47

I was attempting to pull a change into my repository using Git Tower. When I did so, there was a conflict and I mistakenly hit stage all (as I wanted to commit after resolving the conflict). When I did so, the conflict marked itself as resolved.

I wanted to manually resolve the change so I hit "Abort Merge", however, when I did this, It rolled back all my changes! Is there any way to get them back?

Makoto
  • 104,088
  • 27
  • 192
  • 230
David
  • 1,648
  • 1
  • 16
  • 31

3 Answers3

82

If you had anything staged to git, you probably should be able to get that back. (If you just changed working copy, you wouldn't be able to restore it.)

First of all: Backup your repository and working copy before going ahead. (Make sure to backup the .git directory.) Also avoid closing the terminal where this happened, and/or rebooting — if all fails, you have a chance to find stuff in history / memory. Do not run git gc.

Next, try:

git fsck --lost-found

It will print something like:

Checking object directories: 100% (256/256), done.
Checking objects: 100% (30165/30165), done.
dangling blob 8f72c7d79f964b8279da93ca8c05bd685e892756
dangling commit 4993502a6394491190d3f4d6fb3d1e14019c2e9b

Since you lost staged files and did not do a commit, you're interested in dangling blob entries.

Run git show <sha> for each one — some of them should be your files.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Alexander Gladysh
  • 39,865
  • 32
  • 103
  • 160
  • 7
    Thanks! I had given up hope that Git had kept any non-committed files. I wanted to add in a tip for those who have a lot of garbage in their lost and found. I for one had 100's of entries, so to find the hash, you can also use a find-in-file type command in your git directory as long as you can remember some portion of the file you had written. I used find . | xargs grep 'PIECE_OF_MISSING_CODE' -sl | grep 'lost-found' – David Jun 19 '12 at 16:45
  • git show shows crap, I mean there are some recognisable strings, but the rest is crap. Is it meant to be decoded somehow, or is it what it is (not usable). – jayarjo May 01 '15 at 14:20
  • I almost lost a lot of important changes after using `git reset --hard` but was saved by Local History feature of GoLand IDE – akskap May 31 '19 at 14:00
  • 1
    Thank you. You saved me 3 weeks of hard work. I was wondering if there is a simple way to recover the files to it original path inside the repository. – Daniel Miranda Aug 15 '19 at 00:26
  • @jayarjo keep searching other files. That means the blob you are looking at is likely compiled code. – young_souvlaki Nov 23 '20 at 17:51
  • How do you retrieve the file once you find it? – young_souvlaki Nov 23 '20 at 17:52
  • @akskap I have now created a shell alias that refuses to run `git reset --hard`, since it is usually a bad idea. It can be replaced by `git reset --keep` most of the time, and if the local changes conflict, then stash them first (and maybe even drop the stash), that way they are always indexed in git. – xeruf Mar 01 '21 at 12:12
  • Saved my life. I had staged my stuff and then switched to a different branch, with all my work just disappearing. – Dev Star Nov 11 '21 at 21:25
38

A very late answer that could simplify (a lot? comparing to other answers) the recover using the command line by letting you figure it out quicker which blobs should be recovered:

git fsck --full --no-reflogs --unreachable --lost-found | grep blob | cut -d\  -f3 | while read in; do printf "blob: $in\n"; git cat-file -p $in; printf "\n--------------------------------\n"; done > recover.txt

This command will create a file containing the hash and content of all the blobs that could be recovered.

That way, you could easily search into this file and recover the blobs you want with the given hash (with the command git cat-file -p 8f72c7d79f964b8279da93ca8c05bd685e892756 > myFile.txt)

Disclaimer: this file could become huge and slow to create if you've got a lot of unreachable blobs.

Note: with this command, you will retrieve contents but there is no possibility to get the corresponding filename (because the tree objects has still not been added to the git object folder. It is only done when committing.)

If you prefer using GUI tools and are on Windows, you could also use GitExtensions that could be helpful to recover files.

Philippe
  • 28,207
  • 6
  • 54
  • 78
  • 3
    This was tremendously helpful when I was recovering 20-something files. – John Dough Jan 16 '20 at 17:59
  • This is really helpful. Is there a way to tell what file a blob is associated with? I can see the content, but I am just trying to recover specific files only, and the content is similar to other files so I can only differentiate with file names. – MasayoMusic Aug 06 '21 at 03:30
  • 1
    @MasayoMusic if the file have just been staged (I. e. not committed), no that's not possible to retrieve the filenames because the tree objects has still not been added to the git object folder. It is done when committing. – Philippe Aug 06 '21 at 05:37
  • 1
    You are God for me right now :) This was awesome! – Pablo Mar 25 '22 at 12:57
  • This honestly saved me. You have no idea how thankful I am to find this bit of gen online. Yes it took a little effort to search in the large file it generated, but that was offset against actually seeing days of work re-appear that I thought I had lost forever. Thank you stranger of the internet! – PilotSnipes Sep 01 '23 at 17:27
  • @PilotSnipes you're welcome! I spent many hours crafting this command line and also improving recovery in GitExtensions even if I never had to use it because I knew it will save tremendous time to maybe a lot of people. Thanks for your kind words. – Philippe Sep 01 '23 at 23:50
15

To expand on Alexander's answer with a simpler alternative: yes, if you've staged your changes then you can probably get your files back. When you run git add, files are actually added to Git's object database. At the moment that you do, git will put the file in the index:

% git add bar.txt
% git ls-files --stage
100644 ce013625030ba8dba906f756967f9e9ca394464a 0   bar.txt
100644 6af0abcdfc7822d5f87315af1bb3367484ee3c0c 0   foo.txt

Note that the entry for bar.txt contains the object ID of the file. Git has actually added the file to its object database. In this case, Git has added it to the repository as a loose object:

% ls -Flas .git/objects/ce/013625030ba8dba906f756967f9e9ca394464a
4 -r--r--r--  1 ethomson  staff  21 14 Jun 23:58 .git/objects/ce/013625030ba8dba906f756967f9e9ca394464a

These files will eventually be garbage collected (so indeed, do not explicitly run git gc). Thankfully, by default, this will happen in a matter of months, not days. Until these files are garbage collected, you can recover them.

The easiest way to do this is to download and install the git-recover program in interactive mode:

% git recover -i
Recoverable orphaned git blobs:

61c2562a7b851b69596f0bcad1d8f54c400be977  (Thu 15 Jun 2017 12:20:22 CEST)
> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
> tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
> veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
> commodo consequat. Duis aute irure dolor in reprehenderit in voluptate

Recover this file? [y,n,v,f,q,?]: 

git-recover looks for files in the object database that are not committed (or in the index). You can find out more about git-recover in the blog post announcing it.

Edward Thomson
  • 74,857
  • 14
  • 158
  • 187
  • 1
    Please add a disclosure that both, tool and blog post, are yours. – jan-glx Nov 16 '19 at 14:53
  • Awesome. Using interactive mode I could help my UX team to recover a file after a git merge --abort. For help others, using -i, select the "f" letter and put the name of your file and .extension – Isac Moura Mar 23 '20 at 14:37