在错误合并后重建 git 分支(尊重合并提交)
Rebuilding git branch after a faulty merge (respecting merge commits)
我有一个典型的情况:我将 dev
分支合并到 master
,然后意识到我犯了一个错误并恢复了合并。然后在 dev
中添加了一个修复并想再次合并它。当然不能直接合并,因为在git看来,已经合并了
经典方案
还原还原提交,应用您的修复。继续前进。
优点:简单。
缺点:历史被糟蹋了。很难责怪比这个还原的还原更深。
我想要的
我想从头开始重建 dev
分支,然后再次合并。根据书籍,使用 git rebase --force-rebase
应该很容易完成。但是分支历史并没有那么简单,它包含了很多合并,包括来自 master
的合并。我要尊重这些。
让我们举个例子:
master|
v
-*------------X-----Y---------*-----*----M-W
\ / \ \ / /
\ / \ -*- /
\ / -D- G--H-- /
\ / / \ / \ /
A--B--C-----E--F--------I-----J
^
|dev
错误的合并是M
。它的还原是 W
。我假设 dev
到 B
的提交是可以的,因为 B
被合并到 master
作为 X
。我想用完全相同的拓扑重建从 B
开始的分支。请看下面的树。新提交标有素数。您可以看到提交 C..J
是如何重新设置为 C'..J'
的。相应地,dev
变基为 dev'
。其他提交没有改变。
dev'|
v
C'----E'-F'-------I'----J'
/ \ / \ /
| -D' G'-H'-
| / |master
| / v
-*--------+---X-----Y---------*-----*----M-W
\ | / \ \ / /
\ | / \ -*- /
\ |/ -D- G--H-- /
\ / / \ / \ /
A--B--C-----E--F--------I-----J
^
|dev
然后我将应用我的修复 K
并将这个新分支合并到 master
:
dev'|
v
C'----E'-F'-------I'----J'--K
/ \ / \ / \
| -D' G'-H'- \
| / \ |master
| / \v
-*--------+---X-----Y---------*-----*----M-W-M2
\ | / \ \ / /
\ | / \ -*- /
\ |/ -D- G--H-- /
\ / / \ / \ /
A--B--C-----E--F--------I-----J
^
|dev
优点:良好的历史。
缺点:我不知道该怎么做。
好吧,好像 rebase
有一个选项,叫做 --rebase-merges
。但它没有做我想要的。它变基所有提交, 是 dev
的祖先和 B
的后代。其中包括提交 X
和 Y
。哪些已经在 master
上了,我为什么要它们? (实际上,它还带来了一些更古老历史的其他提交,我还不明白为什么,但这不是重点)。
相反,我想带来提交,它们是 dev
但不是 master
的祖先(考虑到错误合并之前的 master
当然)。对我来说听起来真的很容易。但是我不知道该怎么做,除非手动构建提交的这种差异并以某种方式手动 cherry-picking 它们,小心地保存 parents.
那么,如何重建我的分支,包含仅在我的分支上完成的工作并尊重合并提交?
PS我们不能简单地将master
重置为M^
,那太容易了。
基于https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt,我会
git checkout dev
$EDITOR files
git commit files -m 'Fix'
git checkout master
git revert W
git merge dev
当您 re-merge.
时,revert-revert 是保持更改所必需的
好的,看来我找到了解决办法:
git rebase --interactive --rebase-merges B dev
- 改写 C
这产生了我想要的历史。提示归功于 @mstrap。
我不太清楚为什么这会按照我想要的方式工作。
我有一个典型的情况:我将 dev
分支合并到 master
,然后意识到我犯了一个错误并恢复了合并。然后在 dev
中添加了一个修复并想再次合并它。当然不能直接合并,因为在git看来,已经合并了
经典方案
还原还原提交,应用您的修复。继续前进。
优点:简单。
缺点:历史被糟蹋了。很难责怪比这个还原的还原更深。
我想要的
我想从头开始重建 dev
分支,然后再次合并。根据书籍,使用 git rebase --force-rebase
应该很容易完成。但是分支历史并没有那么简单,它包含了很多合并,包括来自 master
的合并。我要尊重这些。
让我们举个例子:
master|
v
-*------------X-----Y---------*-----*----M-W
\ / \ \ / /
\ / \ -*- /
\ / -D- G--H-- /
\ / / \ / \ /
A--B--C-----E--F--------I-----J
^
|dev
错误的合并是M
。它的还原是 W
。我假设 dev
到 B
的提交是可以的,因为 B
被合并到 master
作为 X
。我想用完全相同的拓扑重建从 B
开始的分支。请看下面的树。新提交标有素数。您可以看到提交 C..J
是如何重新设置为 C'..J'
的。相应地,dev
变基为 dev'
。其他提交没有改变。
dev'|
v
C'----E'-F'-------I'----J'
/ \ / \ /
| -D' G'-H'-
| / |master
| / v
-*--------+---X-----Y---------*-----*----M-W
\ | / \ \ / /
\ | / \ -*- /
\ |/ -D- G--H-- /
\ / / \ / \ /
A--B--C-----E--F--------I-----J
^
|dev
然后我将应用我的修复 K
并将这个新分支合并到 master
:
dev'|
v
C'----E'-F'-------I'----J'--K
/ \ / \ / \
| -D' G'-H'- \
| / \ |master
| / \v
-*--------+---X-----Y---------*-----*----M-W-M2
\ | / \ \ / /
\ | / \ -*- /
\ |/ -D- G--H-- /
\ / / \ / \ /
A--B--C-----E--F--------I-----J
^
|dev
优点:良好的历史。
缺点:我不知道该怎么做。
好吧,好像 rebase
有一个选项,叫做 --rebase-merges
。但它没有做我想要的。它变基所有提交, 是 dev
的祖先和 B
的后代。其中包括提交 X
和 Y
。哪些已经在 master
上了,我为什么要它们? (实际上,它还带来了一些更古老历史的其他提交,我还不明白为什么,但这不是重点)。
相反,我想带来提交,它们是 dev
但不是 master
的祖先(考虑到错误合并之前的 master
当然)。对我来说听起来真的很容易。但是我不知道该怎么做,除非手动构建提交的这种差异并以某种方式手动 cherry-picking 它们,小心地保存 parents.
那么,如何重建我的分支,包含仅在我的分支上完成的工作并尊重合并提交?
PS我们不能简单地将master
重置为M^
,那太容易了。
基于https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt,我会
git checkout dev
$EDITOR files
git commit files -m 'Fix'
git checkout master
git revert W
git merge dev
当您 re-merge.
时,revert-revert 是保持更改所必需的好的,看来我找到了解决办法:
git rebase --interactive --rebase-merges B dev
- 改写 C
这产生了我想要的历史。提示归功于 @mstrap。
我不太清楚为什么这会按照我想要的方式工作。