假设我们有一个主分支。

然后我们创建一个新分支

git checkout -b newbranch

并对newbranch进行两次新的提交:commit1和commit2

然后我们切换到master,进行精选

git checkout master
git cherry-pick hash_of_commit1

查看gitk,我们看到commit1和它的精选版本有不同的哈希值,所以从技术上讲,它们是两个不同的提交。

最后我们将newbranch合并到master:

git merge newbranch

可以看到,这两个具有不同哈希值的提交合并起来没有问题,尽管它们意味着应该应用两次相同的更改,因此其中一个应该失败。

git在合并时是否真的对提交的内容进行了智能分析,并决定不应该应用两次更改,或者在内部将这些提交标记为链接在一起?


简短的回答

别担心,Git会处理的。

长回答

与SVN1不同,Git不以delta格式存储提交,而是基于快照的2,3。虽然SVN会天真地尝试将每个合并提交作为一个补丁应用(由于您所描述的确切原因而失败),但Git通常能够处理这种情况。

合并时,Git会尝试将两个HEAD提交的快照合并到一个新的快照中。如果在两个快照中有一部分代码或文件是相同的(也就是说,因为提交已经被选中了),Git不会处理它。

来源

1在Subversion中跳过delta 2 Git基础 3 Git对象模型


在这样的合并之后,历史记录中可能会有两次精心挑选的提交。

防止这种情况的解决方案,我引用了一篇文章,这篇文章建议在合并之前使用rebase:

git merge after git cherry-pick: avoiding duplicate commits Imagine we have the master branch and a branch b: o---X <-- master \ b1---b2---b3---b4 <-- b Now we urgently need the commits b1 and b3 in master, but not the remaining commits in b. So what we do is checkout the master branch and cherry-pick commits b1 and b3: $ git checkout master $ git cherry-pick "b1's SHA" $ git cherry-pick "b3's SHA" The result would be: o---X---b1'---b3' <-- master \ b1---b2---b3---b4 <-- b Let’s say we do another commit on master and we get: o---X---b1'---b3'---Y <-- master \ b1---b2---b3---b4 <-- b If we would now merge branch b into master: $ git merge b We would get the following: o---X---b1'---b3'---Y--- M <-- master \ / b1----b2----b3----b4 <-- b That means the changes introduced by b1 and b3 would appear twice in the history. To avoid that we can rebase instead of merge: $ git rebase master b Which would yield: o---X---b1'---b3'---Y <-- master \ b2'---b4' <-- b Finally: $ git checkout master $ git merge b gives us: o---X---b1'---b3'---Y---b2'---b4' <-- master, b

编辑 David Lemon评论中的修正