1

I have a project on git. My project has files like:

file1.js
file2.html
file3.js
file4.css
file5.html
file6.jpg
file7.html
file8.js
file9.css

I did a git -rm filename for all the files and committed them, until I was left with

file1.js
file2.html

I need to get back my file6.jpg

How do I get file6.jpg so my repo will have

file1.js
file2.html
file6.jpg
Mike
  • 3,348
  • 11
  • 45
  • 80

4 Answers4

2
git checkout HEAD~N -- file6.jpg

Where N is the number of commits back in time where file6.jpg was present.

Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
1

git checkout might be the simplest option for a single file.

  1. Use git log to view your commit history. Find the hash of the commit before you removed the file in question. For example:

    commit 5faff7e3f74c3408985acecd1dbb90feeb7b1d75 <--- "hash"
    Author: Nick Tomlin <myemail@email.com>
    Date:   Fri Apr 5 11:34:03 2013 -0500
    
  2. then run git checkout <hash> path/to/file6.jpg replacing <hash> with the string of characters above (you usually only need the last 5 or so, but let's just use them all now to be safe. If you are in the directory that file6.jpg resides, you can just do git checkout <hash> file6.jpg

This is a more longform approach to accessing a commit, one could just use HEAD~6, but I generally prefer it when referencing commits that are farther back than HEAD~3 . It's a easier to reference the wrong commit using the relative ~ reference, and I end up looking through my log to figure out exactly which commit I need anyway : ).

Nick Tomlin
  • 28,402
  • 11
  • 61
  • 90
  • how do I find hash. sorry I am new to git. – Mike Apr 05 '13 at 19:23
  • Thanks this worked, however Gabriele approach also worked. Do you know what is the difference between the two approaches? If I would have deleted and committed all the files in one short. what is the way to get back the desired file. – Mike Apr 06 '13 at 05:40
  • @Mike they perform the same action; Gabrielle's is just a different way of referencing the commit. I updated my answer to explain this more. You could use the same ``checkout`` method if all the files had been deleted in a single commit. You would just need to reference the commit previous to the one that you deleted the files. For more than one file, it's probably best o use something like ``git revert`` [link](https://www.kernel.org/pub/software/scm/git/docs/git-revert.html) but that is not quite as simple; simple is good : ) – Nick Tomlin Apr 06 '13 at 15:50
0
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.

Community
  • 1
  • 1
eddiemoya
  • 6,713
  • 1
  • 24
  • 34
-1

Assuming file6.jpg was previously committed you can get all of the revisions of file6.jpg in your git repository by:

git rev-list --objects --all | grep file6.jpg

Then you can restore the file using

git cat-file {sha} > file6.jpg

Add the file and commit.

See also this answer talking about how to get all objects from a git repository: https://stackoverflow.com/a/7350019

and this site about git object internals: http://git-scm.com/book/en/Git-Internals-Git-Objects

Community
  • 1
  • 1
Charlie
  • 7,181
  • 1
  • 35
  • 49