撤消Git Rebase
我在我的分支上执行了一个git rebase master
,并没有意识到它并不是我想要的,直到我把它推到远程之后。 只有我自己和另外一个人参与了这个项目,所以我知道他们还没有取得最新的变化。
阅读StackOverflow的其他问题,它说使用git reflog
,然后在git reset --hard HEAD@{n}
之前将gad git reset --hard HEAD@{n}
。 我这样做是为了在rebase之前创建一个提交,但它并没有恢复到之前的状态。
我错过了一步吗? 有没有办法让其他人强行推回他的回购以恢复他们的状况?
谢谢
正如Makoto已经指出的那样,你可能不应该打扰撤销这个rebase:这可能是你想要的。 尽管如此,随时阅读如何撤消它。
使用分支的reflog,因为它更易于阅读。 ( HEAD
reflog具有相同的信息,但有更多的东西在里面,因此很难找到你要找的东西。)
例如,如果我刚刚重新mybranch
,我会看到:
$ git reflog mybranch
nnnnnnn mybranch@{0}: rebase finished: refs/heads/mybranch onto biguglysha1
ooooooo mybranch@{1}: commit: some sort of commit message
...
因此,名称mybranch@{1}
与ooooooo
(旧缩写的SHA-1)同义(此刻)。 每次你对分支做一些事情(比如git reset
)时, @{...}
部分中的数字将会改变,而SHA-1永远是永久的,所以使用SHA-1会更安全一些或缩写)用于剪切和粘贴。
如果你那么:
$ git checkout mybranch # if needed
和:
$ git reset --hard ooooooo # or mybranch@{1}
你应该有原始的背面。 这是因为rebase
只是复制提交,然后移动标签。 在重新绑定之后,但在重置之前,提交图看起来像这样,其中A
到C
是“您的”提交:
A - B - C <-- (only in reflog now)
/
... - o - o - o - A' - B' - C' <-- mybranch (after rebase)
和git reset
simply1擦除当前分支标签并将其粘贴到提供的SHA-1上(如果需要,首先将reflog名称转换为SHA-1)。 因此, reset
:
A - B - C <-- mybranch, plus older reflog
/
... - o - o - o - A' - B' - C' <-- (only in reflog now)
请注意,现在, reset
后,基于rebase的提交副本是仅在reflog条目中找到的“已抛弃”副本。 被遗弃的原件现在再次在mybranch
下mybranch
。
思考这个东西的方法是绘制提交图(使用新提交指向他们的父提交),然后用长箭头指向提交图来绘制分支标签。 除了添加新的提交,它有新的和不同的大丑丑SHA-1s(这就是为什么我用A
B
和C
来代替字母,并且像A'
的复制品)添加剂的原因。 SHA-1保证是独一无二的3并且是永久性的,但带有长箭头的标签会一直被擦除和重新指向。 (如果您在白板上进行此操作,则通常应将黑色用于提交图形,并将颜色或多种颜色用于标签。)
1Well, git reset
不仅仅是移动标签,除非你添加一些命令行标志。 默认情况下,它移动标签并重置索引; 使用--hard
,它会移动标签并重置索引并清除您的工作树。 使用 - --soft
只需移动标签,只留下索引和工作树。 Git的是它是什么,还有一堆更多的标志,即使进一步扭动起来的意思,但这些都是三巨头: --soft
,没什么又名--mixed
,和--hard
。
2如果git只添加了一些东西,那么随着时间的推移,您的回购将会变得非常庞大。 因此,最终,“无法访问”提交 - 没有标签的提交,甚至没有任何剩余的reflog条目指向它们,并且这些条目不是由具有标签或某些其他指向提交的提交指向的 - 最终这些无法访问的提交(以及任何其他不可访问的对象)在git自动运行git gc
时被删除。 你可以强制它们被更早的移除,但是很少有理由去打扰。
3Git本身取决于保证。 这在数学上是可能的,但极不可能的是,任何两个不同的物体都会以相同的SHA-1结束。 如果发生这种情况,git就会中断。如果分布足够好,那么2160中的概率就是1,这非常小。 这是一件好事,因为“生日悖论”很快就提出了这种可能性,但因为它开始很小,所以它很小,实际上它从来不是问题。
4By的设计中,“破坏”是git只是停止添加对象,所以所有的东西都还是不错的。 然后你必须转向任何新的系统来处理数十亿个对象库,“下一代”git或其他任何东西。
我对你有好消息和坏消息。
好消息是,你处于表达你想要的状态! master
的最后一次提交现在确实在你的分支中,并且一切都与宇宙有关。
坏消息是,现在,通过你的转换操作,你已经有效地将你的分支转移到了主控端; 也就是说,您的开发分支现在处于相同的状态,就好像您只是从主控端分支一样。
但是这被认为是一件好事:假设你没有任何合并冲突,你没有在这个过程中丢失任何数据,并且你的分支也没有一个无价值的合并提交。
这本书很好地解释了什么是rebase,所以我不会重复。 从你描述的操作中,你不应该失去任何工作。
如果您确实想在强制推送之前重新创建原始历史记录,那么具有非拉取历史的人可以强制将其分支推送到远程存储库。 这会导致您的回购状态成为他们推动时的回报状态。
如果你确实从reflog获取提交散列(也是正常git日志中条目的尾部),那么你可以得到reset --hard COMMIT,然后git push -f origin master,这通常是一件坏事。 我建议在执行强制推送之前查看完整的历史记录到单独的干净目录。
链接地址: http://www.djcxy.com/p/23537.html上一篇: Undo Git Rebase
下一篇: Aborted old git rebase and lost commits since the rebase started