如何使用cherry-pick和revert?

9

我正在尝试理解在数学集合操作中,merge和rebase的含义。

在下文中,“-”表示diff(类似于在数学中进行集合差分,但“A-B”的意思是属于A而不属于B,减去B中不属于A的元素),“+”表示patch(即在数学中进行不相交并集。我以前没有使用过patch,所以不确定)。

以下内容来自《使用Git进行版本控制,作者为Loeliger,第2版》

  1. 命令git cherry-pick commit将指定提交引入当前分支中的更改。它会引入一个新的、独立的提交。严格来说,使用git cherry-pick不会修改存储库中现有的历史记录;相反,它会添加到历史记录中。

    enter image description here

    enter image description here

    是否正确,F' = (F-B) + Z?

  2. 命令git revert commit与git cherry-pick commit命令基本相似,但有一个重要的区别:它应用给定提交的相反操作。因此,该命令用于引入撤销给定提交效果的新提交。

    enter image description here

    enter image description here

    是否正确,D' = G - D?


你的问题很好,你应该观看这个系列:http://shop.oreilly.com/product/0636920024774.do,它会教给你很多东西。 - CodeWizard
3个回答

9

挑选指定提交记录(cherry-pick)

F' = (F-B) + Z,这个公式是正确的吗?

不正确,这样会将CDE所做的更改也一并引入。

git-cherry-pick通过隔离要挑选的提交记录中的唯一更改内容(即,本例中的F-E,忽略其他祖先,包括合并基础),并将它们应用到目标上来实现挑选。

这并不是通过补丁应用来完成的,而是通过使用三方合并算法 - 要挑选的提交记录的父级将被用作公共祖先,要挑选的提交记录将成为一个合并的一侧,目标将成为另一侧。最终产生的结果是已包含在挑选的提交记录和目标中的更改。

例如,如果E是要挑选的提交记录的父级,则其内容(作为公共祖先)应为:

Line 1
Line 2
Line 3
Line 4
Line 5

例如,如果要挑选的提交是F,它的内容如下:
Line 1
Line 2
Line Three
Line 4
Line 5

而 cherry-pick Z 的目标是:

LINE 1
Line 2
Line 3
Line 4
Line 5!

三路合并的结果如下(带有每行来自哪里的注释):

LINE 1
Line 2
Line Three
Line 4
Line 5!

还原

D' = G - D,这个说法正确吗?

大致上是的。唯一属于D的更改已从G中移除。与git-cherry-pick类似,git-revert使用三方合并实现,但这次要将被还原的提交视为公共祖先,一边是当前提交,另一边是要还原的提交的父提交。

这意味着,当一行在要还原的提交和当前提交之间相同时,将选择其父提交中的行。

如果要还原的提交D的内容充当公共祖先,并且其内容为:

Line 1
Line 2
Line THREE
Line 4
Line FIVE

CD 的父级)的内容如下:

Line 1
Line 2
Line 3
Line 4
Line 5

G的内容已进一步更改,现在它的内容如下:

Line One
Line 2
Line THREE
Line 4
Line FIVE

那么三方合并的结果将会是:
Line One
Line 2
Line 3
Line 4
Line 5

从父C和目标G中获取唯一行的结果。

合并提交

正如torek所指出的那样(如下所示),由于这些机制都涉及使用父提交,因此当存在多个父提交时,它们将会失效。 (即,所讨论的提交是合并提交并具有多个父提交)。在这种情况下,您需要指定要考虑哪个父提交(使用-m标志)。

冲突

当然,这两种机制都可能导致冲突。例如,如果当前冲突已经进一步更改,则必须解决冲突。例如,在上面的还原示例中,如果随后的提交也更改了第5行,则G实际上应该是:

Line One
Line 2
Line THREE
Line 4
LINE FIVE!

这会导致冲突。合并后的工作目录将如下:

Line One
Line 2
Line 3
Line 4
<<<<<<<
LINE FIVE!
=======
Line 5
>>>>>>>

您需要决定是要原始更改 (第5行) 还是最新更改 (第五行!)。


1
在这里值得补充的是,除非你告诉 Git 使用哪个多个父提交中的一个作为(假定的单一)前任节点,否则你不能挑选或还原合并提交。当选择 E 或还原 D 时,你不需要这样做,因为它们已经只有一个前任节点。 - torek
@torek 非常正确。我本来希望这个区别能够不被注意到。:) 我更新了我的答案,试图澄清这一点。 - Edward Thomson
1
这是一个真正棒极了的答案! - Samuel
但是如果在提交D中添加了第6行呢?由于提交G也继承了该行,而第6行不是在提交C中找到的相同行,那么它会被还原吗?当挑选提交F时,同样的情况也会出现,如果在共同祖先E中添加了某些第6行。 - Ruraloville

3

如下所示,很容易理解:

cherry-pick

选择任何分支或松散提交的哪些提交,并将其选定并放置在当前分支中,换句话说 - 从存储库中获取任何提交并将其带到我的分支中。


revert

撤消任何提交。它将通过撤销提交中所做的任何更改来“还原”它们,如果您知道什么是补丁,则可以将其视为在补丁中翻转符号-变为+反之亦然。您的更改正在“还原”,并且更改正在被撤消。

git revert命令撤消了已提交的快照。

但是,它不会从项目历史记录中删除提交,而是找出如何撤消提交引入的更改,并追加一个包含结果内容的新提交。

这样做可以防止Git丢失历史记录,这对您的修订历史和可靠的协作很重要。


F' = (F-B) + Z是否正确?

这意味着现在在较低分支中,还包含创建在提交F中的补丁,您的较低分支包含其更改+提交F中所做的更改(只有这些更改,除了F没有其他提交)。


D' = G-D是否正确?

不完全正确 - 这意味着现在您拥有提交D,并在几个提交之后进行了撤消,存储库中仍然存在2个提交,但代码将保持不变(2个单独提交上的更改和撤消)。


谢谢。我仍然不清楚F'和D'包含什么以及它们是如何从现有的提交中创建的。(1) 在cherry-pick操作中,F和Z的共同祖先,例如B,是否参与其中?(2) 在还原操作中,G如何参与其中? - Tim
回答你的两个问题:D' 是 D 的“撤销”操作,意味着在 D 中进行的任何更改现在都被撤消了 - 你有两个提交。一个是原始的,另一个是这个提交的撤销。你的代码回到了在提交 D 之前的状态,但你有两个提交。D=更改,D'=撤消更改。现在对你来说有意义了吗? - CodeWizard
在还原操作中,G是如何参与的?G并没有进化,它是图10-8中的最后一次提交,D'只是在之后提交的(图10-9)。 - CodeWizard
谢谢。但还是不行。 - Tim
你还有什么不理解的吗? - CodeWizard
显示剩余2条评论

2
在Git 2.29(2020年第四季度)中解决了类似的情况。
查看 提交 087c616, 提交 409f066, 提交 5065ce4(2020年9月20日)由 brian m. carlson (bk2204) 提交。
(由Junio C Hamano -- gitster --合并于提交 c5a8f1e,2020年9月29日) 文档:解释为什么在合并时不总是应用还原操作。

签名:brian m. carlson

常见情况是用户将更改应用于一个分支并将其挑选到另一个分支中,然后稍后在第一个分支中撤销更改。这会导致当两个分支合并时出现更改存在的情况,这让许多用户感到困惑。
我们已经有了关于 git mergeman)如何工作的文档,但从频繁提问的情况来看,很明显这很难理解。 我们也没有向用户解释,在这种情况下最好使用 rebase,它会实现他们的意图。
让我们在常见问题解答中添加一条条目,告诉用户发生了什么,并建议他们在这里使用 rebase。
现在,gitfaq 在其手册页面中包括了上述内容。
如果我在两个分支上进行更改,但在其中一个分支上撤销了更改,为什么合并这些分支会包括更改?
默认情况下,当 Git 进行合并时,它使用一种称为递归策略的策略,该策略执行一种复杂的三方合并。在这种情况下,当 Git 执行合并时,它考虑恰好三个点:这两个头和第三个点,称为合并基础,通常是这些提交的共同祖先。Git 根本不考虑这些分支上发生的历史或个别提交。
因此,如果两侧都有更改并且一侧已经撤销了该更改,则结果是包含更改。这是因为代码在一侧发生了变化,而在另一侧没有净变化,在这种情况下,Git 采用了更改。
如果这对您造成问题,您可以选择重新应用基底(rebase),将具有撤销的分支重新应用到另一个分支上。在这种情况下,重新应用基底将撤销更改,因为重新应用基底应用每个单独的提交,包括撤销。请注意,重新应用基底会重写历史记录,因此除非您确定自己对此感到舒适,否则应避免重新应用基底到已发布的分支上。有关更多详细信息,请参见 git rebase 中的“注意事项”部分。

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