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.