59

我想有一个简单的解决方案来在交互式 rebase 期间将两个合并提交压缩在一起。

我的存储库看起来像:

   X --- Y --------- M1 -------- M2 (my-feature)
  /                 /           /
 /                 /           /
a --- b --- c --- d --- e --- f (stable)

也就是说,我有一个my-feature最近合并了两次的分支,中间没有真正的提交。我不只是想重新设置my-feature分支,因为它是它自己的已发布分支,我只想将最后两个合并提交合并为一个(尚未发布这些提交)

   X --- Y ---- M (my-feature)
  /            /
 /            /
a --- ... -- f (stable)

我试过了:

git rebase -p -i M1^

但我得到了:

Refusing to squash a merge: M2

我最后做的是:

git checkout my-feature
git reset --soft HEAD^  # remove the last commit (M2) but keep the changes in the index
git commit -m toto      # redo the commit M2, this time it is not a merge commit
git rebase -p -i M1^    # do the rebase and squash the last commit
git diff M2 HEAD        # test the commits are the same

现在,新的合并提交不再被视为合并提交(它只保留了第一个父级)。所以:

git reset --soft HEAD^               # get ready to modify the commit
git stash                            # put away the index
git merge -s ours --no-commit stable # regenerate merge information (the second parent)
git stash apply                      # get the index back with the real merge in it
git commit -a                        # commit your merge
git diff M2 HEAD                     # test that you have the same commit again

但是如果我有很多提交,这可能会变得复杂,你有更好的解决方案吗?谢谢。

米尔德里德

4

6 回答 6

56

这是一个老话题,但我只是在寻找类似信息时遇到了它。

类似于Subtree octopus merge中描述的技巧是解决此类问题的一个非常好的方法:

git checkout my-feature
git reset --soft Y
git rev-parse f > .git/MERGE_HEAD
git commit

这将采用存在于 my-feature 尖端的索引,并使用它从 Y 创建一个新的提交,并将“f”作为第二个父级。结果与您从未执行过 M1 而是直接执行 M2 相同。

于 2010-11-09T20:51:12.877 回答
8

如果您尚未发布最后两个合并提交,您可以进行重置和简单合并。

git reset --hard Y
git merge stable
于 2009-11-12T22:34:37.577 回答
5

我来到这个话题想压缩一个合并提交;所以我的回答对原始问题没有那么有用。

               X
                \   
                 \  
a --- b --- c --- M1 (subtree merge)

我想要的是 rebase M1 合并并将所有内容压缩为 b 之上的单个提交。

a --- b --- S (include the changes from c, X and M1)

我尝试了各种不同的组合,但这是有效的:

git checkout -b rebase b (checkout a working branch at point b)
git merge --squash M1

这会将更改应用到可以提交的索引中 git commit

于 2013-07-04T20:23:58.473 回答
2

使用原始合并提交的树对象将确保内容保持不变。commit-tree 可用于使用所需的父级和相同的内容进行新的提交。但是,要使 fmt-merge-msg 生成正常的合并消息,您需要首先软重置回 Y。这是使用通用配方打包的所有内容:

parent2=$(git rev-parse f)
parent1=Y
merge_branch=stable
tree=$(git rev-parse HEAD^{tree})
git reset --soft $parent1
commit=$(echo $parent2$'\t\t'"branch $merge_branch" | git fmt-merge-msg | git commit-tree -p $parent1 -p $parent2 -F - $tree)
git reset --hard $commit

这是一个可以放在 ~/.gitconfig 中的别名:

[alias]
    remerge = "!f() { p1=$1; p2=`git rev-parse $2`; t=`git rev-parse HEAD^{tree}`; git reset --soft $p1; git reset --hard `echo $p2$'\t\t'"branch ${3:-$2}" | git fmt-merge-msg | git commit-tree -p $p1 -p $p2 -F - $t`; }; f"

启用:

git remerge <parent1-rev> <parent2-rev> [<parent2-branch>]
于 2021-12-12T21:44:47.907 回答
1

对于最近的 git 版本,上述方法均不适用于我。在我的情况下,以下是诀窍:

git reset --soft Y
git reset --hard $(git commit-tree $(git write-tree) -p HEAD -p stable < commit_msg)

不过,您必须先将提交消息写入文件 commit_msg。

于 2012-03-09T05:39:57.580 回答
0

在我看来,最好的方法是将自己置于合并提交之上并撤消顶部提交并修改对先前合并提交的更改。

您将使用以下命令撤消 git-commit:

    git reset HEAD~1

或者

    git reset HEAD^

然后使用:

    git add . && git commit --amend

然后检查结果:

    git log

您应该看到第一个合并提交现在包含两个更改。

此方法可用于所有类型的提交的任何此类需求,或者当

    git rebase -i HEAD~10

... 不能使用。

于 2021-12-21T14:06:35.037 回答