樱桃挑选工作后git如何合并?

Pau*_*aul 180 git git-merge cherry-pick

让我们假设我们有一个master分支.

然后我们创建一个 newbranch

git checkout -b newbranch
Run Code Online (Sandbox Code Playgroud)

和两个新提交到newbranch:commit1commit2

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

git checkout master
git cherry-pick hash_of_commit1
Run Code Online (Sandbox Code Playgroud)

展望gitk我们看到commit1和樱桃采摘的版本有不同的哈希值,所以在技术上它们是两个不同的提交.

最后我们合并newbranchmaster:

git merge newbranch
Run Code Online (Sandbox Code Playgroud)

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

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

hel*_*ert 124

简短的回答

别担心,Git会处理它.

答案很长

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

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

来源

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

  • 实际上,我会说[你应该担心合并](http://stackoverflow.com/questions/20380013/git-merge-strategies-spaces-make-default-shows-no-conflict-and-bring-unexpected)并且"git会处理它"并不是一个好的经验法则. (39认同)
  • 实际上,合并CAN在某些情况下会导致重复内容.Git有时会处理它,但有时却没有. (4认同)
  • @he_the_great,没有.SVN的跳过 - 增量存储格式(!=快照)已在[手册]中详细记录(http://svn.apache.org/repos/asf/subversion/trunk/notes/skip-deltas).我真的不明白你的意思*condevable*.我不是母语人士,但我很确定这不是一个真实的词. (2认同)
  • @he_the_great但即使是packfiles文件的任何给定哈希都会产生完整文件.是的,它使用增量进行压缩,但它不是提交中更改的增量,而是文件哈希之间的增量.就提交对象而言,它引用的是引用完整文件的哈希值的树.在数据库被压缩的情况下,这不会影响git的工作方式.就提交而言,Git存储完整的文件,SVN根据我的理解存储提交的增量. (2认同)

eph*_*err 38

在这样的合并之后,你可能会在历史上两次提交樱桃.

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

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

想象一下,我们有主分支和分支b:

   o---X   <-- master
    \
     b1---b2---b3---b4   <-- b
Run Code Online (Sandbox Code Playgroud)

现在我们迫切需要master中的提交b1和b3,而不是b中的剩余提交.所以我们做的是检查master分支和cherry-pick提交b1和b3:

$ git checkout master
$ git cherry-pick "b1's SHA"
$ git cherry-pick "b3's SHA"
Run Code Online (Sandbox Code Playgroud)

结果将是:

   o---X---b1'---b3'   <-- master
    \
     b1---b2---b3---b4   <-- b
Run Code Online (Sandbox Code Playgroud)

假设我们在master上做了另一个提交,我们得到:

   o---X---b1'---b3'---Y   <-- master
    \
     b1---b2---b3---b4   <-- b
Run Code Online (Sandbox Code Playgroud)

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

$ git merge b
Run Code Online (Sandbox Code Playgroud)

我们会得到以下内容:

   o---X---b1'---b3'---Y--- M  <-- master
     \                     /
      b1----b2----b3----b4   <-- b
Run Code Online (Sandbox Code Playgroud)

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

$ git rebase master b
Run Code Online (Sandbox Code Playgroud)

哪个会产生:

   o---X---b1'---b3'---Y   <-- master
                        \
                         b2'---b4'   <-- b
Run Code Online (Sandbox Code Playgroud)

最后:

$ git checkout master
$ git merge b
Run Code Online (Sandbox Code Playgroud)

给我们:

   o---X---b1'---b3'---Y---b2'---b4'   <-- master, b
Run Code Online (Sandbox Code Playgroud)

由David Lemon评论的编辑更正

  • 老实说,这听起来真是太好了,我必须亲眼所见。还需要重新修改提交的基准,您的最后一个时间轴应该是“ --- Y --- b2” --- b4” (2认同)
  • @JHH 这就是我们在这里重新设置本地分支的原因 (2认同)