我正在开发我的功能分支。开发完成后,我将所有提交的代码移动到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)
我如何合并这些分支?
答案 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-commit
到A
后的任何内容的差异包括所有G
更改,以及从D-E-F-G
到A
之后或之后的差异还包括所有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