121

I would like to restore a whole directory (recursively) from the history of my git repository.

There is only 1 branch (master).

I know the commit where errors were included.

Can I use the sha1 hash of the parent commit to restore the state of the directory as it was before the errors were included?

I thought about something like this:

git checkout 348ce0aa02d3738e55ac9085080028b548e3d8d3 path/to/the/folder/

but it did not work.

CharlesB
  • 86,532
  • 28
  • 194
  • 218
mostwanted
  • 1,549
  • 3
  • 13
  • 21
  • 10
    try adding '--' between revisions and paths: `git checkout 348ce0aa02d3738e55ac9085080028b548e3d8d3 -- path/to/the/folder/` – Carlos Campderrós Mar 12 '12 at 16:20
  • 1
    @CarlosCampderrós Write that as a real answer and collect your 15 points before someone else does it ;) – rtn Mar 12 '12 at 16:36
  • @MagnusSkog I wasn't sure that would work, so I made a comment just to check. Now that I'm sure it works, I've written it down as answer :) – Carlos Campderrós Mar 12 '12 at 16:42
  • 2
    As a general hint, "it did not work" isn't very useful. Tell us *why* it didn't work, ideally with the error output (trimmed if it's very long). – me_and Mar 12 '12 at 16:57
  • @me_and you are right - thanks for your feedback. next time i will add some more information! – mostwanted Mar 12 '12 at 17:04

6 Answers6

207

try adding '--' between revisions and paths:

git checkout 348ce0aa02d3738e55ac9085080028b548e3d8d3 -- path/to/the/folder/ 

And if you want to recover a directory from the previous commit, you can replace the commit hash by HEAD~1, for example:

git checkout HEAD~1 -- path/to/the/folder/ 
Alain Tiemblo
  • 36,099
  • 17
  • 121
  • 153
Carlos Campderrós
  • 22,354
  • 11
  • 51
  • 57
  • same command, almost different purpose: http://stackoverflow.com/questions/953481/restore-a-deleted-file-in-a-git-repo – cregox Sep 06 '12 at 16:33
  • Seems to work with folders as well as with single files. Thanks. – Valentin Despa Apr 29 '14 at 06:52
  • 23
    There is one issue though: the OP doesn't specify if the directory still exists. To restore an existing directory to the state of a commit, the content of the directory should be deleted first. In other case, existing files that didn't exist in the old commit won't be removed. – Alberto Jul 21 '14 at 13:18
  • 8
    +1 @Alberto agree definitely. I did a `rm -Rf path/to/the/folder` then `git checkout 348ce0aa02d3738e55ac9085080028b548e3d8d3 -- path/to/the/folder/` - Result: that path had exactly the same files as in that commit, no differences and no extra files that had been created after this commit. Which is what I want. – therobyouknow May 28 '15 at 12:19
  • Adding the Caret at the end of the commit worked for me git checkout ^ -- – Rady Jul 10 '16 at 19:58
  • If you just made a change and did not stage the files yet simply replace the SHA1 (348c...) by HEAD : `git checkout HEAD -- path/to/the/folder/` – Yahel Mar 21 '17 at 10:59
  • 2
    what does the `--` do? – Ray Foss Mar 07 '18 at 19:18
  • 2
    @RayFoss it tells git that the following parameters are files (else they could be confused with a commit hash, branch or something else). Usually they are not needed but it doesn't hurt to put them – Carlos Campderrós Mar 09 '18 at 09:51
  • how can I bring back `directory recursively` from **commit id** `d4a9a47` A `directory` which was deleted as the project progressed There were a few other changes in other files that I like to avoid – Azhar Uddin Sheikh Jul 13 '22 at 14:42
8

For modern git (-s or --source):

git restore -s commit-sha-that-contains-dir relative/path/to/folder

man reference:

-s <tree>, --source=<tree>
   Restore the working tree files with the content from the given tree. It is common to specify
   the source tree by naming a commit, branch or tag associated with it.

   If not specified, the contents are restored from HEAD if --staged is given, otherwise from the index.

   As a special case, you may use "A...B" as a shortcut for the merge base of A and B if there
   is exactly one merge base. You can leave out at most one of A and B, in which case it
   defaults to HEAD.
uptoyou
  • 1,427
  • 19
  • 24
4

There are two easy ways to do this:

If the commit that included the errors only included the errors, use git revert to invert the effects of it.

If not, the easy path is this:

  1. git checkout 348…
  2. cp -a path/to/the/folder ../tmp-restore-folder
  3. git checkout HEAD # or whatever
  4. rm -rf path/to/the/folder
  5. mv ../tmp-restore-folder path/to/the/folder
  6. git add path/to/the/folder
  7. git commit -m "revert …"
Daniel Pittman
  • 16,733
  • 4
  • 41
  • 34
2
git checkout -- path/to/folder/
amalik2205
  • 3,962
  • 1
  • 15
  • 21
2

You can do git checkout master -- path/to/the/folder-you-want-to-restore/ to restore a directory or file on your local branch from the master branch.

Rafay
  • 6,108
  • 11
  • 51
  • 71
1

If you simply do git checkout <SHA-ID> then it will temporarily move you to that sha-commit.

Each commit object holds the entire structure of the disk at that time, so if you have files there and need to copy them out, you can do so. Warning though, you will not be in any branch, so you'll have to move back to master before copying the file into your working tree and commit it.

Mark Fisher
  • 9,838
  • 3
  • 32
  • 38