有没有一种简单清晰的方法可以撤销 git 合并操作?

3

我读到过这样的说法,即执行 git reset commitBeforeDoingMerge --hard 操作不会撤销合并:

1pm-3pm This is my branch and I need to merge master into it
1pm-2pm This was master
1pm-2pm-3pm-4pm Merging ended up doing this, 4pm being the merge commit
1pm-2pm-3pm if This is the result if you do git reset 3pm --hard, because it does not undo the merge, it just goes back to that commit in the branch that was merged.

现在,另一个提议是执行 git revert 4pm -m 1,但是根据手册,这样做存在问题:

通常情况下,您无法撤消合并,因为您不知道应该将合并的哪一侧视为主线。此选项指定了主干的父代编号(从1开始),并允许回退相对于指定父代的更改。

撤消合并提交意味着您永远不想使用合并引入的树更改。结果,以后的合并只会带来那些不是之前撤消合并祖先的提交所引入的树更改。这可能是您想要的,也可能不是。

那么,有没有一种简单清晰的方式可以取消 Git 合并操作呢?


1
git reset --hard 可以撤销合并操作(始终如一且干净),但我认为您应该澄清如何完成“合并”,因为合并至少应该有两个平行的分支,而不是单个线条。 - ian
@ian 我更新了问题,现在可能更清楚了。Git reset --hard会将你带回那个快照,但不会撤消对历史记录所做的更改。 - user33276346
3个回答

3
我看到有人说执行 git reset commitBeforeDoingMerge --hard 命令并不会撤销合并操作,但这是错误的。这确实是撤销合并操作的正确方法。假设你正在将 branch 合并到 master 分支中,那么在合并之前,状态应该是这样的:
A -- B -- C (master)
 \
  X -- Y (branch)

好的,所以我们执行 git checkout mastergit merge branch 命令。结果是:
A -- B -- C -- D (master)
 \             |
  X -- Y (branch)

...这里的 D 是合并提交,其父提交为 C 和 Y。

如果你现在执行 git reset --hard <C的SHA值> 命令,你会回到这个状态:

A -- B -- C (master)
 \
  X -- Y (branch)

这是一个完美的撤销功能。


1
我不确定您在做什么,但这不是 git merge 的工作方式。 我会尝试重现您所做的事情,也许您可以看出不同之处。
首先,我创建了您的两个起始分支:
git log --oneline --graph --all
* 0593ba1 (HEAD -> test) 3pm
| * eba415c (master) 2pm
|/
* 7f9a804 1pm

将主分支合并到测试分支。 git merge master -m "4pm"

git log --oneline --graph --all
*   6be609f (HEAD -> test) 4pm
|\
| * eba415c (master) 2pm
* | 0593ba1 3pm
|/
* 7f9a804 1pm

现在我们将测试重置回3点。
git reset --hard 0593ba1
HEAD is now at 0593ba1 3pm

git log --oneline --graph --all
* 0593ba1 (HEAD -> test) 3pm
| * eba415c (master) 2pm
|/
* 7f9a804 1pm

现在我们发现2pm的提交只在主分支中,为了确认仅进行了测试的日志。
git log --oneline
0593ba1 (HEAD -> test) 3pm
7f9a804 1pm

这是我如何合并和撤销合并的方法,请随意告诉我您的不同做法或者我没有按您需要的方式重现示例。

我认为混淆出现在我把已推送的合并撤销的想法混淆在了一起。因此,我尝试找到一种干净的方法来撤销它,而不必重写历史记录。 - user33276346
不用担心,很高兴能帮上忙。如果你真的想撤销合并操作而不重写历史记录,你可以使用 git revert -m <#parent> <sha> 命令来实现,但是请务必仔细阅读相关文档,因为它也有自己的陷阱,我不确定它是否比重写历史记录更好的解决方案。 - ian

0

重置应该已经生效了,但在主分支上,重置到e:

合并后:

a-b-d  (mybranch)
  \
   c-e (master)

myBranch合并到主分支应该得到:

a-b---d  (mybranch)
  \    \
   c-e-f (master)

没有任何分支会列出abcdef,只有abcef(主分支)

如果您在master上执行reset --hard e,则会返回原始历史记录(如上面的第一个)

如果您在主分支上执行reset --hard d,则已经移动了主分支HEAD,但合并仍然存在:

a-b---d  (mybranch, master)
  \    \
   c-e-f

我正在将主分支合并到我的分支中。我不理解你的回答,所以我更新了问题,也许更清楚了。 - user33276346

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接