例如,我有一个
dev
分支和一个 stable
分支。
如果我从
dev
到 stable
精心挑选了几个提交。
是否有任何方法可以让 Git 知道精选的提交,并在我稍后合并、变基或精选重叠范围(从
dev
回到 stable
时避免双重合并它)? (这是 SVN 中的基本合并跟踪功能)
还值得注意的是,
-x
的 cherry-pick
标志将原始提交的 SHA 添加到提交消息的末尾。
我也喜欢将缩写的 SHA 添加到提交摘要的末尾,以便在查看日志时更容易将精心挑选的提交与原始提交相关联。使用
-s
签核标志来指示谁进行了挑选也很有帮助。
示例:
> git cherry-pick -sex 27d4985
#333: fixes all the things (27d4985)
- how it fixes all the things
(cherry picked from commit 27d49855238364d0184ad344884a366b5b16e)
Signed-off-by: Chuck Norris <[email protected]>
git cherry-pick
是 git rebase
而不是 git merge
的一个有趣案例,因此它实际上重写了您精心挑选的提交,因此它将对您精心挑选的分支的顶部应用相同的更改。由于 git 的提交 ID 是基于提交内容的,因此新提交具有不同的 id,因此被 git 视为完全不同的提交。
另一方面,git merge
创建合并提交;这就是 git 实现合并跟踪的方法。合并提交标志着两个(或更多)不同历史记录聚合的点。调用 git merge [commit-id]
而不是 git cherry-pick [commit-id]
来显式创建合并提交是可以接受的,但这不仅会带来单个精心挑选的提交的效果,还会带来该分支的发散历史记录中的整个更改集。
尽管如此,“双重合并”在 git 中通常不是问题。如果您尝试与包含已存在的变更集的历史记录合并,那么当历史记录粘合在一起时,它就会变成无操作; git 实际上只关心每次提交中树的状态,而不关心使其进入该状态的更改。
实际上有一个名为 git cherry 的命令,它可以打印两个分支之间未合并的每个提交。
对于每个打印的提交,“+”号表示您可以合并它,“-”号表示您已经选择了该提交。
输出远非漂亮。
对于那些来自 SVN 并习惯了 svnmerge.py 的人,我为 git 制作了一个“svnmergevail -l”等效的 bash 脚本,我称之为 gitavail:
#!/bin/bash
# get current branch
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
# get tracked branch (1st argument), if no arg or arguments are only options, assume master
if test -z $1 || grep -q '^-' <<< $1;
then TRACKED_BRANCH=master
else TRACKED_BRANCH=$1; shift
fi
# Log commits available for merge from tracked branch
LOG_OPTIONS=$*
for i in $(git cherry $CURRENT_BRANCH $TRACKED_BRANCH | egrep '^\+' | awk '{print $2}'); do git --no-pager log -n1 $i ${LOG_OPTIONS}; echo; done
假设您在一个分支上,并且您想要列出哪些内容符合从主分支合并的条件,只需运行:
gitavail --name-status
您将得到与“svnmergevail-l”非常相似的输出。
我猜cherry-pick提交一定不能手动修改(冲突怎么办?),如果patch id改变,gitcherry不会意识到该提交已经被cherry-picked了。