Git Smarter: Retrieve deleted files from history [ git unremove ]Posted: March 25, 2014
In the course of development, there are times you want to look at or retrieve a file deleted sometime in the past – and you probably don’t know when it was deleted. I’ve written a simple git alias that makes it super easy.
|### Git Unremove ##|
|# Adds an alias called "unrm" to retrieve a pile or path deleted at any point in the repositories history.|
|# git unrm [path]|
|# git unrm path/to/file|
|git config –global alias.unrm '!COMMIT=$(git log -1 –pretty=%h — "$1"); git checkout $COMMIT^ — "$1"; echo "File: $1, was restored from commit $COMMIT"; git show -s $COMMIT'|
So how does this work? If you don’t care, then just copy and paste the config line above – if you want to know what’s going on here, read on.
It uses some simple features of the “git log” and “git checkout” commands that everyone is already familiar with. Each can have a file path passed to them after a couple of dashes “–“. First, you need to find out when in the git history the file was removed, for that you can just use “git log” with a “–” and a path.
|# Show specifically only the last commit to affect the path/to/file –|
|# this will be the commit where the file as deleted.|
|git log -1 — path/to/file|
This works just like normal git-log, but narrows the log to show only commits that affect the given path – keep in mind that the path can be a specific file or an entire directory.
What if you want to actually retrieve that file? Well, you can do that with the “git checkout” command by doing basically the same thing. First copy the SHA1 hash of the last commit affecting the file you want to retrieve – this is important because you it will tell git-checkout where to look for the file.
|# Recreate the file at path/to/file in the state in the state it was at|
|# just prior to having been deleted (made up commit hash for example)|
|git checkout 4efa6b0^ — path/to/file|
The commit hash you copied from the “git log” output doesn’t actually contain the file, its just when the file was deleted because that commit is by definition the last commit to affect the file. To get the last state of the file before its removal you need to look to the commit immediately before it, thats what the “^” does, it looks one commit back.
So that a bunch of stuff to remember – although its fairly simple compared to some other more complex tasks in git – but I made the git alias to make it even easier. I think I originally came up with this alias an an answer on StackOverflow, but its been sitting around as a gist on my github account for a while. I’ll probably be sharing more stuff from gist in the future.