摘樱桃后git如何合并?


190

假设我们有一个master分支。

然后我们创建一个 newbranch

git checkout -b newbranch

并向以下两个新提交newbranchcommit1commit2

然后我们切换到主人 cherry-pick

git checkout master
git cherry-pick hash_of_commit1

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

最后,我们合并newbranchmaster

git merge newbranch

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

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

Answers:


131

简短答案

不用担心,Git会处理的。

长答案

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

合并时,Git将尝试将两个HEAD提交的快照合并到一个新的快照中。如果两个快照中的代码或文件的一部分相同(即,因为已经选择了提交),则Git不会使用它。

资料来源

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


40
实际上,我想说的是您应该担心合并,并且“ git会处理它”并不是一个好的经验法则。
cregox

4
实际上,在某些情况下,合并可能导致重复的内容。Git有时会处理它,但有时却不会。
donquixote 2013年

这是非常错误的。几乎以所有可配置的形式存储文件文件。如果我没记错的话,SVN用来存储快照。
he_the_great

2
@he_the_great,不。SVN的skip-delta存储格式(!=快照)在手册中有详细记录。而且我真的无法理解可构想的意思。我不是母语人士,但我敢肯定这不是一个真实的词。
赫尔姆伯特

2
@he_the_great但是,即使在打包文件时,文件的任何给定哈希也将导致完整文件。是的,它使用增量进行压缩,但这不是提交更改的增量,而是文件散列之间的增量。就提交对象而言,它引用的树是引用完整文件的哈希值。在后台对数据进行压缩不会影响git的工作方式。Git就提交而言存储完整的文件,据我所知,SVN存储提交的增量。
彼得·奥尔森

43

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

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

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

想象我们有一个master分支和一个b分支:

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

现在我们迫切需要master中的提交b1和b3,而不是b中的其余提交。因此,我们要做的是检出master分支,然后执行pick-pick提交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

编辑 大卫·柠檬的评论所建议的更正


1
关于变基的好提示!它将自动“跳过”所有精心挑选的提交。
iTake

2
老实说,听起来实在太好了,我必须亲眼看一下。还要重新修改提交,您的最后一个时间表应该是---Y---b2'---b4'
David Lemon '18

完美运作。如果您不想在历史上两次经历精心挑选的提交,这将非常有帮助。
user2350644 '19

1
不应该指出的是,虽然变基很漂亮,但是使用它的危险在于,从旧b创建的所有fork或分支将不同步,用户可能需要诉诸git reset --hard和git之类的东西。推-f?
JHH

1
@JHH这就是为什么我们在这里
重新建立
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.