如何樱桃挑选一系列提交并合并到另一个分支?

cra*_*yte 599 git git-merge git-cherry-pick

我有以下存储库布局:

  • 主分公司(生产)
  • 积分
  • 工作的

我想要实现的是从工作分支中挑选一系列提交并将其合并到集成分支中.我是git的新手,我无法弄清楚如何正确地做到这一点(在一次操作中不提取合并的樱桃选择提交范围)而不会弄乱存储库.关于这个的任何指针或想法?谢谢!

Von*_*onC 767

当涉及到一系列的提交,采摘樱桃 不实际的.

正如Keith Kim 在下面提到的,Git 1.7.2+引入了挑选一系列提交的能力(但是你仍然需要知道未来合并的挑选结果)

git cherry-pick"学会选择一系列提交
(例如" cherry-pick A..B"和" cherry-pick --stdin"),所以" git revert";这些不支持更好的排序控制" rebase [-i]".

达米安 评论并警告我们:

在" cherry-pick A..B"形式,A应该比年龄大B.
如果它们的顺序错误,命令将无声地失败.

如果你想挑选范围B通过D(含),这将是B^..D.
请参阅" Git从先前提交范围创建分支? "作为示例.

正如Jubobs 在评论中提到的那样:

这假设B不是root提交; unknown revision否则你会得到一个" "错误.

注意:从Git 2.9.x/2.10(2016年第3季度)开始,您可以直接在孤儿分支(空头)上挑选一系列提交:请参阅" 如何在git中使现有分支成为孤儿 ".


原始答案(2010年1月)

A rebase --onto会更好,你可以在集成分支上重放给定的提交范围,正如Charles Bailey在这里所描述的那样.
(另外,在git rebase手册页中查找"以下是如何将基于一个分支的主题分支移植到另一个分支" ,以查看实际示例git rebase --onto)

如果您当前的分支是集成:

# Checkout a new temporary branch at the current location
git checkout -b tmp

# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range

# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration
Run Code Online (Sandbox Code Playgroud)

这将重播之间的一切:

  • first_SHA-1_of_working_branch_range(因此~1)的父项之后:您要重播的第一个提交
  • 最多" integration"(指向您要重播的最后一次提交,来自working分支)

到" tmp"(integration指向之前指向的位置)

如果重播其中一个提交时有任何冲突:

  • 要么解决它并运行" git rebase --continue".
  • 或跳过此补丁,而不是运行" git rebase --skip"
  • 或用" git rebase --abort" 取消所有东西(并将integration分支放回tmp分支)

之后rebase --onto,integration将返回到集成分支的最后一次提交(即" tmp"分支+所有重放的提交)

选择樱桃,或者rebase --onto不要忘记它会对后续合并产生影响,如此处所述.


这里讨论一个纯粹的" cherry-pick"解决方案,它将包含以下内容:

如果你想使用补丁方法,那么"git format-patch | git am"和"git cherry"是你的选择.
目前,git cherry-pick只接受单一的承诺,但如果你想选择的范围内B通过D,这将是B^..D在git的行话,所以

git rev-list --reverse --topo-order B^..D | while read rev 
do 
  git cherry-pick $rev || break 
done 
Run Code Online (Sandbox Code Playgroud)

但无论如何,当你需要"重放"一系列提交时,"重放"一词应该会促使你使用rebaseGit 的" "特性.

  • 如果您的提交的父项需要 `-m` 选项,您将如何处理这些提交?或者有没有办法过滤掉这些提交? (2认同)

小智 134

从git v1.7.2开始,cherry pick可以接受一系列提交:

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

  • 请注意,`cherry-pick A..B`将不会得到提交A(你需要'A~1..B`),如果有任何冲突,git将不会像rebase那样自动继续(至少如1.7.3.1) (99认同)
  • 值得注意的是,`git cherry-pick A..BC`并不像你期望的那样天真地工作.它不会选择"A..B"范围内的所有内容并提交"C"!要做到这一点,你需要分成两行,首先是`git cherry-pick A..B`然后是`git cherry-pick C`.因此,只要有范围,就需要单独执行. (3认同)

Kos*_*asA 32

假设你有2个分支,

"branchA":包括要复制的提交(从"commitA"到"commitB")

"branchB":您希望从"branchA"传输提交的分支

1)

 git checkout <branchA>
Run Code Online (Sandbox Code Playgroud)

2)获取"commitA"和"commitB"的ID

3)

git checkout <branchB>
Run Code Online (Sandbox Code Playgroud)

4)

git cherry-pick <commitA>^..<commitB>
Run Code Online (Sandbox Code Playgroud)

5)如果您有冲突,请解决并输入

git cherry-pick --continue
Run Code Online (Sandbox Code Playgroud)

继续樱桃采摘过程.

  • 4) 的“gitcherry-pick &lt;commitA&gt;^..&lt;commitB&gt;”命令中的“^”有什么作用? (4认同)
  • 请有人编辑帖子,指出“cherry-pick”范围不包括在内。 (3认同)
  • @JVM 当您使用范围内没有“^”的cherry-pick时,将不包含第一个提交 (3认同)
  • @JVM `^` 表示之前的提交。正如 @Tomas 指出的,“cherry-pick”的行为离开了 commitA。因此,要包含“commitA”,您需要使用“commitA^”选择相应的先前提交 (2认同)

djs*_*djs 26

你确定你不想真正合并分支吗?如果工作分支有一些你不想要的最近提交,你可以在你想要的位置创建一个带有HEAD的新分支.

现在,如果你真的想要挑选一系列提交,无论出于何种原因,一个优雅的方法是只需要一个补丁集并将其应用到你的新集成分支:

git format-patch A..B
git checkout integration
git am *.patch
Run Code Online (Sandbox Code Playgroud)

这基本上就是git-rebase正在做的事情,但不需要玩游戏.您可以添加--3waygit-am,如果你需要合并.如果您逐字按照说明操作,请确保在您执行此操作的目录中没有其他*.patch文件...

  • 请注意,与其他修订范围一样,它需要是“A^”才能包含“A”。 (2认同)

Sai*_*pta 26

gitcherry-pick start_commit_sha_id ^.. end_commit_sha_id

例如git cherry-pick 3a7322ac^..7d7c123c

假设您位于要从branchA中选择提交的位置(给出了范围的开始和结束提交 SHA,而左侧提交 SHA 较旧branchB。整个提交范围(包括两者)都将在branchA.

官方文档中给出的例子非常有用。


Ada*_*nco 9

我将VonC的代码包装成一个简短的bash脚本git-multi-cherry-pick,以便于运行:

#!/bin/bash

if [ -z $1 ]; then
    echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
    echo "";
    echo "Usage:  $0 start^..end";
    echo "";
    exit 1;
fi

git rev-list --reverse --topo-order $1 | while read rev 
do 
  git cherry-pick $rev || break 
done 
Run Code Online (Sandbox Code Playgroud)

我正在使用这个,因为我重建了一个项目的历史,该项目的第三方代码和自定义在同一个svn主干中混合在一起.我现在将核心第三方代码,第三方模块和自定义分离到他们自己的git分支上,以便更好地理解未来的自定义.git-cherry-pick在这种情况下有用,因为我在同一个存储库中有两棵树,但是没有共享的祖先.


kxr*_*kxr 8

git cherry-pick FIRST^..LAST仅适用于简单场景。

为了实现像样的“将其合并到集成分支”,同时具有通常的舒适度,例如自动跳过已经集成的选择、移植钻石合并、交互式控制......)最好使用变基。这里的一个答案指出了这一点,但是该协议包含了一个冒险git branch -f和与临时分支的杂耍。这是一个直接的稳健方法:

git rebase -i FIRST LAST~0 --onto integration
git rebase @ integration
Run Code Online (Sandbox Code Playgroud)

允许-i交互式控制。~0如果 LAST 是分支名称,则可确保分离的变基(不移动/另一个分支)。否则可以省略。第二个 rebase 命令只是integration以安全的方式将分支引用移动到中间分离头 - 它不会引入新的提交。要使用合并菱形等对复杂结构进行变基,请在第一个变基中考虑--rebase-merges或 。--rebase-merges=rebase-cousins


phi*_*i_b 6

几天前,在阅读了 Vonc 非常清晰的解释后,我对此进行了测试。

我的脚步

开始

  • 分支机构dev: ABCDEFGHIJ
  • 分行target: ABCD
  • 我既不想E也不H

复制分支中没有步骤 E 和 H 的特征的步骤dev_feature_wo_E_H

  • git checkout dev
  • git checkout -b dev_feature_wo_E_H
  • git rebase --interactive --rebase-merges --no-ff D我放在变基编辑器drop前面E和里面的地方H
  • 解决冲突,继续并commit

在目标上复制分支的步骤dev_feature_wo_E_H

  • git checkout target
  • git merge --no-ff --no-commit dev_feature_wo_E_H
  • 解决冲突,继续并commit

一些备注

  • cherry-pick我这样做是因为前几天做了太多事

  • git cherry-pick功能强大且简单,但是

    • 它会创建重复的提交
    • 当我想要时,merge我必须解决初始提交和重复提交的冲突,因此对于一两个cherry-pick,“择优挑选”是可以的,但对于更多,它太冗长了,分支将变得太复杂


归档时间:

查看次数:

322351 次

最近记录:

7 年,2 月 前