tags:

views:

513

answers:

2

So here's an interesting situation when using git and python, and I'm sure it happens for other situations as well.

Let's say I make a git repo with a folder /foo/. In that folder I put /foo/program.py. I run program.py and program.pyc is created. I have *.pyc in the .gitignore file, so git doesn't track it.

Now let's say I make another branch, dev. In this dev branch, I remove the /foo/ folder entirely.

Now I switch back to the master branch, and /foo/ reappears. I run the program.py and the program.pyc file reappears. All is well.

I switch back to my dev branch. The /foo/ directory should disappear. It only exists in the master branch, not the dev branch. However, it is still there. Why? Because the ignored program.pyc file prevents the folder from being deleted when switching branches.

The solution to this problem is to recursively delete all *.pyc files before switching branches. I can do that easily with this command.

find . -name "*.pyc" -exec rm '{}' ';'

The problem is that it is annoying to have to remember to do this almost every time I change branches. I could make an alias for this command, but then I still have to remember to type it every time I change branches. I could also make an alias for git-branch, but that's no good either. The git branch command does other things besides just change branches, and I don't want to delete all pyc files every time I use it. Heck, I might even use it in a non-python repo, then what?

Is there a way to set a git hook that only executes when I change branches? Or is there some other way to set all *.pyc files to get erased whenever I switch branches?

+5  A: 

There is a post-checkout hook, to be placed in .git/hooks/post-checkout. There's probably a sample there, possibly named .sample or possibly not executable, depending on your git version. Short description: it gets three parameters, the previous HEAD, the new HEAD, and a flag which is 1 if the branch changed and 0 if it was merely a file checkout. See man githooks for more information! You should be able to write a shell script to do what you need and put it there.

Edit: I realize you're looking to do this pre-checkout, so that the checkout automatically cleans up directories which become empty. There's no pre-checkout hook, though, so you'll have to use your script to remove the directories too.

Another note: Aliases are part of gitconfig, which can be local to a repository (in .git/config, not ~/.gitconfig). If you choose to do this with aliases (for git-checkout, not git-branch) you can easily put them only in python-related repositories. Also in this case, I'd make an alias specifically for this purpose (e.g. cc for checkout clean). You can still use checkout (or another aliased form of it) if you don't want to clean up pyc files.

Jefromi
Thanks! Also, there should be a pre-checkout hook.
Apreche
Yeah, the git developers seem to take a fairly conservative approach to adding hooks. It wouldn't be super-difficult to add one in yourself though! If you look at the call to the post-checkout hook (at the bottom of the checkout function), it calls a one-line wrapper function which grabs the hashes old/new hashes and branch vs. file checkout flag, then calls a generic run_hook function.
Jefromi
Here is the post-checkout hook I wrote. It works perfectly.#!/usr/bin/env bashfind /path/to/repo/ -name "*.pyc" -exec rm {} \;find /path/to/repo/ -depth -type d -empty -exec rmdir {} \;
Apreche
+3  A: 

Just copying and updating a good solution by Apreche that was buried in the comments:

Save this shell script to the file /path/to/repo/.git/hooks/post-checkout, and make it executable.

#! /bin/sh

# Start from the repository root.
cd ./$(git rev-parse --show-cdup)

# Delete .pyc files and empty directories.
find . -name "*.pyc" -delete
find . -type d -empty -delete
Christian Oudard
. will only work assuming you are in the top level directory of your git repo when you checkout. If you checkout from deeper within the repo, only the pyc files from there down will be cleaned up.
Apreche
Updated script to always start from the repository root.
Christian Oudard