默认情况下,有关原始“樱桃”提交的信息不会记录为新提交的一部分。
在提交消息中记录源提交
如果您可以强制使用特定的工作流程/选项,
git cherry-pick 有 -x 选项:
在记录提交时,在原始提交消息中附加一条注释,指出此更改是从哪个提交中挑选出来的。
如果您不能依靠使用该选项的樱桃采摘者,这显然是无用的。
此外,由于记录的信息只是纯文本——就 Git 而言不是实际的参考——即使你使用-x,你仍然必须采取措施确保原始提交保持活动状态(例如标记或非回绕分支的 DAG 的一部分)。
git cherry 和 git patch-id
如果您可以将搜索限制在历史 DAG 的两个特定分支,那么git cherry 可以同时找到“未采摘”和“采摘”樱桃。
注意:此命令(以及相关的git patch-id)只能识别单独采摘的无冲突樱桃,无需额外更改。如果在挑选樱桃时发生冲突(例如,您必须稍微修改它以使其应用),或者您使用 -n/--no-commit 进行额外的更改(例如,单个提交中的多个樱桃),或者提交的内容在挑选后被重写,那么您将不得不依赖提交消息比较(或 -x 信息,如果它被记录)。
git cherry 并不是真正旨在识别采摘樱桃的来源,但我们可以稍微滥用它来识别单个樱桃对。
鉴于以下历史 DAG(如原始海报示例中所示):
1---2---3---B---D master
\
A---C dev
# D is a cherry-picked version of C
你会看到这样的:
% git cherry master dev
+ A
- C
% git cherry dev master
+ B
- D
(A、B、C 和 D 是真实输出中的完整 SHA-1 哈希)
由于我们在每个列表中看到一个樱桃(- 行),它们必须形成一对樱桃。 D 是从 C 中挑选出来的(反之亦然;你不能仅通过 DAG 来判断,尽管提交日期可能会有所帮助)。
如果您要处理多个潜在的樱桃,则必须“滚动自己的”程序来进行映射。任何语言中的代码都应该很容易使用关联数组、散列、字典或等价物。在 awk 中,它可能看起来像这样:
match_cherries() {
a="$(git rev-parse --verify "$1")" &&
b="$(git rev-parse --verify "$2")" &&
git rev-list "$a...$b" | xargs git show | git patch-id |
awk '
{ p[$1] = p[$1] " " $2 }
END {
for (i in p) {
l=length(p[i])
if (l>41) print substr(p[i],2,l-1)
}
}'
}
match_cherries master dev
有两个采摘樱桃的扩展示例:
1---2---3---B---D---E master
\
A---C dev
# D is a cherry-picked version of C
# E is a cherry-picked version of A
输出可能如下所示:
match_cherries master dev
D C
E A
(A、C、D 和 E 是真实输出中的完整 SHA-1 哈希)
这告诉我们 C 和 D 代表相同的变化,而 E 和 A 代表相同的变化。和以前一样,除非您还考虑(例如)每个提交的提交日期,否则无法判断每一对中的哪一个是“第一个”。
提交消息比较
如果您的樱桃不是用-x 采摘的,或者它们是“脏的”(有冲突,或添加了其他更改(即--no-commit 加上临时额外更改,或git commit --amend 或其他“历史重写”机制)),那么您可能不得不依赖于比较不可靠的提交消息比较技术。
如果您可以找到一些可能是提交所独有的提交消息,并且不太可能在由于挑选樱桃而导致的提交中发生更改,则此技术最有效。效果最好的部分取决于项目中使用的提交消息的样式。
一旦您选择了消息的“识别部分”,您就可以使用git log 来查找提交(在 Jefromi 的回答中也有演示)。
git log --grep='unique part of the commit message' dev...master
--grep 的参数实际上是一个正则表达式,因此您可能需要转义任何正则表达式元字符 ([]*?.\)。
如果您不确定哪些分支可能保存原始提交和新提交,您可以使用 --all,如 Jefromi 所示。