我最近开始与Git合作。
在网上查阅Git书,我在“ Git Rebase”部分找到了以下内容:
使用rebase命令,您可以执行在一个分支上提交的所有更改,并在另一个分支上重播它们。
(引自:http : //git-scm.com/book/en/Git-Branching-Rebasing)
我认为这是git cherry-pick的确切定义(在当前签出的分支上重新应用一个提交或一组提交对象)。
两者有什么区别 ?
我最近开始与Git合作。
在网上查阅Git书,我在“ Git Rebase”部分找到了以下内容:
使用rebase命令,您可以执行在一个分支上提交的所有更改,并在另一个分支上重播它们。
(引自:http : //git-scm.com/book/en/Git-Branching-Rebasing)
我认为这是git cherry-pick的确切定义(在当前签出的分支上重新应用一个提交或一组提交对象)。
两者有什么区别 ?
Answers:
自从git cherry-pick
学习了能够应用多个提交的时间以来,这种区分确实变得有些争议了,但这就是所谓的收敛进化;-)
真正的区别在于创建这两种工具的原始意图:
git rebase
的任务是将开发人员在其私有存储库中针对上游分支的X版本创建的一系列更改转发到同一分支的Y版本(Y> X)。这有效地改变了该系列提交的基础,因此“ 变基础 ”。
(它还允许开发人员将一系列提交移植到任意提交上,但这不太明显。)
git cherry-pick
是为了将有趣的承诺从一个开发线带到另一个开发线。一个典型的示例是将在不稳定的开发分支上进行的安全修复程序反向移植到稳定的(维护)分支,在该分支上merge
没有意义,因为这会带来很多不必要的更改。
自首次出现以来,git cherry-pick
就能够一次一次地拾取多个提交。
因此,这两个命令之间最显着的区别可能是它们如何对待工作的分支:git cherry-pick
通常从其他地方带来提交,并将其应用于当前分支的顶部,记录新提交,同时git rebase
获取当前分支并重写一系列自己的提示以一种或另一种方式提交。是的,这是对git rebase
可以做什么的沉闷描述,但这是有意的,试图使总体思想沉入其中。
更新以进一步说明git rebase
正在讨论的使用示例。
在这种情况下,
《书》指出:
但是,还有另一种方法:您可以对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
如下所示:
git merge-base
以查看“实验”和“大师”共享的最后一次提交是什么(换句话说,这是转移的重点)。这是C2。git apply
按顺序应用每个已保存的提交(就像使用一样)。在我们的玩具示例中,这只是一次提交,即C3。假设其应用程序将生成提交C3'。现在回到您的问题。如您所见,从技术上讲 ,这里git rebase
确实是将一系列提交从“实验”移植到“ master”的尖端,因此您可以正确地告诉我们在此过程中确实存在“另一个分支”。但是要点是,来自“实验”的技巧提交最终成为“实验”中的新技巧提交,它只是改变了其基础:
再次,从技术上讲,您可以说git rebase
这里合并了“ master”的某些提交,这是绝对正确的。
使用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)
topic
基于进行了重新基础master
,则其中不包含遗漏的提交,那么它们将属于哪个分支?
git checkout topic
再git reset --hard C'
进行樱桃采摘,那么您得到的结果与重新定基后的结果完全相同。我使用樱桃挑选而不是重新定级,从而避免了很多合并冲突,因为共同祖先早已退后。
git
-guru,但是这个rebase
/ cherry-pick
在所有细节上git
都是我有一个理解上的问题。
git checkout -b
,与无关git cherry-pick
。解释您要说的话的一种更好的方法是“您git rebase
在topic
分支上运行并通过它master
;您git cherry-pick
在master
分支上运行并将其传递(从提交)topic
。”
挑选个人作品的赏心悦目。
当您进行基础调整时,它将历史记录中的所有提交应用于分支中缺少的HEAD。
git cherry-pick foo~3..foo
并从“ foo”中逐一选择树顶提交。
git am
在其上运行。樱桃选择适用于逐次提交的提交(可能通过为每个补丁创建一个单消息邮箱)。我的rebase失败了,因为它正在创建的邮箱文件在驱动器上空间不足,但是具有相同修订范围的cherry-pick成功了(并且运行速度似乎更快)。
一个简短的答案:
上面给出的答案很好,我只是想举一个例子来证明它们的相互关系。
不建议以此顺序替换“ 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
假设我们要对master进行一些非常重要的更改(提交#2至#5),并将其包含在test_branch_1中。通常我们只是切换到一个分支并执行“ 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(master的一个尖端提交)。HEAD被移动并指向一个提交,该提交从本质上讲是一个重新创建分支的尖端。现在我们需要做的就是删除一个旧的分支指针并创建一个新的分支指针:
$ git branch -D test_branch_1
$ git checkout -b test_branch_1 dd0d3b4
现在,test_branch_1从最新的主控职位开始扎根。做完了!
cherry-pick
能够应用一系列提交,我想是的。尽管这样做有点怪异,但没有什么可以阻止您在功能分支的顶部挑选所有提交master
,然后删除功能分支并重新创建,使其指向的尖端master
。你可以认为git rebase
作为一个序列git cherry-pick feature_branch
,git branch -d feature_branch
和git branch feature_branch master
。
它们都是用于重写一个分支在另一个分支上的提交的命令:区别在于哪个分支-“您的”(当前签出的HEAD
)或“他们的”(作为参数传递给命令的分支)-是此重写的基础。
git rebase
接受一个起始提交,并在它们提交之后重播您的提交(起始提交)。
git cherry-pick
接受一组提交并在您(您的)之后重播它们的提交HEAD
。
换句话说,这两个命令,在其核心行为(忽略了不同的性能特点,调用约定,并增强选项),对称:检查出的分支bar
和运行git rebase foo
套bar
如检查出的分支的分支在同一历史foo
和运行git cherry-pick ..bar
将设置foo
到(从进行更改foo
,然后是从进行更改bar
)。
在命名方面,可以记住这两个命令之间的区别,因为每个命令都描述了它对当前分支的作用:rebase
使另一个成为更改的新基础,而cherry-pick
从另一个分支中选择更改并将其放在顶部您的HEAD
(像圣代冰淇淋上的樱桃)。
两者都做非常相似的事情。主要的概念差异(以简化的方式)是:
rebase将提交从当前分支移动到另一个分支。
Cherry-pick副本从另一个分支提交到当前分支。
使用类似于@Kenny Ho的答案的图:
给定此初始状态:
A---B---C---D master
\
E---F---G topic
...并且假设您想从topic
当前master
分支的顶部重放分支的提交,则有两个选择:
使用rebase:首先,请topic
执行git checkout topic
,然后通过运行来移动分支git rebase master
,产生:
A---B---C---D master
\
E'---F'---G' topic
结果:您当前的分支topic
已重新定位(移至上)master
。
该topic
分支进行了更新,而master
分支留在地方。
使用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表示法明确地告诉cherry-pick选择一系列提交。如果您只是简单地传递了分支名称(如中的),则它将只选择分支顶端的提交,结果是: foo..bar
git cherry-pick topic
A---B---C---D---G' master
\
E---F---G topic