压缩合并的分支

时间:2017-10-31 16:29:17

标签: git rebase squash

我想知道如何压缩所有合并分支的提交: feature | c3 - merge_master - c6 / / \ master | c1 - c2 - c5 ------------- merge_feature - c7

我的目标是拥有这个 master | c1 - c2 - c5 - squash_c3_c6 - c7

我发现git rebase c6 c5 --onto c6允许我重播c3c6c3'c6',但我总是c3和{ {1}}在我的历史中。

我必须在脚本中执行此操作以处理大型存储库(超过6k分支!)因此我无法使用c6

有什么想法吗?

3 个答案:

答案 0 :(得分:0)

你不能(完全)得到你想要的东西,但你得到的东西可能会很好。

在Git中,“壁球”意味着“复制”。更具体地说,“squash merge”使用Git的合并机制,执行合并操作(单词 merge 作为动词),但随后进行普通提交。例如,假设你有这个:

   C3--C6   <-- feature
  /
C1
  \
   C2--C5   <-- master

(请注意,masterfeature之类的分支名称实际上只指向一个提交,即分支的提示提交;而某些提交位于两个分支,例如C1)。然后运行git checkout master && git merge --squash feature

  • 选择C1作为分支共享提交的最后位置;
  • 选择C5作为当前分支的提示master;
  • 选择C6作为feature
  • 的提示

这些是合并过程的输入(“合并”作为动词)。然后Git会:

  • 比较C1C5:这是“我们改变了什么”;
  • 比较C1C6:这是“他们改变了什么”。
然后,Git尝试将两组更改结合起来。如果一切顺利,结果将放在索引和工作树中(“为提交暂存”)。由于您使用--squash自动打开--no-commit,因此Git会在此时停止,而不进行提交,但会构建预加载的提交消息。

您现在可以运行git commit,它会进行普通提交(不是合并提交 - 它使用单词 merge 作为形容词,描述类型承诺)。那个普通的提交就是你想要的:

   C3--C6   <-- feature
  /
C1
  \
   C2--C5--C7_which_is_3_plus_6   <-- master (HEAD)

此时,分支名称feature唯一明智的做法是删除它,放弃原始提交C3C6(最终,或者甚至很快,垃圾收集:删除分支也删除分支的保护它们的reflog。)

C7的日志消息是您想要的,但根据您配置Git的方式,您可以将其默认为组合来自C3C6的现有日志消息(将merge.log设置为true或至少为2的数字,或使用--log

请注意新的提交C7,其中包含原始C3C6中的内容(减去C5已复制的内容)。据推测,这可以使feature完全像这样删除。

不幸的是,那不是你拥有的。您已经可以从feature的提示处获得合并提交,并提供您绘制的图表:

   C3--C4--C6   <-- feature
  /   /
C1--C2--C5   <-- master

featuremaster的合并基础现在不是提交C1,而是提交C2。这是因为当我们从master开始向后工作时,我们会找到提交C5,然后是C2,然后是C1;当我们从feature开始向后工作时,我们会找到C6,然后是C4,然后同时找到C3C2;然后是C1

这意味着C2,而不是C1,是对两个分支上的两个分支提示的“最近”提交。然后在git merge --squash上使用master

  • diff C2 vs C5:我们改变了什么;
  • diff C2 vs C6:他们改变了什么;
  • 合并更改,并因隐含的--no-commit
  • 而停止

然后,您可以进行新的提交C7

   C3--C4--C6   <-- feature
  /   /
C1--C2--C5----C7   <-- master

同样,feature唯一明智的做法就是删除它。结果将是序列...--C1--C2--C5--C7这是与之前相同的提交序列,更重要的是,与C7关联的(源内容)应该与您的树相同只要C4本身不是evil mergeC4不撤消C6的一部分,d就会获得C4

原因是C4包含C3的更改,显然C6包含C6的更改。这意味着当Git运行git diff C2 C6时,它会看到C3C6中的更改:这些是merge-as-a-verb进程的两个输入之一。因此,新C7包含您想要的所有更改。

根据--logmerge.log设置,的内容是自动填充日志消息。但您可以按照自己喜欢的方式编辑C7的日志消息,包括查找早期提交,例如C1并使用git log --pretty=short --no-merges <hash>..feature

答案 1 :(得分:0)

我认为你要找的是git filter-brabch,它会从合并提交中删除第二个父母。

像(未经测试!)

git filter-branch --parent-filter 'read pkey pvalue rest && echo "$pkey $pvalue"' branch_first_commit..branch

(sed或awk可能会更快但是我害怕引用时会出错。它可能在第一次提交时失败)

说明:较旧的历史记录可能存在冲突,因此无法自动重播分支历史记录。但“被压缩的合并”只是与被移除的第二个父母的合并。而且你已经有了合并,所以你只需要删除父母。

答案 2 :(得分:0)

所以我玩git filter-branch --parent-filter它允许我将所有合并的分支提交压平在我的主人身上,很有用,但是松散正确的提交顺序=&gt; C1--C3--C2--C4--C5。结果很好,但历史变得不一致,我期待像C1--C2--C3--C4--C5这样的东西,即便如此,它仍然是压制C3和C4。

@torek感谢您的解释,我更好地理解C2和C3是C4的同等祖先,没有原点概念,如“从功能分支提交”或“从合并分支提交”。并且有“合并提交”但只是提交合并。

我发现有一种方法来编写rebase interactive mode的脚本,就像我可以通过rebase interactive实现我想要的东西,我将编写脚本。

我会随时通知你