221

假设我们有一个master分支。

然后我们创建一个newbranch

git checkout -b newbranch

并做出两个新的提交newbranchcommit1commit2

然后我们切换到master并制作cherry-pick

git checkout master
git cherry-pick hash_of_commit1

调查gitk我们看到commit1及其精选版本具有不同的哈希值,因此从技术上讲,它们是两个不同的提交。

最后我们合并newbranchmaster

git merge newbranch

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

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

4

2 回答 2

150

简短的回答

别担心,Git 会处理的。

长答案

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

合并时,Git 会尝试将两个 HEAD 提交的快照合并到一个新的快照中。如果两个快照中的一部分代码或文件是相同的(即,因为提交已经被精心挑选),Git 不会触及它。

来源

1 Subversion 中的 Skip-Deltas
2 Git 基础
3 Git 对象模型

于 2013-01-23T18:08:56.713 回答
60

在这样的合并之后,您可能会在历史上两次精选提交。

防止这种情况的解决方案我引用了文章,该文章建议具有重复(樱桃采摘)提交的分支在合并之前使用 rebase:

git cherry-pick 之后的 git 合并:避免重复提交

假设我们有 master 分支和一个分支 b:

   o---X   <-- master
    \
     b1---b2---b3---b4   <-- b

现在我们迫切需要 master 中的 b1 和 b3 提交,而不是 b 中剩余的提交。所以我们要做的是检查 master 分支并选择提交 b1 和 b3:

$ git checkout master
$ git cherry-pick "b1's SHA"
$ git cherry-pick "b3's SHA"

结果将是:

   o---X---b1'---b3'   <-- master
    \
     b1---b2---b3---b4   <-- b

假设我们在 master 上再次提交,我们得到:

   o---X---b1'---b3'---Y   <-- master
    \
     b1---b2---b3---b4   <-- b

如果我们现在将分支 b 合并到 master 中:

$ git merge b

我们会得到以下信息:

   o---X---b1'---b3'---Y--- M  <-- master
     \                     /
      b1----b2----b3----b4   <-- b

这意味着 b1 和 b3 引入的更改将在历史记录中出现两次。为了避免这种情况,我们可以变基而不是合并:

$ git rebase master b

这将产生:

   o---X---b1'---b3'---Y   <-- master
                        \
                         b2'---b4'   <-- b

最后:

$ git checkout master
$ git merge b

给我们:

   o---X---b1'---b3'---Y---b2'---b4'   <-- master, b

编辑 大卫柠檬的评论所提出的更正

于 2017-07-07T08:50:34.820 回答