恢复合并时如何找出分支号?

Posted

技术标签:

【中文标题】恢复合并时如何找出分支号?【英文标题】:How to find out branch numbers when reverting a merge? 【发布时间】:2014-02-13 05:36:25 【问题描述】:

我的提交历史如下:

A - B - C - D - E
     \     /
      X - Y

分支ABCDEmaster,分支XY 是某个其他分支(比如test),D 是一个合并提交。 HEAD 现在位于 E。我需要将我的工作目录返回到A 的状态,假设 使用git reset --hard <SHA1(A)>,只使用git revert。据我所知,在这种情况下,可以通过两种方式完成:

第一种方式:

git revert --no-commit <SHA1(E)>
git revert -m 1 --no-commit <SHA1(D)>
git revert --no-commit <SHA1(C)>
git revert --no-commit <SHA1(B)>
git commit -m "Reverted to state A"

第二种方式:

git revert --no-commit <SHA1(E)>
git revert -m 2 --no-commit <SHA1(D)>
git revert --no-commit <SHA1(Y)>
git revert --no-commit <SHA1(X)>
git revert --no-commit <SHA1(B)>
git commit -m "Reverted to state A"

一个绊脚石是git revert -m。在这个例子中,我假设1 允许沿着分支master2 沿着分支test 继续恢复链。

问题是:我怎么知道哪个数字代表哪个分支?

【问题讨论】:

你为什么不直接git checkout A?如果需要切换分支指向 A,git checkout A; git branch -D NAME; git branch NAME; git checkout NAME。您仍然可以结帐任何 ABCDEX 或 Y。 实际上我正在使用远程仓库,在这种情况下,我只能恢复,不能重置和结帐。 我会在 A 和 HEAD 之间生成一个补丁,然后使用 patch -R 反向应用它。 啊。所以你想要一个新的提交来“回到过去”,对吧? @Kaz 正是我要提出的建议! 【参考方案1】:

您可以检查合并提交以查看其父级:

git show <SHA1(D)>

父母将按照您可以参考的顺序列出。此信息也打印在git log 的输出中。使用它来推断当您执行 git revert -m 时意味着哪些提交。

编辑:您似乎正在使用公共存储库并寻找一种更改已发布分支的方法,这与更改工作副本的状态完全不同。 Git 有一种方法可以恢复,而不必在此过程中找出合并的每个父级。一次性完成:

git revert <SHA1(B)>..

更新:我正在阅读一些旧的东西,并意识到我给出的这个答案是完全不正确的。如果您执行上述操作,您将不会获得状态 A,而是会获得您不想要的科学怪人:

A - C' - D' - E'
 \     /
  X - Y

那个 ^ 相当于你得到的,这根本不是你想要的。实际上只有一种方法可以做到这一点并完全保留您的历史记录:

git revert HEAD              # reverts E, labeled as E' below
git revert -m 1 <SHA1(D)>    # reverts D, labeled as D' below
git revert HEAD              # reverts C, labeled as C' below
git revert HEAD              # reverts B, labeled as B' below

这将使您的历史看起来像这样:

A - B - C - D - E - E' - D'C - C' - B'
     \     /
      X - Y

这种方法会得到你想要的,并保留每一点历史。 @Kaz 和 @torek 的方法更有效,更简洁,如果您不想重新引入 XY,那么我推荐其中一种解决方案;但是,如果您关心的话,它们可能会使将 XY 重新引入您的主分支变得更加困难。还原每个部分使得重新引入XY 成为可能,而无需再次重写/C&P 代码,如果XY 发生很大变化,或者如果您执着于保持最准确的历史记录,这是一个有吸引力的选择可能(我倾向于那样)。

要重新引入XY,您应该这样做:

git revert D'

这可能会产生合并冲突,尤其是如果您不同时还原 B'C',但这可能比手动重新执行 XY 更好。 Linux Torvalds 写了a very thorough explanation of this scenario 可能对你有一些帮助。

【讨论】:

启动一个新分支不会将那个分支恢复到A点。每个人都必须切换到新分支。他可能也不想重置,因为这是一个非快进更改。 啊。他没有在他的问题中指定任何关于公共回购的信息,这很关键。 他确实指定重置为 A 是不可接受的。如果这些更改未发布到任何其他存储库,则该解决方案没有理由不可接受。【参考方案2】:

另一种方法是简单地清空工作树,然后插入工作树-as-it-was-at-commit-A:

# assumes you're in the top level
$ git rm -rf .
$ git checkout sha-or-other-specifier-for-A -- .
$ git commit -m 'revert to state A'

这里的想法是git rm -rf 完全清空工作树和索引/暂存区,然后git checkout &lt;rev&gt; -- . 完全重新填充工作树和索引/暂存区,但从指定的修订版本,而不是最新版本。

这两个完成后,新的提交将写入与提交 A 中相同的树和文件。

【讨论】:

【参考方案3】:

在这种情况下,我不会在 git 上绞尽脑汁,而是这样做:

git diff <sha(A)> HEAD | git apply -R
git commit -a -m "undoing everything since A"

当然,在提交之前检查所有内容。另外,在提交之后,验证:现在 A 和 HEAD 有什么区别?理想情况下,什么都没有:

git diff <sha(A)> HEAD

【讨论】:

@Andy Envy;复仇;在智能手机的小屏幕上笨拙地涂抹; TCP/IP 校验不足... :) @Kaz 我只是想给你投票,但我没有足够的声誉:( 还有另一种方法可以避免需要 diff-and-apply,因此稍微容易一些(有时但并不总是更快);我会添加它作为答案。

以上是关于恢复合并时如何找出分支号?的主要内容,如果未能解决你的问题,请参考以下文章

从分支 B 合并时,在分支 A 上恢复的提交不存在

如何恢复已经推送到远程分支的合并提交?

您如何合并已恢复的提交?

GIT:如何在恢复合并后从分支中提取更改

恢复分支独有的提交

重新提交在 git 中恢复的提交