ChatGPT解决这个技术问题 Extra ChatGPT

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

假设我们有一个 master 分支。

然后我们创建一个 newbranch

git checkout -b newbranch

并对 newbranch 进行两次新的提交:commit1commit2

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

git checkout master
git cherry-pick hash_of_commit1

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

最后我们将 newbranch 合并到 master 中:

git merge newbranch

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

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


P
Paul

简短的回答

别担心,Git 会处理的。

长答案

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

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

来源

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


实际上,我会说 you should worry about merging 并且“git 会处理它”不是一个好的经验法则。
事实上,在某些情况下,合并会导致内容重复。 Git 有时会处理它,但有时不会。
这是非常错误的。 Got 几乎以所有可转换的形式存储文件文件。如果我没记错的话 SVN 用于存储快照。
@he_the_great,不。 SVN 的 skip-delta 存储格式(!= 快照)有据可查 in the manual。我真的不明白你所说的 condevable 是什么意思。我不是母语人士,但我很确定这不是一个真实的词。
@he_the_great 但即使是打包文件,文件的任何给定哈希都会产生完整的文件。是的,它使用增量进行压缩,但它不是提交中更改的增量,而是文件哈希之间的增量。就提交对象而言,它正在引用一棵树,该树正在引用完整文件的哈希值。在引擎盖下数据被压缩不会影响 git 的工作方式。就提交而言,Git 存储完整的文件,据我了解,SVN 存储提交的增量。
e
ephemerr

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

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

git cherry-pick 之后的 git merge:避免重复提交假设我们有 master 分支和一个分支 b:o---X <-- master \ b1---b2---b3---b4 <-- b 现在我们迫切需要 master 中的提交 b1 和 b3,而不是 b 中的剩余提交。所以我们要做的是检查 master 分支和 cherry-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 引入的更改将在历史记录中出现两次。为了避免这种情况,我们可以 rebase 而不是合并: $ 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

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


关于变基的好提示!它会自动“跳过”所有精心挑选的提交。
老实说,这听起来好得令人难以置信,我必须亲眼看到它。也 rebase 修改提交,你的最后一个时间线应该是 ---Y---b2'---b4'
完美运行。如果您不想在历史上进行两次精心挑选的提交,这将非常有帮助。
是否应该注意,虽然 rebase 很漂亮,但使用它的危险是从旧 b 创建的任何叉子或分支都将不同步,用户可能需要求助于 git reset --hard 和 git 之类的东西推-f?
@JHH 这就是我们在这里重新设置本地分支的原因