83

I accidentally delete a file from my repo using git filter-branch:

git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch images/thumb/a.JPG' HEAD

How can I undo this? Is it possible? i.e. is the file permanently deleted?

Chin
  • 19,717
  • 37
  • 107
  • 164

4 Answers4

157

When you use git filter-branch, a backup file is created in

refs/original/refs/heads/master

If you used the command in branch master. You can check if you have the backup in .git/refs directory. With this in mind, you can use this backup to recover your files with:

git reset --hard refs/original/refs/heads/master
eddiemoya
  • 6,713
  • 1
  • 24
  • 34
William Seiti Mizuta
  • 7,669
  • 3
  • 31
  • 23
  • 9
    I got the error message `fatal: Cannot do hard reset with paths.`, so instead I first did `git reflog` and found the line `HEAD@{integer}: filter-branch: rewrite`, then I noted down the integer and performed `git reset --hard HEAD@{integer}` and I was back. – hermansc May 29 '14 at 06:10
  • This worked for me. I included `git push -f` after `git reset --hard HEAD@{integer}` – kilojoules Jan 05 '15 at 07:52
  • I wanted to use `git filter-branch` to remove a enormous amount of lines, from someone accidentally committing a library to our repo. So in the graph, it shows like 8000 lines of addition/deletion, I thought filter-branch was was gonna rewrite. And the graph would update, but it didn't. It doubled all the lines. Will doing this bring the line count to the old state? or double it again?! – Arian Faurtosh Apr 23 '15 at 16:31
  • Yes, this command will return your code to the state before the 'filter-branch' command. – William Seiti Mizuta Apr 23 '15 at 20:27
  • 4
    Thank you for resetting my heart attack. Worked flawlessly after a filter command removed everything but a folder. – jHilscher Sep 19 '16 at 13:11
  • Thanks a million! I would put two thumbs up if possible. – h3xStream Apr 20 '18 at 18:50
  • You are a true champion – jimh Dec 04 '19 at 23:56
  • How can I remove the backup? (once I am satisfied with filter-branch result) I am deleting the .git/refs/original folder and it works, but I wonder if a more elegant git command exists for the purpose. Thanks – Anton M Mar 24 '21 at 18:57
  • Man! you just saved my job! – Bob May 27 '22 at 12:31
34

Probably a more proper way than just doing hard reset to the original master would be to restore all refs rewritten by git filter-branch, and maybe even delete backup refs afterwards in order to be able to invoke git filter-branch again without --force:

for orig_ref in $(git for-each-ref --format="%(refname)" refs/original/); do
    git update-ref "${orig_ref#refs/original/}" $orig_ref
    git update-ref -d $orig_ref  # to also remove backup refs
done

And after that:

git reset --hard master

UPD.

Here's (arguably) a bit more git'ish way to perform the same without a shell for-loop:

git for-each-ref --format="update %(refname:lstrip=2) %(objectname)" refs/original/ | git update-ref --stdin
git for-each-ref --format="delete %(refname) %(objectname)" refs/original/ | git update-ref --stdin
Eldar Abusalimov
  • 24,387
  • 4
  • 67
  • 71
7

A much cleaner solution is given in this answer by @jthill.

git fetch . +refs/original/*:*

As noted in that answer you may need to detach the HEAD if the currently checked out branch is to be restored.

To delete the refs/original refs, issue:

git for-each-ref refs/original --format='delete %(refname) %(objectname)' | git update-ref --stdin
Mr_and_Mrs_D
  • 32,208
  • 39
  • 178
  • 361
5

It's possible that your old branch tip will be preserved in your reflog. Then you should be able to check out the unchanged commit with all the previous history.

che
  • 12,097
  • 7
  • 42
  • 71
  • git reflog... Hurray.. this command have saved me countless times. :) – Ccr Mar 09 '21 at 05:17
  • Yep this solved it for me and seemed like the simplest solution. Found the reflog entry I wanted to revert to (which happened to be `HEAD@{5}`) and ran `git reset HEAD@{5}`. For more details can checkout this [link](https://www.atlassian.com/git/tutorials/rewriting-history/git-reflog). – jimmy Dec 29 '21 at 23:50