Git:有没有办法弄清楚提交的选择在哪里?

问题描述 投票:33回答:3

如果我从多个分支中挑选,是否有一种简单的方法来确定提交的来源(例如原始提交的sha)?

例: - 在主分公司 - 来自dev分支的cherry pick commit A. - A在主分支处变为D.

之前:

* B (master) Feature Y
| * C (dev) Feature Z
| * A Feature X
|/
* 3
* 2
* 1  

后:

* D (master) Feature X
* B Feature Y
| * C (dev) Feature Z
| * A Feature X
|/
* 3
* 2
* 1  

是否有可能弄清楚D是从A中挑选出来的(除了搜索提交消息)?

编辑: 虽然我会使用daggy-fixes(请参阅VonCs回答),但我接受了Chris Johnsens的回答,因为它更接近于实际问题。多谢你们。

git version-control
3个回答
36
投票

默认情况下,有关原始“cherry”提交的信息不会记录为新提交的一部分。

在提交消息中记录源提交

如果你可以强制使用特定的工作流程/选项,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显示。


10
投票

如果我按照你的图表,你想知道你是否可以确定,而不是D(不是B)是采摘樱桃的结果。

理论上,如“How to list git branches that contain a given commit?”所示,如果D实际上是与A相同的提交(SHA1),则可以搜索提交:

git branch --contains <commit>

但正如Jefromi评论的那样,D在这种情况下不能拥有相同的SHA1。 这留下了搜索常见的提交消息:请参阅Jefromi's answer


正如Ken Bloom在问题的评论中提到的那样,对于这样的本地樱桃采摘,一种daggy-fix技术(如monotonemercurial)更合适,因为它将留下合并的清晰痕迹。

Daggy修复意味着使用而不是丢失祖先图中的错误和修复之间的真正起源和关系。

由于[Git]提供了在任何修订版本之上进行提交的能力,从而产生了一个小的匿名分支,一个可行的樱桃选择方法如下:

  • 使用bisect来识别出现错误的修订版;
  • 查看该修订;
  • 修复bug;
  • 并将修复程序作为引入该错误的修订版的子项提交。

这个新的变化可以很容易地合并到任何有原始bug的分支中,而不需要任何粗略的挑选樱桃的滑稽动作。 它使用修订控制工具的常规合并和冲突解决机制,因此它比采摘樱桃更可靠(其执行几乎总是一系列奇怪的黑客攻击)。

https://storage.googleapis.com/google-code-attachments/rainforce/issue-4/comment-5/Hg-dag-6-daggy-fix.png Hg DaggyFox

(这里是Mercurial图,但很容易应用于Git)

一直做daggy修复不适合每个人。 在引入错误的修订版中直接开发修复程序并不总是那么容易。

  • 也许直到其他一些更新的代码以暴露bug的方式使用它时才发现这个bug;如果没有其他代码,很难调试并找到修复程序。
  • 或许当时还没有实现修复的重要性或范围。

另见article for more on daggy-fix

这种回溯历史以修复错误,然后将修复程序合并到现代分支中的技术被Monotone的作者命名为“daggy fixes”,directed acyclic graph, or dag是一个有影响力的分布式修订控制系统。 修复被称为daggy,因为他们利用项目的历史结构为git log --grep="<commit subject>" --all 。 虽然这种方法可以与Subversion一起使用,但与分布式工具相比,它的分支是重量级的,这使得daggy-fix方法不太实用。这强调了一种工具的优势将为其用户带来的技术提供信息的想法。


4
投票

没有关于原始提交的信息嵌入在新创建的提交中,因此没有直接的方法可以告诉。你建议的(搜索提交消息)可能是最好的方法 - 它肯定比搜索具有相同diff的提交容易得多:

git fsck

当然除非提交不再可以从分支中找到...可能那么你想看看qazxswpoi的输出。

© www.soinside.com 2019 - 2024. All rights reserved.