撤消“= 10 =”之前
Undo Git Rebase
我在我的分支上执行了一个 git rebase master
,直到我将它推送到远程后才意识到这不是我想要的。只有我自己和另外 1 个人在处理这个项目,所以我知道他们没有提取最新的更改。
阅读 Whosebug 上的其他问题,它说在 rebase 之前使用 git reflog
然后 git reset --hard HEAD@{n}
。我这样做是为了转到我在变基之前创建的提交,但它并没有将事情恢复到以前的状态。
我是不是漏掉了一步?有没有办法让其他人强制推送他的回购协议以将事情恢复到原来的样子?
谢谢
如果您确实从 reflog(也是正常 git 日志中条目的尾部)获取提交哈希,您可以执行 get reset --hard COMMIT 然后 git push - f origin master 通常是 bad thing 。我建议在执行强制推送之前将完整的历史记录检出到一个单独的、干净的目录中。
我有好消息和坏消息要告诉你。
好消息是,您正处于 的状态! master
上的最后一次提交现在确实在您的分支中,宇宙一切正常。
坏消息是,现在,通过你的 rebase 操作,你已经有效地将你的分支移到了 master 的顶端;也就是说,您的开发分支现在处于相同的状态,就好像您只是从 master 的尖端分支出来一样。
但这[被认为]是一件好事:前提是您没有任何合并冲突,在此过程中您没有丢失任何数据,并且您也没有无价值的合并提交在你的分支上。
The book does a great job explaining what a rebase is,就不重复了。从您描述的操作来看,您应该不会丢失任何工作。
如果您确实想在强制推送之前重新创建原始历史记录,那么具有非拉取历史记录的人可以将他们的分支强制推送到远程存储库。这将导致你的回购协议的状态是他们推送时他们盒子上的任何东西。
作为 ,您可能不应该费心撤消此变基:这可能正是您想要的。尽管如此,请继续阅读以了解如何撤消它。
为分支使用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
只是 复制 提交然后移动标签。在 rebase 之后,但在重置之前,提交图看起来像这样,其中 A
到 C
是 "your" 提交:
A - B - C <-- (only in reflog now)
/
... - o - o - o - A' - B' - C' <-- mybranch (after rebase)
和 git reset
只是 1 擦除当前分支标签并将其粘贴到提供的 SHA-1 上(如果需要)。因此,在 reset
:
之后
A - B - C <-- mybranch, plus older reflog
/
... - o - o - o - A' - B' - C' <-- (only in reflog now)
请注意,现在 post-reset
,rebase 制作的提交副本是 "abandoned" 那些只能在 reflog 条目中找到的副本。已被放弃的原件现在再次在 mybranch
下声明。
考虑这些东西的方法是绘制提交图(新提交指向它们的父提交),然后绘制分支标签,长箭头指向提交图。除了 add new 提交之外,该图从不2 更改,它有新的和不同的大丑 SHA- 1s(这就是为什么我使用 A
B
和 C
之类的字母,并在副本上添加 A'
之类的添加剂)。 SHA-1 保证是唯一的 3 并且是永久的,但是带有长箭头的标签会一直被擦除并重新指向。 (如果您在白板上执行此操作,您通常应该使用黑色作为提交图,并使用一种颜色或多种颜色作为标签。)
1嗯,git reset
不只是移动标签,除非您添加一些命令行标志。默认情况下,它移动标签 并且 重置索引;使用 --hard
,它移动标签 and 重置索引 and 清理你的工作树。使用 --soft
它 只是 移动标签,单独留下索引和工作树。由于 git 是什么,还有更多的标志进一步扭曲了意义,但这是三大标志:--soft
、--mixed
和 [=33] =].
2如果 git 只添加东西,你的仓库会随着时间的推移变得越来越大。所以,最终,"unreachable" 提交——那些没有标签,甚至没有任何剩余的 reflog 条目,指向它们,并且没有被 做 的一些提交指向有一个标签,或其他一些指向提交——当 git 自动为你运行 git gc
时,最终这些无法访问的提交(以及任何其他无法访问的对象)将被删除。您可以强制提前删除它们,但很少有好的理由去麻烦。
3Git本身就靠保底了。任何两个不同的对象都以相同的 SHA-1 结束,这在数学上是可能的,但极不可能。如果发生这种情况,git 就会崩溃。4 如果分布足够好,则概率为 2160 中的 1,这确实是微小的。这是一件好事,因为 "Birthday paradox" 迅速提高了可能性,但因为它开始时很小,所以它保持很小,在实践中从来都不是问题。
4根据设计,"breakage" 是 git 只是停止添加对象,因此到目前为止一切都很好。然后,您必须转移到已设计用于处理数十亿对象存储库的任何新系统,"next generation" git 或其他任何系统。
我在我的分支上执行了一个 git rebase master
,直到我将它推送到远程后才意识到这不是我想要的。只有我自己和另外 1 个人在处理这个项目,所以我知道他们没有提取最新的更改。
阅读 Whosebug 上的其他问题,它说在 rebase 之前使用 git reflog
然后 git reset --hard HEAD@{n}
。我这样做是为了转到我在变基之前创建的提交,但它并没有将事情恢复到以前的状态。
我是不是漏掉了一步?有没有办法让其他人强制推送他的回购协议以将事情恢复到原来的样子?
谢谢
如果您确实从 reflog(也是正常 git 日志中条目的尾部)获取提交哈希,您可以执行 get reset --hard COMMIT 然后 git push - f origin master 通常是 bad thing 。我建议在执行强制推送之前将完整的历史记录检出到一个单独的、干净的目录中。
我有好消息和坏消息要告诉你。
好消息是,您正处于 master
上的最后一次提交现在确实在您的分支中,宇宙一切正常。
坏消息是,现在,通过你的 rebase 操作,你已经有效地将你的分支移到了 master 的顶端;也就是说,您的开发分支现在处于相同的状态,就好像您只是从 master 的尖端分支出来一样。
但这[被认为]是一件好事:前提是您没有任何合并冲突,在此过程中您没有丢失任何数据,并且您也没有无价值的合并提交在你的分支上。
The book does a great job explaining what a rebase is,就不重复了。从您描述的操作来看,您应该不会丢失任何工作。
如果您确实想在强制推送之前重新创建原始历史记录,那么具有非拉取历史记录的人可以将他们的分支强制推送到远程存储库。这将导致你的回购协议的状态是他们推送时他们盒子上的任何东西。
作为
为分支使用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
只是 复制 提交然后移动标签。在 rebase 之后,但在重置之前,提交图看起来像这样,其中 A
到 C
是 "your" 提交:
A - B - C <-- (only in reflog now)
/
... - o - o - o - A' - B' - C' <-- mybranch (after rebase)
和 git reset
只是 1 擦除当前分支标签并将其粘贴到提供的 SHA-1 上(如果需要)。因此,在 reset
:
A - B - C <-- mybranch, plus older reflog
/
... - o - o - o - A' - B' - C' <-- (only in reflog now)
请注意,现在 post-reset
,rebase 制作的提交副本是 "abandoned" 那些只能在 reflog 条目中找到的副本。已被放弃的原件现在再次在 mybranch
下声明。
考虑这些东西的方法是绘制提交图(新提交指向它们的父提交),然后绘制分支标签,长箭头指向提交图。除了 add new 提交之外,该图从不2 更改,它有新的和不同的大丑 SHA- 1s(这就是为什么我使用 A
B
和 C
之类的字母,并在副本上添加 A'
之类的添加剂)。 SHA-1 保证是唯一的 3 并且是永久的,但是带有长箭头的标签会一直被擦除并重新指向。 (如果您在白板上执行此操作,您通常应该使用黑色作为提交图,并使用一种颜色或多种颜色作为标签。)
1嗯,git reset
不只是移动标签,除非您添加一些命令行标志。默认情况下,它移动标签 并且 重置索引;使用 --hard
,它移动标签 and 重置索引 and 清理你的工作树。使用 --soft
它 只是 移动标签,单独留下索引和工作树。由于 git 是什么,还有更多的标志进一步扭曲了意义,但这是三大标志:--soft
、--mixed
和 [=33] =].
2如果 git 只添加东西,你的仓库会随着时间的推移变得越来越大。所以,最终,"unreachable" 提交——那些没有标签,甚至没有任何剩余的 reflog 条目,指向它们,并且没有被 做 的一些提交指向有一个标签,或其他一些指向提交——当 git 自动为你运行 git gc
时,最终这些无法访问的提交(以及任何其他无法访问的对象)将被删除。您可以强制提前删除它们,但很少有好的理由去麻烦。
3Git本身就靠保底了。任何两个不同的对象都以相同的 SHA-1 结束,这在数学上是可能的,但极不可能。如果发生这种情况,git 就会崩溃。4 如果分布足够好,则概率为 2160 中的 1,这确实是微小的。这是一件好事,因为 "Birthday paradox" 迅速提高了可能性,但因为它开始时很小,所以它保持很小,在实践中从来都不是问题。
4根据设计,"breakage" 是 git 只是停止添加对象,因此到目前为止一切都很好。然后,您必须转移到已设计用于处理数十亿对象存储库的任何新系统,"next generation" git 或其他任何系统。