在Git中删除分支后可以恢复分支吗?


1065

如果我运行git branch -d XYZ,有没有办法恢复分支?有没有办法像我没有运行delete branch命令一样返回?


4
关于已接受答案的一个非常令人敬畏的注释是,即使该分支在原始位置被删除,它仍然有效!我只是恢复了几个分支,这些分支原本被不小心删除了,但这些分支在本地已经不存在了。
theblang

Answers:


1954

是的,您应该能够git reflog在已删除分支的顶端找到提交的SHA1,然后只需git checkout [sha]。一旦完成该提交,就可以git checkout -b [branchname]从那里重新创建分支。


感谢此压缩/单线版本的@Cascabel。

您可以一步完成:

git checkout -b <branch> <sha>

476
您可以一步一步完成:git checkout -b <branch> <sha>
卡斯卡贝尔

200
快速提示-如果您刚刚删除了分支,您将在终端中看到类似的内容-“已删除分支<your-branch>(was <sha>)”。然后,这非常容易-只需使用它即可<sha>。如上所述,例如git checkout -b <branch> <sha>
Snowcrash 2014年

6
是的,只是在您的终端中向上滚动(除非您这样做了CMD+K
neaumusic

42
使用git reflog --no-abbrev看全<sha>是被默认的缩写。
jkulak 2015年

5
对于像我这样的其他人,他们很难找到已删除分支的阴影:我能够git checkout remotes/origin/deleted_branch
杰夫·欧文

161

大多数情况下,无法到达的提交都在reflog中。因此,首先要尝试的是使用命令git reflog(显示的reflog HEAD)查看reflog 。

如果提交是仍存在的特定分支的一部分,则可能更容易使用命令git reflog name-of-my-branch。它也可用于远程操作,例如,如果您强行按下(其他建议:始终宁可选择git push --force-with-lease更好地防止错误,更可恢复)。


如果您的提交不在您的reflog中(也许是因为被未写入reflog的第3方工具删除了),我成功地恢复了一个分支,方法是使用这样的命令将其分支重置为找到的提交的sha(创建一个带有所有悬空提交的文件):

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

如果您应该多次使用它(或想将其保存在某处),也可以使用该命令创建一个别名...

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'

并与 git rescue

要调查找到的提交,可以使用一些命令显示每个提交以对其进行调查。

要显示提交元数据(作者,创建日期和提交消息):

git cat-file -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

还要查看差异:

git log -p 48540dfa438ad8e442b18e57a5a255c0ecad0560

找到提交后,请使用以下命令在此提交上创建一个分支:

git branch commit_rescued 48540dfa438ad8e442b18e57a5a255c0ecad0560

对于Windows下喜欢GUI的用户,您可以使用功能=> => 通过GitExtensions轻松恢复提交(以及未提交的暂存文件)。RepositoryGit maintenanceRecover lost objects...


可以轻松恢复已删除的暂存文件的类似命令:https : //stackoverflow.com/a/58853981/717372


2
巨大的帮助。我有一个丢失的提交,该丢失从未在我的本地回购中出现。您在那里的第一个命令帮助我在服务器上找到了它。+1
Sean Adkinson

1
那个git抢救别名真是天赐!!!非常感谢您的贡献!
72A12F4E

2
你救了我的命。
杰德·林奇

Patrick Koorevaar的回答对我有所帮助,因为我不知道我最后删除的分支提交<sha>。
Monir Khan

@ Monir-Khan和?我应该得出什么结论?帕特里克(Patrick)的回答只是我命令的复制/粘贴(有一个错误:他忘记对提交进行过滤)...
菲利普

45

如果您想使用GUI,则可以使用gitk执行整个操作。

gitk --reflog

这将使您可以查看分支的提交历史记录,就好像未删除该分支一样。现在,只需右键单击对分支的最新提交,然后选择菜单选项Create new branch


28

票数最高的解决方案实际上超出了要求:

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

要么

git checkout -b <branch> <sha>

将您连同可能忘记提交的所有最近更改一起移到新分支。这可能不是您的意图,尤其是在失去分支后处于“紧急模式”时。

一种更简洁(更简单)的解决方案似乎是一线(在找到<sha>with之后git reflog):

git branch <branch> <sha>

现在,您当前的分支和未提交的更改都不会受到影响。取而代之的是,直到之前,都只会创建一个新分支<sha>

如果不是小费,它仍然可以使用,并且您的分支会更短,然后可以使用新的<sha>和新的分支名称重试,直到正确为止。

最后,您可以将成功还原的分支重命名为该分支的名称或其他名称:

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

不用说,成功的关键是找到正确的提交<sha>,因此,明智地命名您的提交:)


14

添加到tfe答案:Git源区域(在git.git存储库中)还存在git-resurrect.sh脚本contrib/,这可能会对您有所帮助。

git-resurrect <name>尝试找到称为的分支尖端的痕迹<name>,然后尝试将其复活。当前,在reflog中搜索结帐消息以及-r合并消息。使用 -m-t,将扫描所有裁判的历史记录以查找Merge <name> into other/ Merge <other> into <name>(分别)提交主题,这虽然很慢,但可以让您复活其他人的主题分支。


1
尽管我必须将/ usr / lib / git-core /添加到PATH,但它现在对我有用。但这并没有实现我希望的奇迹:(
AmanicA 2015年

10

我使用以下命令来查找和检索删除的分支。第一步来自gcb的描述。

$ 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

现在,基于提交注释查找git commit id(GIT-SHA),并在下面的命令中使用它。使用先前找到的GIT-SHA签出一个名为NEW-BRANCH的新分支:

$ git checkout -b NEW-BRANCH GIT-SHA

非常感谢你。花了一些时间搜索名称,但是值得。如果有一种方法也可以搜索提交消息字符串,那就更好了。
Monir Khan

9

如果您没有reflog,例如 因为您正在一个未启用reflog的裸存储库中工作,并且您要恢复的提交是最近创建的,所以另一个选择是查找最近创建的提交对象并对其进行浏览。

.git/objects目录内部运行:

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

这将查找最近12个小时内创建的所有对象(提交,文件,标签等),并将其过滤以仅显示提交。然后检查这些是一个快速的过程。

我会先尝试Jakub的答案中提到的git-ressurect.sh脚本。


1
不错的选择!您的命令虽然会引发错误。问题出在“ 12h”部分(实际上是“ h”)。一旦删除了“ h”,它就可以正常工作。来自man find:“-ctime n-文件状态是n * 24小时前最后一次更改。” 因此,我们还应该将12更改为0.5,以具有最近12小时的预期行为。
pagliuca

1
我在这里使用OS X 10.8,因此上面的'find'标志基于它附带的版本。
罗伯特·奈特

1
是的,确定问题出在版本上!这就是为什么我首先赞成您的答案!我只是评论过,所以人们意识到参数可能有所不同。
pagliuca

9

对于未安装Git的GitHub用户:

如果要从GitHub网站还原它,则可以使用其API获取与回购相关的事件的列表:

第一

  • 找到那些SHA(提交哈希):

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

    ...或私人回购协议:

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

    (将提示您输入GitHub密码)

    • (如果报告要求二元身份验证,请参阅下面有关此答案的评论。)

下一个

  • 转到GitHub并创建一个新的临时分支,该分支将永远删除(最好使用Chrome)。

   •转到分支并删除该分支。

   •   在同一页面上,无需重新加载,打开DevTools,“网络”面板。现在准备...

   •单击还原。您会注意到一个新的“行”。右键单击它,然后选择“复制为cURL”,然后将此文本保存在某些编辑器中。

   •追加到复制的代码行的末尾,该行是:-H "Cookie="

您现在应该得到类似以下内容:

    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

最后一步

  • 用您的SHA哈希和需要的名称的BranchName替换“ BranchSHA”(顺便说一句,从Web重命名分支是一个很好的技巧)。如果您不太慢,则无论如何都需要发出此请求。例如,只需将其复制粘贴到终端即可。

聚苯乙烯

我意识到这可能不是“最简单的解决方案”或“正确的”解决方案,但是如果有人发现它有用的话,就会提供它。


1
上面是少数不需要依靠的之一git reflog,因此例如在删除远程分支并失去对计算机的访问时很有用,因为这样做并不能获得任何有用的寒意reflog。请注意,在Github上使用OAuth或两因素身份验证时,curl命令的格式如下:curl -u username:token https://api.github.com/usercurl -H "Authorization: token TOKEN" https://api.github.com/repos/USER_OR_ORG_NAME/REPO_NAME/events
TT--

@ TT--哇,我很高兴它有所帮助!并感谢您对身份验证令牌的贡献:)
Maxim Mazurok '19

8

据我了解,如果要删除的分支可以被另一个分支访问,则可以使用以下命令安全地删除它

git branch -d [branch]

并且您的工作不会丢失。请记住,分支不是快照,而是指向它的指针。因此,当删除分支时,将删除指针。

如果删除另一个分支无法访问的分支,您甚至都不会丢失工作。当然,它不像检出提交哈希那样简单,但是您仍然可以做到。这就是Git无法删除使用无法到达的分支的原因-d。相反,您必须使用

git branch -D [branch]

这是Scott Chacon关于Git的必看视频的一部分。检查58:00分钟,当他谈论分支以及如何删除它们时。

GitHub的Scott Chacon介绍Git


7
这如何帮助回答问题?
Dmitri Zaitsev

6
告诉质问者分支不保存内容,但实际上是指针。您不必担心删除分支..您可以创建指向与已删除分支相同的提交的新分支。我仍然记得我问这个问题的时候。美好的时光回到2012年!
fabiopagoti 2015年

1
只好滚动三个屏幕到AT LAST,找到解决这个问题的答案:删除分支就是删除一个纯指针。这里没有数据丢失的情况,唯一要恢复的是它指向的位置。直接去的答案reflog太过分了。
RomainValeri

5

确保在本地执行所有这些操作,并在推送到Bitbucket Cloud之前确认您的存储库处于所需状态。克隆当前的回购并首先测试这些解决方案也是一个好主意。

  1. 如果您只是删除了分支,那么您将在终端中看到以下内容:
    Deleted branch <your-branch> (was <sha>)

2.要还原分支,请使用:

    git checkout -b <branch> <sha>

如果您不知道头部上方的“阴影”,可以:

  1. 使用以下命令在已删除分支的顶端找到提交的“ sha”:
    git reflog
  1. 要还原分支,请使用:
    git checkout -b <branch> <sha>

如果您的提交不在您的引用日志中:

  1. 您可以尝试通过以下命令将分支重置为找到的提交的阴影来恢复分支:
    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.然后,您可以使用以下任一显示每次提交:

    git log -p <commit>
    git cat-file -p <commit>

4

要恢复已删除的分支,请首先浏览reflog历史记录,

git reflog -n 60

其中n表示最后n次提交。然后找到合适的头并使用该头创建一个分支。

git branch testbranch HEAD@{30}

4

我从远程重新建立了一个分支,以尝试清除一些我不想要的提交,并将挑选我想要的正确提交。当然我写的SHA错了...

这是我如何找到它们的方式(大多是通过此处答案中的内容更轻松的界面/交互):

首先,在日志中生成一个松散提交列表。尽快执行此操作并停止工作,因为这些可能会被垃圾收集器丢弃。

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

这将创建一个lost包含所有您必须查看的提交的文件。为了简化我们的生活,让我们仅从中删除SHA:

cat lost | cut -d\  -f3 > commits

现在,您有了一个commits包含所有必须查看的提交的文件。

假设您正在使用Bash,最后一步是:

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

这将为您显示每个差异和提交信息。等你按Enter。现在,写下所有想要的内容,然后将它们挑选出来。完成后,只需Ctrl-C即可。



1

首先转到git batch移动到您的项目,如:

cd android studio project
cd Myproject
then type :
git reflog

大家都有更改列表,参考编号带有参考编号,然后
从android studio或git betcha 签出。另一个解决方案采用参考编号,然后转到android studio,向下单击git分支,然后单击超出参考编号的checkout标签或修订,然后大声笑您具有分支。


1

添加到tfe的答案中,您可以使用上述过程进行恢复,除非未对提交进行垃圾收集。Git分支只是指向提交树中特定提交的指针。但是,如果删除指针,并且该分支上的提交未合并到其他现有分支中,则git将其视为悬空提交,并在垃圾回收期间将其删除,该垃圾回收可能会定期自动运行。

如果您的分支未合并到现有分支,并且已被垃圾回收,则您将松散所有提交,直到分支从现有分支派生到分支为止。


1

一个相关的问题:我在搜索“如何知道删除的分支是什么”之后来到了此页面。

在删除许多旧分支时,我觉得我误删除了一个较新的分支,但是不知道要恢复的名称。

要了解最近删除了哪些分支,请执行以下操作:

如果您转到自己的Git URL,它将类似于以下内容:

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

然后,您可以查看最近的提要,删除的对象和删除对象。


当然。上面的答案是针对GitHub的。我们在本地安装了GitHub。感谢您提出问题。
Manohar Reddy Poreddy '17

1

我在删除分支的计算机上执行了此操作:

git reflog

响应:

74b2383 (develope) HEAD@{1}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{2}: checkout: moving from develope to master
74b2383 (develope) HEAD@{3}: checkout: moving from master to develope
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{4}: reset: moving to HEAD
40ef328 (HEAD -> master, origin/master, origin/HEAD) HEAD@{5}: clone: from http://LOCALGITSERVER/myBigProject/Android.git

我用此命令检索分支:

git checkout -b newBranchName 74b2383


0

只是使用git reflog并没有sha为我返回。仅commit id((长度为8个字符,而sha更长)

所以我用 git reflog --no-abbrev

然后执行与上述相同的操作: git checkout -b <branch> <sha>


您可以始终使用缩写的8个字符的阴影,而不必使用完整的阴影
Michael Dreher

0

如果您使用的是VSCode ... 并且在删除分支之前将分支与服务器进行了同步...

请注意,git branch delete仅删除本地副本,而不删除服务器上的副本。首先,在Git面板(左侧工具栏上的git图标)中,浏览分支并查看分支在“ origin / your_branch_name”下是否仍然存在。如果是这样,只需选择该选项,您就应该找回代码(建议您立即将其复制/粘贴/保存在其他地方)。

如果没有看到“ origin / your_branch_name”,请安装GitLens扩展名。这使您可以直观地在服务器存储库中四处浏览,并找到同步到服务器的副本。如果您有多个存储库,请注意,可能需要从所需的存储库中至少打开一个文件,以使该存储库出现在GitLens中。然后:

  1. 打开GitLens面板

  2. 扩展存储库

  3. 您应该会看到以下类别的列表:分支机构/贡献者/远程用户/储藏人员/等

您应该在“分支”下或可能在“ Remote-> Origins”下找到YourLostTreasure。希望您会看到一个具有所需名称的分支-如果展开它,您应该会看到在该分支中更改的文件。双击文件名将其打开,然后立即备份该代码。

如果您没有立即看到丢失的分支,请四处寻找,如果发现有希望的东西,请立即打开它并获取代码。我不得不四处摸索,直到找到TheGoldenBranch,即使这样,代码也丢失了最后一两次保存(可能是因为在尝试进行“分支合并”之前,我未能同步到服务器,但偶然地单击了“删除分支)。我的搜索不必要地延长了,因为当我第一次找到该分支时,我并不完全确定名称是否正确,因此一直在寻找,并且花了一些时间来重新找到该第一个分支。(因此,Carpe Carpum, 然后 继续查找。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.