如何“压缩”后续合并提交

时间:2019-11-11 14:03:30

标签: git git-merge git-rewrite-history

在我的项目中,我有这样的历史记录:

    b --- c --- g
  /        \     \ 
a           f --- h --- j
  \        /           /
    d --- e --- i ----

我想删除中间的合并提交,并且只有一个合并提交具有相同的内容,例如:

    b --- c --- g
  /              \ 
a                 j'
  \              /
    d --- e --- i 

一种方法是从头开始重做所有内容,但是f拥有大约。 600个有冲突的文件,g实际上又是200个新的提交,我不想再花一个星期来解决冲突。 我该如何实现?

3 个答案:

答案 0 :(得分:3)

如果我知道分支结构,也许可以更清楚地解释该过程,但是通常您会这样做:

您实际上只需要在gi之间创建新的合并,因为在绘制时,您要删除的任何合并都不在{{1 }}或g,并且所有相关更改 ig的历史记录中(即,要删除的部分仅 合并提交[1])。

您不想重做所有冲突解决方案,但这没关系,因为您已经知道合并的期望结果。因此,您需要复制父母为ij的{​​{1}}的副本。至少有两种方法可以做到这一点。

最直接的方法是使用管道命令,因此看起来不太熟悉。

g

其中i是您当前在git checkout $( git commit-tree j^{tree} -p g -p i -m "merge message here" ) git branch -f my_branch 处的分支,而my_branch jj是可从图中解析为相应提交的表达式。 (可以是提交iD(SHA)值,当前指向这些提交的引用,等等。)

请记住,提交的父项是有序的-第二个g选项标识将看起来已被“合并到”第一个i选项的提交中的提交。

另一种方法是检出-p(假设-p应该是第一次提交;否则,请在此过程中交换gg),并且

g

采用这种方法,您将启动一个新的合并,清除工作树和索引,从先前的合并结果中加载提交树和索引,然后使用该内容完成合并。

我发现这涉及到更多问题,它包含一个i命令,如果您不确定正在发生的事情,该命令可能会发出红旗,但是它的优点是坚持使用面向最终用户的命令


[1]我有点假设没有任何合并会引入新的更改(冲突解决除外)。如果这样做,它们有时就是所谓的“邪恶合并”。实际上,上面的过程仍然可以使用,但是也会导致您的新合并也是“恶意合并”。

答案 1 :(得分:0)

我想能够在不完成任何合并过程的情况下一次性完成任务的唯一方法是使用git commit-tree。首先,使用git cat-file获取J版本的树的ID:

git cat-file -p j

复制树对象的ID。

然后运行git commit tree,您可以使用-p提供2个父修订版,使用-m提供注释,并且从上一个git命令获得的树ID将用作调用的最后一个参数。 / p>

git commit-tree -m 'Here's the comment" -p g -p i tree-object-of-j

运行该命令时,git将打印出已创建的新修订版对象的ID。您可以指向它的分支,或者如果已经检查修订是否只是想要的,则移动j指针:

git branch -f j new-revision-of #move j branch to the new revision id

您将是修订的作者。...如果要更改日期或作者,则可以通过设置环境变量来完成。选中git help commit-tree

答案 2 :(得分:0)

这是执行此操作的一种方法:

 git reset --hard g //reset branch to g commit (use 'i' and merge 'g' if the  branch originally came from i) 
 git merge i --no-commit  
 git reset j :/: //resolve all conflicts by replacing the staging area with all file versions from original commit j
 git commit
 optional:  git reset --hard //if you want the work tree to reflect the new merge commit