Git cherry pick vs rebase

时间:2012-08-06 21:07:58

标签: git version-control

我最近开始与Git合作。

在线浏览git book(Git book)我在“Git Rebase”部分找到了以下内容:

  

使用rebase命令,您可以进行所有更改   在一个分支上提交并在另一个分支上重播它们。

(引自:http://git-scm.com/book/en/Git-Branching-Rebasing

我认为这是git cherry-pick 的确切定义(在当前检出的分支上重新应用提交或一组提交对象。

两者有什么区别?

6 个答案:

答案 0 :(得分:141)

由于时间git cherry-pick学会了能够应用多次提交,这种区别确实变得有点没有实际意义,但这可以称为收敛进化; - )

真正的区别在于创建两种工具的原始意图:

  • git rebase的任务是将开发人员在其私有存储库中进行的一系列更改转发到同一分支的版本Y(Y> ; X)。这有效地改变了那一系列提交的基础,因此“重新定位”。

    (它还允许开发人员将一系列提交移植到任意提交中,但这种用法不太明显。)

  • git cherry-pick用于将一个有趣的提交从一个开发线带到另一个开发线。一个典型的例子是将不稳定开发分支上的安全修复程序向后移植到稳定(维护)分支,其中merge毫无意义,因为它会带来大量不必要的更改。

    自第一次出现以来,git cherry-pick已经能够一次一个地提取多个提交。

因此,这两个命令之间可能最显着的区别在于它们如何处理它们所处理的分支:git cherry-pick通常从其他地方带来提交并将其应用于您的当前分支,记录提交,而git rebase获取当前分支,重写一系列自己的提交提交方式或其他。是的,这是对git rebase可以做什么的严重愚蠢的描述,但这是故意的,试图让一般的想法陷入其中。

更新以进一步解释使用git rebase进行讨论的示例。

鉴于这种情况,a state of the repo before rebasing <书籍说明:

  

但是,还有另一种方法:您可以获取C3中引入的更改补丁并在C4之上重新应用它。在Git中,这称为变基。使用rebase命令,您可以获取在一个分支上提交的所有更改,并将它们应用到另一个分支上。

     

在此示例中,您将运行以下命令:

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
这里的“捕获”是在这个例子中,“实验”分支(重新定位的主题)最初是从“主”分支分叉的,因此它分享提交C0到C2有了它 - 实际上,“实验”是“主”,包括C2加上提交C3。 (这是最简单的情况;当然,“实验”可能在其原始基础之上包含几十个提交。)

现在告诉git rebase将“实验”重新绑定到“主”的当前提示上,git rebase如下:

  1. 运行git merge-base以查看“实验”和“主人”共享的最后一次提交是什么(换句话说,转移点是什么)。这是C2。
  2. 保存自转移点以来所做的所有提交;在我们的玩具示例中,它只是C3。
  3. 将HEAD(在操作开始运行之前指向“实验”的提示)重新指向“主”的提示 - 我们正在重新定位它。
  4. 尝试按顺序应用每个已保存的提交(就像使用git apply一样)。在我们的玩具示例中,它只是一个提交,C3。假设它的应用程序将生成一个提交C3'。
  5. 如果一切顺利,“实验”参考会更新,以指向应用上次保存的提交所产生的提交(在我们的案例中为C3')。
  6. 现在回到你的问题。正如你所看到的,这里技术上 git rebase确实将一系列提交从“实验”移植到“主”的尖端,所以你可以正确地告诉那里确实存在“另一个分支”这个过程。但要点是,“实验”中的提示最终成为“实验”中的新提示,它只是改变了它的基础:
    state after merging

    再次,从技术上讲,你可以告诉git rebase这里包含了某些来自“master”的提交,这绝对是正确的。

答案 1 :(得分:86)

使用cherry-pick,原始提交/分支会一直存在并创建新提交。使用rebase,整个分支随着分支指向重放的提交而移动。

让我们开始说:

      A---B---C topic
     /
D---E---F---G master

<强>调整基线:

$ git rebase master topic

你得到:

              A'--B'--C' topic
             /
D---E---F---G master

<强>樱桃挑选:

$ git checkout master -b topic_new
$ git cherry-pick A^..C

你得到:

      A---B---C topic
     /
D---E---F---G master
             \
              A'--B'--C' topic_new

有关git的更多信息,本书大部分都是(http://git-scm.com/book)

答案 2 :(得分:12)

Cherry-picking适用于个人提交

当你进行变基时,它会将历史记录中的所有提交应用到那里缺少的分支的HEAD。

答案 3 :(得分:9)

一个简短的回答:

  • git cherry-pick更“低级别”
  • 因此,它可以模拟git 变基

上面给出的答案很好,我只是想举例说明它们之间的相互关系。

不建议将“git rebase”替换为这一系列动作,它只是“概念证明”,我希望这有助于理解事物的运作方式。

鉴于以下玩具库:

$ git log --graph --decorate --all --oneline
* 558be99 (test_branch_1) Test commit #7
* 21883bb Test commit #6
| * 7254931 (HEAD -> master) Test commit #5
| * 79fd6cb Test commit #4
| * 48c9b78 Test commit #3
| * da8a50f Test commit #2
|/
* f2fa606 Test commit #1

说,我们在trunk中有一些非常重要的更改(提交#2到#5),我们希望将其包含到我们的分支中。通常我们只是切换到一个分支并执行“git rebase master”。但是,由于我们假装我们只配备了“git cherry-pick”,我们这样做:

$ git checkout 7254931                # Switch to master (7254931 <-- master <-- HEAD)
$ git cherry-pick 21883bb^..558be99   # Apply a range of commits (first commit is included, hence "^")    

在所有这些操作之后,我们的提交图将如下所示:

* dd0d3b4 (HEAD) Test commit #7
* 8ccc132 Test commit #6
* 7254931 (master) Test commit #5
* 79fd6cb Test commit #4
* 48c9b78 Test commit #3
* da8a50f Test commit #2
| * 558be99 (test_branch_1) Test commit #7
| * 21883bb Test commit #6
|/
* f2fa606 Test commit #1

正如我们所看到的,提交#6和#7适用于7254931(主提示)。 HEAD被移动并指出一个提交,这实际上是一个重新分支的一个提示。现在我们需要做的就是删除一个旧的分支指针并创建一个新的指针:

$ git branch -D test_branch_1
$ git checkout -b test_branch_1 dd0d3b4

test_branch_1 现在来自最新的主要职位。完成!

答案 4 :(得分:3)

两者都做非常相似的事情;主要的概念差异(以简化方式)是:

  • rebase 将提交从当前分支移到另一个分支

  • 樱桃选择将提交从另一个分支复制到当前分支

使用类似于@Kenny Ho's answer的图:

给出此初始状态:

A---B---C---D master
     \
      E---F---G topic

...并且假设您希望从当前的topic分支顶部重播master分支的提交,则有两个选择:

  1. 使用变基:首先,您要执行topicgit checkout topic,然后通过运行git rebase master移动分支,产生:

    A---B---C---D master
                 \
                  E'---F'---G' topic
    

    结果:您当前的分支topic已重新定位(移至)master上。
    topic分支已更新,而master分支保持不变。

  2. 使用cherry-pick :首先执行master进入git checkout master,然后通过运行git cherry-pick topic~3..topic复制分支(或等效地,git cherry-pick B..G)产生:

    A---B---C---D---E'---F'---G' master
         \
          E---F---G topic
    

    结果:topic的提交复制master
    master分支已更新,而topic分支保持不变。


当然,在这里您必须使用range notation foo..bar明确地告诉Cherry-pick选择一系列提交。如果您只是像git cherry-pick topic中那样传递了分支名称,则它只会在分支的顶端拾取提交,结果是:

A---B---C---D---G' master
     \
      E---F---G topic

答案 5 :(得分:1)

它们都是用于重写一个分支的提交的命令:差异在于哪个分支 - &#34;你的&#34; (目前已检出HEAD)或&#34;他们的&#34; (作为参数传递给分支的分支) - 是这次重写的 base

git rebase 开始提交重播 提交他们的提交 > (开始提交)。

git cherry-pick 提交重播他们的提交作为你的提交 em> (您的HEAD)。

换句话说,这两个命令的核心行为(忽略它们的不同性能特征,调用约定和增强选项),对称:检出分支bar并运行git rebase foobar分支设置为与签出分支foo相同的历史记录,正在运行git cherry-pick ..barfoo设置为foo的更改,然后是bar)的更改。

命名方面,可以记住两个命令之间的区别,因为每个命令都描述了它对当前分支的作用:rebase使另一个命令 new基础用于您的更改,而cherry-pick从其他分支中选择更改并将置于您的HEAD 之上(如圣代顶部的樱桃)。