修改先前合并分支的过去提交,同时保留分支历史记录

Amend a past commit from a previously merged branch, while keeping branch history

问题

说我在master上做了一些工作:

c1 <- c2
       ^
     master

此时,我分支,做一些更多的工作:

                test                  
                 v
          c3 <- c4
c1 <- c2 /
       ^   
     master

然后执行 git merge --no-ff--no-ff 以保留分支历史记录):

                test                  
                 v
          c3 <- c4
c1 <- c2 /        \ [c5]
                      ^   
                    master

[c5] 是合并提交)

然后我删除了 test 分支,以为我已经完成了它。但是,我发现,毕竟我在test上所做的工作有问题。我需要修改 c3,但 不会损害分支历史。


我尝试过的事情


我的尝试

git checkout c3;然后改我需要改的,然后git commit --amend。然后我 checkout master 分支,和 git branch temp c3。然后我 git rebase --preserve-merges temp:这给了我一个合并冲突,我修复了它,然后 git add <file>git rebase --continue

但是,当我使用 git log --oneline --graph 查看分支历史记录时,我看到如下内容:

*  [c5]
|\
| * c4
|/
* c3'
* c2
* c1

它应该看起来更像这样:

*  [c5]
|\
| * c4
| * c3'
|/
* c2
* c1

其中 c3' 是修改后的提交。

我怎样才能摆脱 git 的这种行为?

蒂姆的建议

git checkout c3
git checkout -b test
git commit --amend
git checkout master
git reset --hard c2
git merge --no-ff test

不幸的是,这似乎不起作用,因为我们输了 c4。 (蒂姆,如果我误解了你的回答,请纠正我。)git log --oneline --graph 的结果分支历史如下:

*  [c5]
|\  
| * c3'
|/  
* c2
* c1

其中 [c5'] 是一个新的合并提交。 (顺便说一句,我不介意它是新的。)

如你的问题所示,当你在test分支中提交c4并将其合并到master分支时,快进模式只会将master引用移动到c4,你为什么认为你会丢失分支历史并使用--no-ff 选项是故意的?

关于你的尝试,似乎你对主分支时间线的时间线进行了修改,所以提交图是一个明显的结果。

您可以使用交互式变基:

git checkout master
git rebase -i c2

这应该打开一个编辑器,每次提交一行。将 c3 行中的 pick 更改为 edit。保存并关闭。现在 git 将您倒回到 c3 并将在那里停下来让您进行编辑。改你想改的,用

修改
git commit --amend
git rebase --continue

我似乎找到了答案!谢谢你,蒂姆,给了我尝试 --interactive 变基的灵感。

基本上,答案在于做一个git rebase -p -i <root>;我在分支历史分支 <root> 之前调用提交。在问题的假设情况下,<root>c2.

对于 --preserve-merges-p 是 shorthand,这将阻止 git rebase 删除合并提交。

编辑器会弹出如下内容:

pick c3 <message>
pick c4 <message>
pick [c5] <message>

c3 之前的 pick 更改为 edit 以便您拥有:

edit c3 <message>
pick c4 <message>
pick [c5] <message>

保存并退出。进行您想要进行的更改,添加它们,然后 git commit --amend。在此之后,您需要git rebase --continue 继续变基。

在此期间您可能会遇到合并冲突。只需修复冲突,git add 更改的文件以将冲突标记为已修复,然后 git rebase --continue。重复此操作,直到 git 告诉您变基已成功。