git - How to not shoot yourself in the foot
Jan 27, 2019 • 462 words • 3 min read

With git it is nearly impossible to lose your work after you commit it.

Even after running some "destructive" commands like git reset --hard or git rebase, there's a very good chance you will be able to get your work back.

However, if you have not commited your changes there is one command that can wipe them all out and is impossible to get them back:

git checkout .

Git uses the checkout command for many things: Creating branches, switching between branches, moving to specific commits and, of course, undoing your changes.

The command above basically means "Undo all the changes I have not committed yet, from this directory and all its subdirectories". Pretty destructive, don't you think? Especially if you're like me and you have aliased checkout to co which puts only 8 characters between you and losing your last hour's worth of work.

The solution

The solution to this is to put this alias to your ~/.gitconfig:

[alias]
    co = "!f(){ if [ \"$1\" = '.' ]; then echo 'Nope'; else git checkout $@; fi; }; f"

This basically tells git that whenever you type git co SOMETHING to run a function. The function checks if its first argument $1 is . in which case it will just print "Nope" otherwise it will pass all its arguments $@ to git checkout as intended.

The catch with running functions in your aliases is that all the functions are executed at the top level of your repository (the place where your .git/ dir is). This means that if you are not there you cannot checkout individual files, unless you specify the full path to them or at least provide their relative-to-the-top-level path.

I also tried using the $GIT_PREFIX variable which contains the path to the root of your repository but then it screws up branch operations ¯\_(ツ)_/¯

If you find a way around this send me a message on Twitter.

Alternative

Now, there are many valid use cases that you may want to revert all your changes, maybe to test something else, or to start clean, and there is a non destructive way to do that, by stashing your changes away with git stash. In case you want to bring the changes back, they are just a git stash pop away.

Bottom line

I had this alias in my ~/.gitconfig for the last few months and it stopped me a couple of times from losing all my changes when in reality I've been meaning to only checkout a single directory. I did not run into the drawback because I almost always work from the top level of the repo so it has not been an issue for me.

Let me know if you found this useful and/or how this could be improved.

/git/ /notes-to-self/ /ugly-hacks/