298

I have an old commit that I did a few weeks ago. I want to restore only a single file from that commit. What do I do?

1

4 Answers 4

335
git checkout 'master@{7 days ago}' -- path/to/file.txt

This will not alter HEAD, it will just overwrite the local file path/to/file.txt

See man git-rev-parse for possible revision specifications there (of course a simple hash (like dd9bacb) will do nicely)

Don't forget to commit the change (after a review...)

5
  • 22
    Wow, @heneryville and sehe , I actually thought '7 days ago' was meta for you would figure out what commit. ty! Commented Apr 1, 2014 at 19:49
  • 7
    Part 2 When desiring to choose a particular commit, the above format does not work. Instead use what Urs showed below, git checkout commitShaNumber -- path/to/file.txt per stackoverflow.com/questions/215718/… Commented Apr 1, 2014 at 20:16
  • 2
    @AnneTheAgile in fact that's still exactly the same syntax, I just happened to give a "complex" example of a revision-specification since that is what the OP asked :)
    – sehe
    Commented Apr 1, 2014 at 20:56
  • 3
    If your commit was used to delete the file you are trying to recover, just use shacommit~1 (ex: git checkout 0f4bbdcd~1 -- path/to/file.txt) to get the commit immediately before.
    – sdlins
    Commented Jan 3, 2020 at 4:40
  • I honestly thought the "7 days ago" bit was meant to be the commit hashcode. Commented Aug 21, 2020 at 0:04
121
  1. Check out the file from your old commit via git checkout [Revision_Key] -- path/to/file.
  2. Add, commit, push as appropriate.
6
  • 3
    git checkout can handle single files (see answer by sehe), no need to copy and paste.
    – Koraktor
    Commented Jul 8, 2011 at 12:10
  • 1
    Are revision keys always the SHA1 for the commit?
    – IslandCow
    Commented Sep 29, 2011 at 23:11
  • 1
    They are, but usually the first 6 to 8 characters of the SHA1 are sufficient to identify the revision.
    – Urs Reupke
    Commented Oct 1, 2011 at 15:37
  • 5
    @IslandCow no, they can be sha1 but also branch, tag, or any other thing that points to a commit, e.g. HEAD, ORIG_HEAD, or any of those combined with ^/~/@-style notation. Commented May 28, 2014 at 16:20
  • 3
    You indicate that one is supposed to "add" the file afterwards. But that is incorrect. The file is not placed in the staging area. It's already added.
    – xApple
    Commented Jul 26, 2016 at 12:39
79

All answers mention git checkout <tree-ish> -- <pathspec>. As of git v2.23.0 there's a new git restore method which is supposed to assume part of what git checkout was responsible for. See highlights of changes on github blog.

The default behaviour of this command is to restore the state of a working tree with the content coming from the source parameter (which in your case will be a commit hash).

Assuming the commit hash is abcdef the command would look like this:

git restore --source=abcdef file_name

which (by default) puts it in working tree. If you want to put the change directly in index so it can be committed straight away:

git restore --source=abcdef --worktree --staged file_name

or with short option names:

git restore -sabcdef -W -S file_name
1
  • 7
    This should definitely now become the accepted answer, as it makes the others pretty much obsolete.
    – Akito
    Commented Aug 11, 2021 at 10:05
21

I needed to restore a recent file committed into git. So just to reiterate and give another perspective, you need to do this by running the following two steps:

  1. git log -3
    This shows the three most recent commits. Read the comments and the author's name so you narrow down what exact version you want. Write down that long commit ID (e.g. b6b94f2c19c456336d60b9409fb1e373036d3d71) for the commit version you want.

  2. git checkout b6b94f2c19c456336d60b9409fb1e373036d3d71 -- myfile.java
    Pass the commit ID AND the file name you want to restore. Make sure you have a space before and after the double hyphen.

There are many other ways to do it but this is the simplest one I can remember.

NOTE: If you are inside your project path/folder then is not necessary to type the full file's path in the checkout command.

3
  • Best comment ever. Because the one, which is the accepted answer, assumes that the file that has to be fetched is pushed upstream, however this command fetches/restores the file which only exists locally.
    – alperc
    Commented Aug 21, 2018 at 13:21
  • 1
    Just tried this in the root folder of my local git repo. I still needed to provide the relative path to the file. Just providing the -- [filename] on it's own didn't work. Commented Dec 4, 2018 at 2:09
  • @ot0 No, it doesn’t assume that. They are exactly the same answer.
    – matt
    Commented May 30, 2020 at 16:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.