git checkout $(git log -1 --pretty='%h' -- <path>)^ -- <path>
Breakdown
Using git log
to find the last commit effecting the desired file
$(git log -1 --pretty='%h' -- <path>)
- Runs the
git log
command using a --pretty
formatting that just shows the hash.
- Uses the
--
separator to explicitly specify a file rather than a commit reference.
- Followed by the path and filename of the file we want to retrieve.
- Wrapped all this in
$()
so we can embed it into another git command like a variable.
- This will return the commit in which the given file was removed.
This could of course be used on its own without the $()
if you just wanted to know when that file was removed - changing or removed the pretty formatting will give you more info on the commit it finds.
Using git checkout
to retrieve a fil as it was in a given commit
git checkout <ref>^ -- <path>
- Runs
git checkout
using a commit and specifying a path.
- When a path is specified git simply recreates the state of that path at the provided reference.
- By adding a carrot
^
to the reference, we actually point to the immediate ancestor.
- We want the immediate ancestor, because the commit we get from the log will not have the file - since its the commit in which the file was deleted.
Put it all together, and you are checking out the file in the state it was at in the commit just before that file was removed. If you run this on a file that has not been removed, it will just undo whatever the change that was most recently done to that file.
Alias
git config --global alias.unrm '!COMMIT=$(git log -1 --pretty='%h' -- "$1"); git checkout $COMMIT^ -- "$1"'
I created an alias out of this called unrm
, as in un-remove. If you run the above command, from then on you'll just need to run..
git unrm <path>
Edit: I added some feedback to the command.
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'
Now it informs you of what it has done, and shows you the commit from which it has restored the file.