合并提交时如何避免rebase地狱?

时间:2014-07-16 13:28:19

标签: git rebase git-rebase git-rewrite-history git-branch-sculpting

我的git树中出现以下情况:

1 -- 2 -- 3 -- 4 <-- master
      \         \
       5 -- 6 -- 7 -- 8 -- 9 <-- feature

我想从功能中重新定义和压缩所有内容,以便我可以通过添加要素的单个提交来提升主。

由于提交7已经是解决所有冲突的合并,我尝试了以下内容:

git rebase -i -p master

我在这里给出的唯一选择是提交7,8和9.“有道理”,我想,“因为合并已经包括5和6,所以它们可以被丢弃”。我继续在一次提交中压缩7,8和9,我们称之为“789”。 (我知道,我是创意类型。)

在此之后我的树看起来像这样:

1 -- 2 -- 3 -- 4 <-- master
                \
                 5 -- 6 -- 789 <-- feature

同一分支中5和6的存在使我感到困惑,但是再次,因为它们已经包含在7中(现在是789),我可以放弃它们。

所以我再次git rebase -i master,这次我丢弃了5和6。

然而,冲突在这里和那里出现了,所以我放弃了整个事情。

我目前处于该阶段,但我的远程分支尚未更新,因此我可能会重置为原始状态。

在不必手动解决所有合并冲突的情况下,哪些正确的步骤可以让我找到我想要的地方?

2 个答案:

答案 0 :(得分:6)

  

我想从功能中重新定义和压缩所有内容,以便我可以通过添加要素的单个提交来提升主。

这正是git merge--squash选项所做的。来自docs for git merge

  

- 壁球

     

生成工作树和索引状态,好像发生了真正的合并(合并信息除外),但实际上没有提交或移动HEAD,也没有记录$ GIT_DIR / MERGE_HEAD导致下一个git commit命令创建合并提交。 这允许您在当前分支之上创建单个提交,其效果与合并另一个分支(或章鱼的情况下更多)相同。

(强调我的)

用法示例:

git checkout master
git merge feature --squash
git commit

答案 1 :(得分:5)

替代Ajedi32的解决方案

到目前为止,

Ajedi32's solution绝对是最好和最简单的,但我只是想展示一种替代方法,它的工作原理大致相同,为了完整起见。 --squash的{​​{1}}选项基本上复制您正在合并的分支的最终提交的整个状态,因为每个提交代表一个完整的快照 1

您可以通过简单地将currnt工作副本目录树替换为正在合并的分支中的最终提交的工作树来实现相同的效果(这可能仅在功能分支包含所有主分支更改时才有效,我不确定,我还要考虑一下。所以你可以简单地做

git merge

1 另一种思考方式是从基础分支的尖端到合并分支的尖端的所有差异的总和。

替代方案2(这是我的老答案)

好的,有两件事:

  1. 我有一个 适合你的解决方案。
  2. 解释为什么您目前正在做的事情不起作用。
  3. 解决方案? (这实际上会起作用吗?)

    我们会将您的功能分支部分修改。 git rm -rf -- . git checkout feature -- . git add . # Is this necessary? git commit # Verify that the current working copy state # is identical to the feature branch's git diff feature --preserve-merges的{​​{1}}标志效果最佳,当那些合并提交的父母不会包含您在其他分支机构中提交的提交内容时,就像我&#39我相信你已经见过了。

    为了简洁起见,我将省略关于以下命令的语法的一些解释,因为您可以在文档中查看:

    1. 首先,制作一个备份分支以防万一,可怕的错误,我们最终需要硬重置回你的功能分支原始状态:

      git rebase
    2. 接下来,我们将5和6压缩,然后将它们挑选到git branch backup feature (您可以将它们重新加入master,但因为我们只是樱桃采摘一次提交,rebase对此有点过分杀人):

      master

      现在我们已经将5和6压扁了,我们想要将它挑选到git checkout -b temp 6 git reset --soft HEAD^ git commit -m "Enter your squash commit message here" 。由于您提到合并提交master解决了冲突,这意味着挑选新的压缩提交(让我们称之为7)也会导致冲突。但是,由于您已经在S中解决了这些冲突,我们能够将这些解决方案复制到新挑选的提交中(尽管我是不是100%肯定这个):

      7
    3. 接下来,我们将第8步和第9步重新绑定。我们跳过7,因为它只是在提交点6处向git checkout master git cherry-pick S # If no conflicts, then great! # Otherwise, completely delete the conflicted working directory tree, # and replace it with the directory tree from commit 7 instead: git rm -rf -- . git checkout 7 -- . git add . # Is this necessary? git cherry-pick --continue # When the cherry-pick is done, compare master to 7 and # verify that there are no differences git diff 7 分支表示master的同步事件;但是,因为在feature之上挑选/重新定位5和6会产生与合并相同的最终状态,所以不再需要合并提交。

      master
    4. 应该是它(我认为)。如果它不起作用,那么您可以随时使用

      重新设置功能分支
      git rebase --onto master 7 feature
      
      # Squash 8 and 9 into S (which should be the tip of master).
      # You might have been able to do this in the above step too,
      # but I don't have time to double-check, so this will also work:
      git reset --soft master
      git commit --amend --no-edit
      
      # Once again, verify that the final result
      # matches that original of the feature branch:
      git diff backup
      

      解释为什么你之前没做的事情

      好的,所以完整的解释会花一些时间来写。如果我以后有时间,我会回到这个答案并写出所有细节。但是,在我走之前,我只想指出:

      • Rebase 将提交重新应用为修补程序。当您从rebase中省略提交时,该提交中引入的更改将从所有后续的后代提交中丢失(它们不会保留在后代中)。

      文件的必要链接