Git: Restore file from history

From time to time you want to take a look at a file in the past of your Git repository’s history. The following instructions will tell you how to see (and save) a file at a certain commit in the Git history.

Finding the right commit

Depending on the use case there are different ways of finding the commit you want to take a look at. In any case, after this step you will have a commit id or a branch-relative index which can be used to refer to the desired commit.

Referring to recent commit

If you know that the file was in the desired state in the previous, last but one, etc. commit, you can use the “~ operator”:

  • previous commit: HEAD~1
  • last but one commit: HEAD~2
  • head of certain branch: branch123
  • commit before head of branch: branch123~1
  • etc.

Listing files under version control

The command git ls-tree shows you the files which were under version control at a certain point in time:

git ls-tree --name-only HEAD~1  # non-recursive
git ls-tree -r --name-only HEAD~1  # recursive

Deleted files

Suppose you have deleted the file and want to know in which particular commit you deleted it, then the following command will be helpful, which prints out all log entries which contain a delete instruction (you may search as normal with the “/” operator):

git log --diff-filter=D --summary

Git bisection search

If you don’t know the exact version (commit) of the file, but given the file in some state, you can decide whether the appropriate version has been created rather before or after a given one. In this case the bisection search of Git may help: You tell Git a range of commits which surely “enclose” the desired version of your file. The most recent commit is called the bad state and the oldest commit is called the good state, because the bisection search is meant for finding a commit which introduced a bug which has not been there at some point in the past. In our setting, we are not looking for a bug but for a particular version of a file.

git bisect startgit bisect bad # uses the HEAD
git bisect good <commit id some time in the past>
# e.g., Bisecting: 113 revisions left to test after this (roughly 7 steps)

The bisection search will place you at the “center” between good and bad (you can also visualize the situation with the command git bisect visualize). And now you can examine the file in question whether you think the change is in the future or the past of this commit. In the former case (“future”), our we need to tell Git that the current state is good (“bug” in the future):

git bisect good

Likewise, in the latter case we find that the “bug” is in the past and tell Git so:

git bisect bad

Iterate, until you are done. Then, or if you would like to abort the bisection, type:

git bisect revert

Restoring the file

Now that you have the commit of your choice, use the git show command to display or store the file.

git show HEAD~3:README.txt # show the file contents
git show HEAD~3:README.txt > /tmp/README.txt # store the file contents

shows README.txt file in the 3rd last commit of the current branch.

git show issue123~1:doc/html/index.html # show
git show issue123~1:doc/html/index.html > /tmp/index.html # store

shows index.html in the subdirectory doc/html in the state it was one commit before the HEAD of the branch issue123.

Leave a Reply