Git同内容分支rebase冲突但cherry-pick无冲突原因咨询
你认为rebase和cherry-pick底层逻辑一致是正确的,二者确实都是重新应用提交补丁,但你两次操作的补丁集合完全不一样,这是出现差异的根本原因。
1. rebase的默认操作逻辑
rebase默认会找到当前分支(rename_wellcome)和目标分支(development_v2)的最近共同祖先,也就是提交历史里的c4c7b06 created readme,然后把当前分支上所有在共同祖先之后的提交,全部按顺序一个个应用到目标分支上。
你的rename_wellcome是从development分支切出来的,所以共同祖先之后的提交不止你自己写的c41d4a9 renamed the wellcome to welcome,还包含development分支上的所有原子提交:重命名contacts页面的91acf76、更新contacts内容的84dc37b、登录功能的两个提交等等。
而development_v2(对应production分支)的提交历史是直接cherry-pick的development合并提交,只有最终合并结果,没有这些中间原子提交的记录。当rebase尝试应用91acf76这个提交(操作是把contacts.html重命名为about-us.html)时,Git会检查当前HEAD(也就是development_v2的最新状态):contacts.html早就已经被合并提交改成about-us.html了,源文件不存在,自然就触发了rename/delete冲突。
2. cherry-pick的操作逻辑
你执行cherry-pick的时候,只指定了c41d4a9这一个提交,Git只会应用这一个提交的补丁:把wellcome.html重命名为welcome.html。这个操作和contacts页面的修改完全无关,development_v2上也存在wellcome.html这个文件,所以整个过程没有任何冲突。
满足以下两个条件就会触发这类冲突:
- 你要rebase的源分支的历史包含大量中间原子提交,而目标分支的历史是这些原子提交的合并结果(比如cherry-pick合并提交、squash合并生成的提交),两者只有最终代码内容一致,提交历史没有对应关系
- 这些中间原子提交包含文件重命名、删除类操作,目标分支上已经完成了这些操作,导致Git应用中间提交时找不到对应的操作源文件
如果你只想把当前任务分支上自己写的提交rebase到新分支,不需要带上之前development的历史提交,可以指定rebase的范围:
git rebase --onto development_v2 development rename_wellcome
这个命令的含义是:把rename_wellcome分支上比development分支多的提交(也就是只有你自己的任务提交),应用到development_v2上,效果和你手动cherry-pick完全一致,不会触发冲突。
内容的提问来源于stack exchange,提问作者martlin

