如何樱桃select一系列的提交并合并到另一个分支

我有以下存储库布局:

  • 主分公司(生产)
  • 积分
  • 加工

我想要实现的是樱桃从工作分支中挑选一系列的提交并将其合并到集成分支中。 我很新的git,我不知道如何正确地做到这一点(樱桃select提交范围在一个操作,而不是合并),而不会扰乱仓库。 任何指针或想法呢? 谢谢!

当涉及到一系列的承诺,樱桃采摘 不实际的。

正如下面 Keith Kim所提到的那样 ,Git 1.7.2+引入了挑选一系列提交的能力(但是您仍然需要意识到未来合并的樱桃采摘的后果 )

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

达米安 评论并警告我们:

在“ cherry-pick A..B ”forms, A应该比B更老
如果他们是错误的命令,这个命令会默默地失败

如果你想select范围BD (包括) ,那将是B^..D
作为一个例子,请参阅“ 从以前的提交范围Git创build分支? ”。

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

这假定B不是根提交; 否则会出现“ unknown revision ”错误。

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


原文答案(2010年1月)

如Charles Bailey在这里所描述的那样, rebase --onto会更好,你可以在你的整合分支之上重播给定的提交范围。
(也可以在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 

这将重播之间的一切:

  • first_SHA-1_of_working_branch_range (因此~1 )的父first_SHA-1_of_working_branch_range之后:要重放的第一个提交
  • 直到“ integration ”(指向您想要重放的最后一个提交,来自working分支)

到“ tmp ”(指向之前integration指向的地方)

如果其中一个提交重放时发生冲突:

  • 要么解决它,并运行“ git rebase --continue ”。
  • 或跳过这个补丁,而是运行“ git rebase --skip
  • 或者用“ git rebase --abort ”取消所有的东西(并且把tmp分支上的integration分支放回去)

在这个rebase --ontointegration将回到整合分支的最后一个提交(即“ tmp ”分支+所有重放的提交)

如果select樱桃树或者rebase --ontoselectrebase --onto ,不要忘记它会对后续的合并产生影响,如此处所述 。


这里讨论一个纯粹的“ cherry-pick ”解决scheme,其中涉及如下内容:

如果你想使用补丁的方法,那么“git format-patch | git am”和“git cherry”是你的select。
目前, git cherry-pick只接受一个提交,但如果你想从D中select范围B ,那么在Git lingo中就是B^..D

 git rev-list --reverse --topo-order B^..D | while read rev do git cherry-pick $rev || break done 

但无论如何,当你需要“重放”一系列提交时,“重放”这个词应该会促使你使用Git的“ rebase ”function。

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

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

你确定你不想实际合并分支吗? 如果工作分支有一些你不想要的提交,你可以在你想要的地方用HEAD创build一个新的分支。

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

 git format-patch A..B git checkout integration git am *.patch 

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

我把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 

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

以上所有选项都会提示您解决合并冲突。 如果您正在合并为团队提交的更改,则很难从开发人员处理合并冲突并继续执行。 然而,“混帐合并”将一次完成合并,但是不能将一系列修改作为parameter passing。 我们必须使用“git diff”和“git apply”命令来执行转换的合并范围。 我发现如果补丁文件的diff文件太多,“git apply”将会失败,所以我们必须为每个文件创build一个补丁,然后应用。 请注意,该脚本将无法删除在源分支中删除的文件。 这是一种罕见的情况,您可以从目标分支手动删除这些文件。 “git apply”的退出状态如果不能应用补丁,则不为零,但是如果使用-3way选项,它将回退到3路合并,您不必担心这个失败。

以下是脚本。

 enter code here #!/bin/bash # This script will merge the diff between two git revisions to checked out branch # Make sure to cd to git source area and checkout the target branch # Make sure that checked out branch is clean run "git reset --hard HEAD" START=$1 END=$2 echo Start version: $START echo End version: $END mkdir -p ~/temp echo > /tmp/status #get files git --no-pager diff --name-only ${START}..${END} > ~/temp/files echo > ~/temp/error.log # merge every file for file in `cat ~/temp/files` do git --no-pager diff --binary ${START}..${END} $file > ~/temp/git-diff if [ $? -ne 0 ] then # Diff usually fail if the file got deleted echo Skipping the merge: git diff command failed for $file >> ~/temp/error.log echo Skipping the merge: git diff command failed for $file echo "STATUS: FAILED $file" >> /tmp/status echo "STATUS: FAILED $file" # skip the merge for this file and continue the merge for others rm -f ~/temp/git-diff continue fi git apply --ignore-space-change --ignore-whitespace --3way --allow-binary-replacement ~/temp/git-diff if [ $? -ne 0 ] then # apply failed, but it will fall back to 3-way merge, you can ignore this failure echo "git apply command filed for $file" fi echo STATUS=`git status -s $file` if [ ! "$STATUS" ] then # status is null if the merged diffs are already present in the target file echo "STATUS:NOT_MERGED $file" echo "STATUS: NOT_MERGED $file$" >> /tmp/status else # 3 way merge is successful echo STATUS: $STATUS echo "STATUS: $STATUS" >> /tmp/status fi done echo GIT merge failed for below listed files cat ~/temp/error.log echo "Git merge status per file is available in /tmp/status" 

另一个select可能是将我们的策略与范围之前的提交合并,然后将一个“常规”合并到该范围的最后一个提交(或者当它是最后一个提交时的分支)。 那么假设只有2345和3456的主要提交被合并到特性分支中:

主:
 1234
 2345
 3456
 4567

在function分支中:

混帐 - 我们的4567
混帐2345

假设你有2个分支,

“branchA”:包含要复制的提交(从“commitA”到“commitB”

“branchB”:你想要从“branchA”转移的分支

1)

  git checkout <branchA> 

2)获取“commitA”和“commitB”

3)

 git checkout <branchB> 

4)

 git cherry-pick <commitA>^..<commitB> 

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

 git cherry-pick --continue 

继续挑选樱桃的过程。