我有两个分支。提交a是一个的头,而另一个有b, c, d, e和f在a的顶部。我想移动c, d, e和f到第一个分支,而不提交b。使用樱桃采摘很容易:签出第一个分支樱桃采摘一个接一个c到f,并重新建立第二个分支到第一个。但是有没有办法在一个命令中选择所有的c-f ?

下面是场景的可视化描述(感谢JJD):


当前回答

你可以使用git rebase和git分支的串行组合来将一组提交应用到另一个分支上。正如wolfc已经发布的,第一个命令实际上复制了提交。但是,在向组的最顶层提交添加分支名称之前,更改是不可见的。

请在新标签页打开图片…

以文本形式总结命令:

使用命令:gitk——all &将gitk作为一个独立的进程打开。 运行git rebase——to a bf。 在gitk中按F5。没有什么变化。但是没有HEAD标记。 运行git分支选择 在gitk中按F5。新的分支及其提交将出现。

这应该澄清一些事情:

Commit a是组的新根目的地。 提交b是组的第一个提交之前的提交(独占)。 提交f是组(包括)的最后一次提交。

然后,你可以使用git checkout功能&& git reset—hard b从功能分支中删除c到f的提交。

除了这个答案,我还写了一篇博客文章,描述了另一个场景中的命令,应该有助于一般使用它。

其他回答

除了提交之外,还可以通过管道从stdin输入sha列表。

git rev-list --reverse ..main -- path/ | git cherry-pick --stdin 

Rev-list基本上是git-log的管道命令(“丑陋”但快速的表亲) 注意——反向是需要的。

您可以通过这种方式执行更高级的操作,而不仅仅是提交范围。

你可以使用git rebase和git分支的串行组合来将一组提交应用到另一个分支上。正如wolfc已经发布的,第一个命令实际上复制了提交。但是,在向组的最顶层提交添加分支名称之前,更改是不可见的。

请在新标签页打开图片…

以文本形式总结命令:

使用命令:gitk——all &将gitk作为一个独立的进程打开。 运行git rebase——to a bf。 在gitk中按F5。没有什么变化。但是没有HEAD标记。 运行git分支选择 在gitk中按F5。新的分支及其提交将出现。

这应该澄清一些事情:

Commit a是组的新根目的地。 提交b是组的第一个提交之前的提交(独占)。 提交f是组(包括)的最后一次提交。

然后,你可以使用git checkout功能&& git reset—hard b从功能分支中删除c到f的提交。

除了这个答案,我还写了一篇博客文章,描述了另一个场景中的命令,应该有助于一般使用它。

最简单的方法是使用on选项来调整基数。假设电流在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
git rev-list --reverse b..f | xargs -n 1 git cherry-pick

git rev-list打印从分支b到分支f(反向)的所有修订,这样当每一行(提交哈希)按顺序传递时,它会将每一行都樱桃式地选择到当前git HEAD中。例如,git选择{哈希的c};Git选择{哈希的d};... ——@coderatchet评论

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

记录两个分支之间的merge-base: MERGE_BASE=$(git merge-base branch-a branch-b) 快进或将旧的分支重置到新的分支上 从步骤1的merge base开始,将生成的分支重新基于自身,并手动删除不需要的提交: ${SAVED_MERGE_BASE} -i 或者,如果只有几个新的提交,则跳过第1步,直接使用 git rebase HEAD^^^^^^^ -i 在第一步中,使用足够的^来移动合并基础。

你会在交互的rebase中看到类似这样的东西:

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(和任何其他你想要的)