Answers:
当涉及到一系列提交时,挑选樱桃 是 是不实际的。
正如下面提到的基思·金,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从先前提交的范围创建分支? ”作为插图。
假设这
B
不是根提交;unknown revision
否则会出现“ ”错误。
注意:从Git 2.9.x / 2.10(2016年第三季度)开始,您可以直接在孤儿分支(空头)上挑选一系列提交:请参阅“ 如何在git中使现有分支成为孤儿 ”。
原始答案(2010年1月)
一个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
)的父项之后:要重播的第一个提交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 lingo,因此
git rev-list --reverse --topo-order B^..D | while read rev
do
git cherry-pick $rev || break
done
但是无论如何,当您需要“重播”一系列提交时,“重播”一词应促使您使用rebase
Git 的“ ”功能。
-m
选项的父母,那么如何处理这些提交?还是有办法过滤掉这些提交?
-m
应该为您处理这些问题,方法是选择-m
为此摘樱桃选择的参数所引用的主线。
-m
仅选择提交范围时击中父提交时使其通过选项?现在如果我通过-m
,git cherry-pick a87afaaf..asfa789 -m 1
它适用于范围内的所有提交。
error: Commit 8fcaf3b61823c14674c841ea88c6067dfda3af48 is a merge but no -m option was given.
我实际上意识到您可以做到的,git cherry-pick --continue
并且可以(但不包括父提交)
从git v1.7.2开始,cherry pick可以接受一系列提交:
git cherry-pick
学会了选择一系列提交(例如cherry-pick A..B
和cherry-pick --stdin
),也是如此git revert
;但是,这些不支持更好的顺序控制rebase [-i]
。
cherry-pick A..B
它将不会获得提交A(您将需A~1..B
要这样做),并且如果有任何冲突,git不会像rebase一样自动继续(至少从1.7.3.1开始)
git cherry-pick A..B C
它并没有像您期望的那样天真地工作。它不会选择范围内的所有内容A..B
并提交C
!为此,您需要先分成两行,git cherry-pick A..B
然后再分为git cherry-pick C
。因此,只要有范围,就需要分别执行。
您确定不想合并分支吗?如果工作分支中有一些您不需要的近期提交,则可以只在需要的位置创建一个带有HEAD的新分支。
现在,无论出于何种原因,如果您确实确实想选择一系列提交,一种简便的方法是仅提取补丁集并将其应用于新的集成分支:
git format-patch A..B
git checkout integration
git am *.patch
无论如何,这本质上就是git-rebase所做的,但是不需要玩游戏。如果需要合并,可以添加--3way
到git-am
。如果遵循逐字说明,请确保执行此操作的目录中没有其他* .patch文件...
A^
包含A
。
我将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
我目前正在使用它,因为我要重建一个项目的历史记录,该项目的第3方代码和自定义项在同一svn干线中混合在一起。我现在将核心第三方代码,第三方模块和自定义项拆分到自己的git分支中,以更好地了解以后的自定义项。git-cherry-pick
在这种情况下很有用,因为我在同一存储库中有两棵树,但是没有共享祖先。
以上所有选项将提示您解决合并冲突。如果您要合并为一个团队提交的更改,则很难解决开发人员的合并冲突并继续进行。但是,“ git merge”将一次性完成合并,但是您不能将一系列修订作为参数。我们必须使用“ git diff”和“ git apply”命令来完成revs的合并范围。我观察到,如果补丁文件中的差异文件太多,则“ git apply”将失败,因此我们必须为每个文件创建一个补丁,然后应用。请注意,该脚本将无法删除在源分支中删除的文件。这是极少数情况,您可以从目标分支中手动删除此类文件。如果无法应用补丁,则“ git apply”的退出状态不为零,
下面是脚本。
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"
几天前,在阅读了关于Vonc的清晰解释后,我进行了测试。
dev
:ABCDEFGHIJtarget
:ABCDE
,也不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
我在rebase编辑器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
,“樱桃采摘”是可以的,但更多的则是太冗长,分支会变得太复杂git rebase --onto
另一种选择可能是与我们的策略合并到该范围之前的提交,然后与该范围的最后一次提交(或分支到最后一个提交)进行“正常”合并。因此,假设只有2345和3456的master提交要合并到功能分支中:
主: 1234 2345 3456 4567
在功能分支中:
git merge -s我们的4567 git merge 2345