如何挑选多个提交


873

我有两个分支。提交a是一个头,而其他有bcdef之上a。我想移动cdef第一支没有提交b。使用樱桃挑选很容易:将第一个分支逐个签出cf然后将第二个分支重新建立到第一个分支上。但有什么办法可以摘樱桃所有c- f在一个命令?

这是该场景的直观描述(感谢JJD):

在此处输入图片说明


3
您提到的rebase与问题不是很相关吗?(我知道您以后可能会希望b以此为基础f,但这与挑选樱桃无关。)
Superole

Answers:


1280

Git 1.7.2引入了选择一系列提交的功能。从发行说明中

git cherry-pick学会了选择一系列提交(例如cherry-pick A..Bcherry-pick --stdin),也是如此git revert;但是,这些不支持更好的顺序控制rebase [-i]

要选择从提交A到提交BA早于B)的所有提交,请运行:

git cherry-pick A^..B

如果要忽略 A本身,请运行:

git cherry-pick A..B

(评论中的信由达米安,JB Rainsberger和sschaef提供)


249
在“ cherry-pick A..B”格式中,A应该早于B。如果命令顺序错误,该命令将自动失败。
达米安

294
此外,这不会挑剔A,而是从A到B
。– JB Rainsberger 2012年

454
要包括A正义类型git cherry-pick A^..B
kiritsuku

17
如果您具有git 1.7.1或更早版本并且无法更新,则可以通过运行git cherry-pick f~3then git cherry-pick f~2等快速按顺序挑选它们,直到git cherry-pick f(按向上箭头获取上一个命令,以便我可以快速更改数字并运行它,在大多数控制台中应该相似)。
戴维·梅森

19
最好知道此语法也适用于分支名称。git cherry-pick master..somebranch将在master分支上选择某个分支上的所有提交(假设已经基于master提交),并将它们应用于当前分支。
Tor Klingberg

102

最简单的方法是onto选择rebase。假设在支路电流结束a被称为mybranch,这是你要移动的分支c- f到。

# checkout mybranch
git checkout mybranch

# reset it to f (currently includes a)
git reset --hard f

# rebase every commit after b and transplant it onto a
git rebase --onto a b

1
谢谢!您还能补充git checkout secondbranch && git rebase mybranch答案吗
tig

1
这个答案对我帮助很大,让我明白了在这种情况下是哪个提交。和:您也可以使用rebase的交互模式。谢谢@查尔斯!
奥利弗

1
这种方法的优点在于,您可以--interactive从序列中删除某些提交,或者在“樱桃挑选”之前对其重新排序。+1
Michael Merickel 2014年

这是一个很巧妙的命令,将您的头缠起来有点棘手,但这确实令人惊奇。
Valerio

狂野,你必须给承诺,你想要衍合为argumente之一(b在本例中),但是这是很适合我。
asontu

85

或要求的单线:

git rebase --onto a b f

5
如果只是为了简洁,这是最好的答案。
内特·钱德勒

9
已投票,但如果f是一次提交(而不是分支),将使您处于分离的HEAD状态-您应进行编辑以添加一个应签出一个分支的方式,如下面的回答所示
Mr_and_Mrs_D

68

您可以使用的串联组合git rebase,并git branch申请一集团承诺的到另一个分支。正如Wolfc已经发布的,第一个命令实际上是复制提交。但是,只有将分支名称添加到组的最前提交后,更改才可见。

请在新标签页中打开图片...

工作流程

要以文本形式汇总命令:

  1. 使用以下命令将gitk作为独立进程打开:gitk --all &
  2. 运行git rebase --onto a b f
  3. F5gitk。没有什么变化。但没有HEAD标记。
  4. git branch selection
  5. F5gitk。出现带有提交的新分支。

这应该使事情澄清:

  • 提交a是组的新根目标。
  • 提交b是组中第一次提交之前的提交(不包括)。
  • 提交f是组中的最后一次提交(包括)。

之后,您可以使用直到从分支git checkout feature && git reset --hard b删除提交。cffeature

除了这个答案之外,我还写了一篇博客文章,描述了另一种情况下的命令,这些情况应该有助于普遍使用它。


2
如果不再需要mybranch(a..f提交),则可以简化为:git rebase --onto a b mybranch和btw- 这些漂亮的git图片是哪个程序?
Mr_and_Mrs_D

2
@Mr_and_Mrs_D感谢您的评论。我想我用cacoo.com画了画。
JJD 2014年

48

要应用JB Rainsberger和sschaef的评论来专门回答这个问题,请执行以下操作:在此示例中使用cherry-pick范围:

git checkout a
git cherry-pick b..f

要么

git checkout a
git cherry-pick c^..f

3
我使用git 2.7.0.windows.1并注意到,当我尝试挑选承诺范围时,一切都很好,但是git并没有告诉您必须git cherry-pick --continue | --abort | --quit尝试做的任何事情,然后再尝试再次进行承诺/选择。因此,如果您选择承诺范围,则git cherry-pick --continue每次准备就绪(解决冲突等问题)时,都需要使用给定范围内的承诺来运行。
kuskmen,2016年

无法找到“a..b”:我做了完全一样的,但致命的
阿米特·卡尼克

我不知道我在哪里错了,但是当我站在一边做'git cherry-pick c ^ .. f'时,这包括提交f但不包括提交c。但是,正如我到处阅读的那样,应该将c和f定义为包含在内。还是我错了?
塞缪尔

@Samuel是的,没错。所述^的C之后实际上意味着即b在这种情况下“C之前提交”。这就是为什么c^..f是的同义词b..f。尝试做一下git log c^..f,您应该会看到c到f的提交,与您所做的完全相同git log b..f
Andy

40

如果您有要合并的选择性修订,例如从A,B,C,D,E,F,G,H,I,J提交中说出A,C,F,J,只需使用以下命令:

git cherry-pick ACFJ


1
漂亮又简单
Spinup

21
git rev-list --reverse b..f | xargs -n 1 git cherry-pick

2
如果没有冲突,则可以完美地工作,否则“基于”可以更容易,因为您不必弄清楚它在哪里停止并重新应用其余补丁。
Ruslan Kabalin 2011年

6
请添加注释以说明操作方式
Mr_and_Mrs_D 2014年

7
因为没有人解释... git rev-list将从分支b到f的所有修订版打印(颠倒),以便在按顺序传递每一行(提交哈希)时,它将选择每一个修订版到当前的git HEAD上。即git cherry-pick {hash of c}; git cherry-pick {hash of d}; ...
coderatchet


7

另一个值得一提的变体是,如果您希望n分支中的最后一次提交,则~语法可能会很有用:

git cherry-pick some-branch~4..some-branch

在这种情况下,上述命令将从分支中选择最后4次提交some-branch(尽管您也可以使用提交哈希代替分支名称)


1
非常有用的答案,谢谢!:)
Jacek Dziurdzikowski

3

实际上,最简单的方法是:

  1. 记录两个分支之间的合并基础: MERGE_BASE=$(git merge-base branch-a branch-b)
  2. 快进或将较旧的分支重新建立到较新的分支
  3. 从第1步的合并基础开始,将结果分支重新定位到自身上,并手动删除不需要的提交:

    git rebase ${SAVED_MERGE_BASE} -i
    

    或者,如果只有几个新提交,则跳过第1步,只需使用

    git rebase HEAD^^^^^^^ -i
    

    在第一步中,使用足够的空间^来移动合并基础。

您将在交互式资源库中看到以下内容:

pick 3139276 commit a
pick c1b421d commit b
pick 7204ee5 commit c
pick 6ae9419 commit d
pick 0152077 commit e
pick 2656623 commit f

然后删除第b行(以及您需要的任何其他行)



0

这是一个脚本,您可以通过简单地告诉脚本樱桃选择的源分支和目标分支以及提交数量,来连续挑选多个提交:

https://gist.github.com/nickboldt/99ac1dc4eb4c9ff003a1effef2eb2d81

要将分支从分支挑选到主分支(使用当前分支作为源):

./gcpl.sh -m

要从6.19.x分支中挑选最新的5个提交提交给master:

./gcpl.sh -c 5 -s 6.19.x -t master

当您可以直接使用Git进行操作时,为什么需要此脚本?...
code_dredd

更少的输入,而且我的脚本会自动为您选择提交,因此您不必通过SHA挑选每个提交。无论如何,YMMV。
nickboldt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.