Git将一个分支转移到另一个具有一个提交历史的分支

时间:2017-01-17 13:38:39

标签: git branch git-branch git-merge

我正在开发我的功能分支。开发完成后,我将所有提交的代码移动到master分支。

但具体点是在此操作之后,master分支应该只有一个提交历史记录。

我会尝试用树来解释。

--- BRANCH TREES WITHOUT MERGE OPERATION ---

A--B--C  (master-branch)
 \    ^--- After the merge operation commit will come after this point.
  \
   D--E--F--G  (feature-branch)


--- AFTER THE MERGE OPERATION EXPECTED BRANCH TREES ---

A--B--C--(H)  (master-branch)
 \        ^--- 'H' is the commit of all feature branch merge. 
  \             Include commits D, E, F, G.  
   \            This should have all source but, will shown one commit   message.
    \
     D--E--F--G  (feature-branch)

我如何合并这些分支?

3 个答案:

答案 0 :(得分:2)

我认为你想做的是'壁球提交'功能。

我只是制作原始分支的副本,然后以交互方式对其进行重新定义,以便我可以压缩提交。

答案 1 :(得分:1)

Git将此称为“壁球合并”,您可以通过运行git merge --squash来获取它。与Git中的所有新提交一样,新提交将添加到当前分支,因此在这种情况下,您将首先进入master-branch,然后运行git merge --squash feature-branch

注意事项

有一些重要的事情需要了解。特别是,与结果提交相关联的(源或工作树)是通过合并(动词:动作,“合并”)获得的,它是不是合并提交(合并的形容词或名词形式)。

请记住,在Git中,提交有两个功能:

  • 他们 历史。

  • 他们包含工作树快照(加上一些元数据:谁进行了提交,何时以及日志消息)。

正常git merge other通过运行git merge-base --all HEAD other 1 然后找到合并基础提交:

  • 组合两组差异:从基础到HEAD的差异,相当于“你改变了什么”,加上从基础到other的差异,相当于“它们是什么”改变”。如果您更改了文件one.txt并更改了文件two.txt,则Git会同时进行更改,即您的one.txt及其two.txt。如果您两个更改了文件three.txt,Git会尝试查看您的更改是否重叠,或者是完全重复,还是完全独立。如果它们重叠,Git会给你一个合并冲突。如果它们是独立的,Git会进行两项更改。如果它们完全相同,Git会获取一份更改。生成的three.txt三向合并的输出

  • 进行历史记录的新提交:“此提交是合并提交,将第一个父HEAD和第二个父other的工作合并在一起”

git merge --squash其他人仍然执行合并操作,包括任何所需的三向合并。然后 - 没有明显的原因 2 -omits git commit步骤让你运行git commit,当你时运行git commit结果是合并提交:它的历史记录说“此提交是普通提交,其唯一父提交是HEAD”。换句话说,它的提交历史好像是你自己完成了other的所有更改,除了任何重复的更改。

这就是你要求的,但它也是一个陷阱。如果您稍后决定需要在feature-branch上开发更多并再次合并,Git将没有显示现有合并的历史记录,并且不会知道它可以启动新的合并使用先前合并的结果进行处理。

这最终意味着当您打算在挤压合并后立即(或至少很快)删除功能分支时,壁球合并效果最佳:

A---B----C      <-- main
 \
  D--E--F--G    <-- feature

(现在git checkout main && git merge --squash feature && git commit && git branch -D feature

A---B----C--H   <-- main
 \
  D--E--F--G    [abandoned]

这样,您就无法返回并添加更多使用G链的D-E-F-G之后的提交,以后需要再次合并。如果您确实返回并进行了此类提交,并再次合并,则合并基础提交将为A,而不是G,并且Git更可能错误合并,意外地重复某些{ {1}}更改。 3

1 如果D-E-F-G找到多个合并库,则行为取决于合并策略。如果找到 no 合并库,则旧版本的Git和新版本的Git中的行为会有所不同:较新的Gits会因为拒绝合并不相关的历史记录而停止。

2 定期合并将停止,但仅在git merge-base --all特别请求时才会停止。随后的--no-commit将进行合并提交,即双父提交。所以git commit没有理由像你也指定git merge --squash那样行事:如果你真的希望它停止,你可以运行--no-commit。 (这可能是最早的Git脚本的延续。)

3 Git的合并算法很难只获取每个更改的一个副本,但通常只能获取一个更改副本。也就是说,从git merge --squash --no-commitA后的任何内容的差异包括所有G更改,以及从D-E-F-GA之后或之后的差异包括所有H更改:但是“获取更改的一个副本”是意味着来处理。

问题在于,当你过分强调这个算法时,它会失败。通常,效果是一个巨大的合并冲突,您必须手动解决。

答案 2 :(得分:1)

其中一种方法:

git checkout -b tmp feature-branch
git reset A --soft
git commit -m "feature"
#a new commit X is created. It's a squash of D, E, F, G
git checkout master-branch
git cherry-pick X
git branch -D tmp