git 在cherry-pick工作后git如何合并?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14486122/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 15:19:09  来源:igfitidea点击:

How does git merge after cherry-pick work?

gitgit-mergecherry-pick

提问by Paul

Let's imagine that we have a masterbranch.

假设我们有一个master分支。

Then we create a newbranch

然后我们创建一个 newbranch

git checkout -b newbranch

and make two new commits to newbranch: commit1and commit2

并进行两次新的提交newbranchcommit1commit2

Then we switch to master and make cherry-pick

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

git checkout master
git cherry-pick hash_of_commit1

Looking into gitkwe see that commit1and its cherry-picked version have different hashes, so technically they are two different commits.

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

Finally we merge newbranchinto master:

最后我们合并newbranchmaster

git merge newbranch

and see that these two commits with different hashes were merged without problems although they imply that the same changes should be applied twice, so one of them should fail.

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

Does git really do a smart analysis of commit's content while merging and decide that changes shouldn't be applied twice or these commits are marked internally as linked together?

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

采纳答案by helmbert

Short answer

简答

Don't worry, Git will handle it.

别担心,Git 会处理的。

Long answer

长答案

Unlike e.g. SVN1, Git does not store commits in delta format, but is snapshot-based2,3. While SVN would naively try to apply each merged commit as a patch (and fail, for the exact reason you described), Git is generally able to handle this scenario.

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

When merging, Git will try to combine the snapshots of both HEAD commits into a new snapshot. If a portion of code or a file is identical in both snapshots (i.e. because a commit was already cherry-picked), Git won't touch it.

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

Sources

来源

1Skip-Deltas in Subversion
2Git Basics
3The Git object model

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

回答by ephemerr

After such merge you may have cherry-picked commits in history twice.

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

Solution to prevent this I quote from articlewhich recommends for branches with duplicate(cherry-picked) commits use rebase before merge:

防止这种情况的解决方案我从文章中引用,该文章建议具有重复(樱桃挑选)提交的分支在合并之前使用 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

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

EDITCorrections supposed by David Lemon's comment

编辑David Lemon 的评论所认为的更正