关于Git的合并与变基

10

图片描述

图片描述

图片描述

上面是合并和变基的结果。

我的问题是,在最终状态下,C5C3' 是否相同?

或者说,git rebase 相当于 git merge + 删除 C3 吗?

3个回答

23

这个示例并不是很好,因为它只考虑了一个提交(合并或变基),给你留下了结果提交相似的印象。通常情况下,变基会添加多个提交,而合并最多只添加一个提交(快进式合并则不添加任何提交)。

此外,只要没有需要解决的冲突,或者您以相同的方式解决这些冲突,C3'和C5的最终内容将是相同的,但它们仍然是不同的提交(由于C3'和C5有不同的父级,它们还具有不同的哈希值,在下面的插图中更为明显)。相应地,每个提交的记录历史也是不同的。请注意,对于变基,历史是线性的,而对于合并,则是格子状结构

考虑当合并/变基多个提交时的情况,如Mark Lodato的"A Visual Git Reference"所示。您会发现最终结果非常不同。

git checkout master
git merge other # update master with tip of branch 'other' changes

git merge other

你只需要:

  • 当前提交(由于你在主分支上,所以是ed489)
  • 另一个分支的最新提交(它表示在“other”分支创建时整个仓库的内容快照,而不是增量)
  • 它们的共同祖先(b325c),然后执行三方合并

关于此图中工作目录和暂存区的含义,请注意箭头指向三方合并,然后指向工作目录和暂存区。工作目录代表你所看到的所有文件(在你的硬盘上),其中一些因为三方合并而更改。暂存区保存了三方合并更改的文件,然后用于创建新提交(f8bc5)。

这与rebase非常不同,rebase旨在将分支的每个提交都重新应用到目标分支之上:

git checkout topic # this time we are on topic
git rebase master  # means: recreate every topic commits on top of master
                           at the end, we are still on (new) 'topic' branch

git rebase master

以上命令获取在'topic'中存在但在master不存在的所有提交(即169a62c33a),将它们重新应用到master,然后将分支头移动到新的结尾。请注意,如果旧的提交不再被引用,它们将会被[最终]垃圾回收。

Rebasing使用工作目录和暂存区,当它重新应用提交时(将更改应用于工作目录、将更改添加到暂存区、提交已暂存的更改,重复)。完成所有操作后,重新定位分支的头到新提交中的最后一个(f7e63)。


另外还有2个不同之处:


我现在有这个疑问,无论你是用 git merge 还是 git rebase,当你执行 git push 时,最终的结果是否相同?不过可能会丢失提交信息。 - asker
我不理解第一张图中的“工作目录”和“暂存区”的链接。 - asker
@VonC:在git mergegit rebase之后,代码的最终状态是否相同?唯一的区别是提交对象不同吗? - TheOneTeam
那么 Git 完全不处理这种情况吗?虽然很不可能,但仍有可能发生。 - asker
1
@kevinmajor1 git rebase 有其用途:请参见 https://dev59.com/qHRB5IYBdhLWcg3w9Lvn#457988 和 https://dev59.com/BXRA5IYBdhLWcg3w2xwI?lq=1 - VonC
显示剩余27条评论

1

不会。C5和C3'将有不同的父提交,这意味着它们本身将是不同的。

如果您问的是C5和C3'引用的根treeish是否相同,则是(假设任何冲突都以相同的方式解决)。换句话说,“包含”在两个提交中的文件的树将是相同的。


不是完全相同,但最终的树形结构应该是相同的,是的。 - cdhowie
你能详细说明一下吗?我认为没有必要进行中间提交,rebase 等同于合并 + 将分支指向结果提交。 - asker
你没有理解我的意思。重新设置基础和合并产生相同提交的说法是不正确的,而且在每种情况下,合并和删除父引用所产生的结果也不会与重新设置基础完全相同。重新设置基础和合并将产生具有相同文件树的提交,但这些提交不会完全相同。 - cdhowie
你有更好的图表来说明吗? - asker
请查看此图表:http://i51.tinypic.com/2h57mm9.png -- 请注意,虽然合并和变基提交将具有相同的文件树,但提交本身将非常不同。 - cdhowie
显示剩余10条评论

0

如果您只查看提交的内容(即不考虑它们的父级),那么C5和C3'都包含相同的内容(假设没有合并冲突或其他需要手动更改的内容)。因此,某人可以将其视为与删除C3相同,对于“删除C3”的定义而言。但是在Git中,无法删除任何提交(所有提交都是不可变的),因此从树中删除提交的操作对于Git来说是未定义的。


不会。它会创建一个新的提交。旧的提交不会丢失,您可以使用 git reflog(或者如果您记得提交哈希,则使用 git checkout)来找回它。唯一删除提交的命令是 git gc - Esko Luontola
它不会删除从分支可到达的提交,并且无法更改任何提交的父级。 - Esko Luontola
好的,让我们将“删除 C3”定义为“将当前指向 C3 的分支指向最终提交”。根据这个定义,git rebase 等于 git merge + 删除 C3 吗? - asker
在这种情况下,肯定不会使用 git commit -a --amend。您正在尝试保留树形结构,因此添加工作目录中的所有更改并不是您想要的。但是,--amend 也无法让您更改父列表。您需要执行 git reset --soft HEAD^; git commit -c HEAD@{1} 来删除其他父提交。 - Jan Hudec
将当前指向C3的分支指向最终提交:git branch -f experiment master或者 git reset --hard master,这不会添加/删除/修改任何提交。而git rebase master相当于git checkout C5; git cherry-pick C3; git branch -f experiment - Esko Luontola
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接