Can I recover a branch after its deletion in Git?

2018-12-31 15:47发布

问题:

If I run git branch -d XYZ, is there a way to recover the branch? Is there a way to go back as if I didn\'t run the delete branch command?

回答1:

Yes, you should be able to do git reflog and find the SHA1 for the commit at the tip of your deleted branch, then just git checkout [sha]. And once you\'re at that commit, you can just git checkout -b [branchname] to recreate the branch from there.



回答2:

Most of the time unreachable commits are in the reflog. So, the first thing to try is to look at the reflog using the command git reflog (which display the reflog for HEAD).

Perhaps something easier if the commit was part of a specific branch still existing is to use the command git reflog name-of-my-branch. It works also with a remote, for example if you forced push.


If your commits are not in your reflog (perhaps because deleted by a 3rd party tool that don\'t write in the reflog), I successfully recovered a branch by reseting my branch to the sha of the commit found using a command like that (it creates a file with all the dangling commits):

git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

If you should use it more than one time (or want to save it somewhere), you could also create an alias with that command...

git config --global alias.rescue \'!git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\\  -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt\'

and use it with git rescue

To investigate found commits, you could display each commit using some commands to look into them.

To display the commit metadata (author, creation date and commit message):

git cat-file -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

To see also the diffs:

git log -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

Once you found your commit, then create a branch on this commit with:

git branch commit_rescued 48540dfa438ad8e442b18e57a5a255c0ecad0560


回答3:

If you like to use a GUI, you can perform the entire operation with gitk.

gitk --reflog

This will allow you to see the branch\'s commit history as if the branch hadn\'t been deleted. Now simply right click on the most recent commit to the branch and select the menu option Create new branch.



回答4:

The top voted solution does actually more than requested:

git checkout <sha>
git checkout -b <branch>

or

git checkout -b <branch> <sha>

move you to the new branch together with all recent changes you might have forgot to commit. This may not be your intention, especially when in the \"panic mode\" after losing the branch.

A cleaner (and simpler) solution seems to be the one-liner (after you found the <sha> with git reflog):

git branch <branch> <sha>

Now neither your current branch nor uncommited changes are affected. Instead only a new branch will be created all the way up to the <sha>.

If it is not the tip, it\'ll still work and you get a shorter branch, then you can retry with new <sha> and new branch name until you get it right.

Finally you can rename the successfully restored branch into what it was named or anything else:

git branch -m <restored branch> <final branch>

Needless to say, the key to success was to find the right commit <sha>, so name your commits wisely :)



回答5:

Adding to tfe answer: there is also the git-resurrect.sh script in the contrib/ area of the Git sources (in git.git repository), which might help you.

git-resurrect <name> attempts to find traces of a branch tip called <name>, and tries to resurrect it. Currently, the reflog is searched for checkout messages, and with -r also merge messages. With -m and -t, the history of all refs is scanned for Merge <name> into other/Merge <other> into <name> (respectively) commit subjects, which is rather slow but allows you to resurrect other people\'s topic branches.



回答6:

If you don\'t have a reflog, eg. because you\'re working in a bare repository which does not have the reflog enabled and the commit you want to recover was created recently, another option is to find recently created commit objects and look through them.

From inside the .git/objects directory run:

find . -ctime -12h -type f | sed \'s/[./]//g\' | git cat-file --batch-check | grep commit

This finds all objects (commits, files, tags etc.) created in the last 12 hours and filters them to show only commits. Checking these is then a quick process.

I\'d try the git-ressurect.sh script mentioned in Jakub\'s answer first though.



回答7:

I used the following commands to find and retrieve my deleted branch. The first steps are from gcb\'s description.

$ git fsck --full --no-reflogs --unreachable --lost-found > lost
$ cat lost | cut -d\\  -f3 > commits
$ cat commits | xargs -n 1 git log -n 1 --pretty=oneline

Now look for the git commit id (GIT-SHA) based on the commit comments and use it in the command below. Checkout a new branch called NEW-BRANCH with the previously found GIT-SHA:

$ git checkout -b NEW-BRANCH GIT-SHA


回答8:

For GitHub users without Git installed:

If you want to restore it from GitHub website, you can Hack their website ;)

   •  First of all, find those SHAs (commit hashes):

curl -i https://api.github.com/repos/PublicUser/PublicRepo/events

... or for private repos:

curl -su YourUserName https://api.github.com/repos/YourUserName/YourProject/events

... (password will be prompted)

   •  Next, go to GitHub and create a new temporary branch which will be deleted for ever (Chrome is preferable).

   •  Go to branches and delete that one.

   •  On the same page, without reloading, open DevTools, Network panel. Now prepare...

   •  Click restore. You will notice a new \"line\". Right-click on it and select \"Copy as cURL\" and save this text in some editor.

   •  Append to the end of the copied line of code, this one: -H \"Cookie=\".

You should get now something like that:

curl \'https://github.com/UserName/ProjectName/branches?branch=BranchSHA&name=BranchName\' -H \'Cookie:\' -H \'Origin: https://github.com\' -H \'Accept-Encoding: gzip, deflate, br\' -H \'Accept-Language: en-US\' -H \'User-Agent: User-Agent\' -H \'Content-Type: application/x-www-form-urlencoded; charset=UTF-8\' -H \'Accept: */*\' -H \'Referer: https://github.com/UserName/ProjectName/branches\' -H \'X-Requested-With: XMLHttpRequest\' -H \'Connection: keep-alive\' --data \'utf8=%E2%9C%93&authenticity_token=token\' --compressed

   •  Final step: replace \"BranchSHA\" with your SHA-hash and BranchName with desired name (BTW, it is great hack to rename branch from web). If you were not too slow, you need to make this request anyhow. For example, just copy-paste to a terminal.

P.S.

I know, it\'s not very simple solution or right solution, but just in case someone, without root password and virtual machine, during hackathon will need to do something weird like that?.. It is totally real, so thank you for taking your time and good luck :)

UPDATE

Ahaha, I am so excited about the fact that someone in the World Wide Web found my answer and actually after reading it, found it funny or useful and upvoted my mind-blowing, insane and so wrong-practice answer :) It\'s a wonderful world around and we, programmers and coders, are one of the craziest part of it <3



回答9:

From my understanding if the branch to be deleted can be reached by another branch, you can delete it safely using

git branch -d [branch]

and your work is not lost. Remember that a branch is not a snapshot, but a pointer to one. So when you delete a branch you delete a pointer.

You won\'t even lose work if you delete a branch which cannot be reached by another one. Of course it won\'t be as easy as checking out the commit hash, but you can still do it. That\'s why Git is unable to delete a branch which cannot be reached by using -d. Instead you have to use

git branch -D [branch]

This is part of a must watch video from Scott Chacon about Git. Check minute 58:00 when he talks about branches and how delete them.

Introduction to Git with Scott Chacon of GitHub



回答10:

I rebased a branch from remote to try to clear a few commits I didn\'t want and was going to cherrypick the right ones that I wanted. Of course I wrote the SHAs wrong...

Here is how I found them (mostly an easier interface/interaction from things on answers here):

First, generate a list of loose commits in your log. Do this as soon as possible and stop working, as those may be dumped by the garbage collector.

git fsck --full --no-reflogs --unreachable --lost-found > lost

This creates a lost file with all the commits you will have to look at. To simplify our life, let\'s cut only the SHA from it:

cat lost | cut -d\\  -f3 > commits

Now you have a commits file with all the commits you have to look.

Assuming you are using Bash, the final step:

for c in `cat commits`; do  git show $c; read; done

This will show you the diff and commit information for each of them. And wait for you to press Enter. Now write down all the ones you want, and then cherry-pick them in. After you are done, just Ctrl-C it.



回答11:

For recovering a deleted branch, First go through the reflog history,

git reflog -n 60

Where n refers to the last n commits. Then find the proper head and create a branch with that head.

git branch testbranch HEAD@{30}


回答12:

First go to git batch the move to your project like :

cd android studio project
cd Myproject
then type :
git reflog

You all have a list of the changes and the reference number take the ref number then checkout
from android studio or from the git betcha. another solution take the ref number and go to android studio click on git branches down then click on checkout tag or revision past the reference number then lol you have the branches.



回答13:

Adding to tfe\'s answer, you can recover with this process mentioned, unless it\'s commits are not garbage collected. Git branch is simply a pointer to a particular commit in the commit tree. But if you delete the pointer, and the commits on that branch are not merged into other existing branch, then git treats it as dangling commits and removes them during garbage collection, which it may run automatically periodically.

If your branch wasn\'t merged to an existing branch, and if it was garbage collected, then you will loose all commits up until the point from where branch was forked from an existing branch.



回答14:

A related issue: I came to this page after searching for \"how to know what are deleted branches\".

While deleting many old branches, felt I mistakenly deleted one of the newer branches, but didn\'t know the name to recover it.

To know what branches are deleted recently, do the below:

If you go to your Git URL, which will look something like this:

https://your-website-name/orgs/your-org-name/dashboard

Then you can see the feed, of what is deleted, by whom, in the recent past.



回答15:

Make sure to perform all of this locally, and confirm your repo is in the state you desire before pushing to Bitbucket Cloud. It may also be a good idea to clone your current repo, and test these solutions out first.

  1. If you just deleted the branch, you\'ll see something like this in your terminal:

    Deleted branch (was )

    2.To restore the branch, use:

    git checkout -b

If you don\'t know the \'sha\' off the top of your head, you can:

  1. Find the \'sha\' for the commit at the tip of your deleted branch using:

    git reflog

  2. To restore the branch, use:

    git checkout -b

If your commits are not in your reflog:

  1. You can try recovering a branch by reseting your branch to the sha of the commit found using a command like:

    git fsck --full --no-reflogs --unreachable --lost-found | grep commit | cut -d\\ -f3 | xargs -n 1 git log -n 1 --pretty=oneline > .git/lost-found.txt

    2.You can then display each commit using one of these:

    git log -p git cat-file -p



回答16:

Just using git reflog did not return the sha for me. Only the commit id (which is 8 chars long and a sha is way longer)

So I used git reflog --no-abbrev

And then do the same as mentioned above: git checkout -b <branch> <sha>



回答17:

BIG YES

if you are using GIT follow these simple steps https://confluence.atlassian.com/bbkb/how-to-restore-a-deleted-branch-765757540.html

if you are using smartgit and already push that branch go to origin, find that branch and right click then checkout