在保留分支历史的情况下,修改先前合并分支中的提交记录

4

问题

假设我在 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 命令提交。然后我将 checkoutmaster 分支上,再用命令 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。(如果我误解了您的答案,请纠正我,Tim。)使用git log --oneline --graph命令得到的分支历史如下:

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

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


你试过直接从c3分支切出去并合并到master主分支吗? - jthill
这只是你的本地主分支吗?还是你已经推送了任何大于等于c3的内容? - Massey101
git checkout c3 会进入“分离头指针”状态,不建议在此状态下进行修改。如果您想修改提交历史记录,应使用 git rebase -i - gzh
只是我的本地主分支,@Massey101;尚未将任何内容推送到远程。 - digitalis_
@Tim(以及所有其他观众):我已经制作了一个Bash脚本,用于创建与问题中假设的测试存储库完全相同的存储库。您可以在GitHub上找到它:https://gist.github.com/danieloosthuizen/f9009b65ce9d833b268c - digitalis_
我不想将它嵌入问题中,因为它已经够长了! - digitalis_
3个回答

1
您可以使用交互式变基(interactive rebase):
git checkout master
git rebase -i c2

这将打开一个编辑器,每个提交显示一行。将c3行中的pick更改为edit。保存并关闭。现在,git会将您倒回到c3,并停在那里让您进行编辑。更改您想要更改的内容,然后使用amend命令进行修改。

git commit --amend
git rebase --continue

当编辑器打开时,它只显示了一行 pick c4 <message>;在我中止 rebase 之后,似乎已经将分支历史展平了。 - digitalis_
@digitalis_ 很抱歉,我犯了一个错误。已经更新了我的答案(git rebase -i c3)。关于你想要扁平化分支历史的问题:很奇怪,中止的变基操作不应该有任何影响。希望你能想办法恢复它? - Tim Pohlmann
1
不用担心,@Tim,我正在使用一个测试仓库 - 没有丢失任何数据。我似乎已经找到了使用交互式变基的答案,就像你建议的那样。感谢你的帮助! - digitalis_
关于奇怪的压平:我认为我一定是先执行了 :wq 然后又执行了 git rebase --abort,这可能是导致压平的原因。 - digitalis_

1
我似乎找到了答案!感谢 Tim 的启发,让我尝试使用 --interactive rebase。
基本上,答案在于执行 git rebase -p -i <root>;我将调用分支历史记录分叉 <root> 之前的提交。在问题的假设情况下,<root>c2-p--preserve-merges 的简写,它将阻止 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 rebase --continue。重复此过程,直到git告诉您变基成功为止。

哦,是啊,我忘记加上 -p 了。很高兴你解决了这个问题! - Tim Pohlmann
1
谢谢@Tim;你的回答(和耐心)帮了我很多! - digitalis_

0

根据您的问题,当您在测试分支中进行c4提交并将其合并到主分支时,快进模式只会将主参考移动到c4,为什么您认为您会丢失分支历史并故意使用--no-ff选项?

关于您尝试过的内容,似乎您修改了主分支时间线,因此提交图是一个明显的结果。


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