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

时间:2010-05-27 15:51:31

标签: git version-control

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

例:
- 在主分公司 - 来自开发分支的樱桃选择承诺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的回答,因为它更接近于实际问题。谢谢你们。

3 个答案:

答案 0 :(得分: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加上进行额外更改,或{{1}或者其他“历史重写”机制)),那么你可能不得不依赖于比较提交消息的可靠性较低的技术。

如果您可以找到一些可能对提交唯一的提交消息并且不太可能在提取中产生更改,那么此技术最有效。最有效的位将取决于项目中使用的提交消息的样式。

一旦您选择了消息的“识别部分”,您就可以使用git log来查找提交(也在Jefromi的答案中进行了演示)。

git commit --amend

git log --grep='unique part of the commit message' dev...master 的参数实际上是一个正则表达式,因此您可能需要转义任何正则表达式元字符(--grep)。

如果您不确定哪些分支可能包含原始提交和新提交,则可以使用[]*?.\作为Jefromi显示。

答案 1 :(得分: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在问题的评论中提到的那样,对于这样的本地采摘,修复技巧(如 monotone 或{{3} })更合适,因为它会留下合并的清晰痕迹。

  

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

     

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

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

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

bisect

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

  

一直做着笨拙的修复不适合所有人   在引入错误的修订版中直接开发修复程序并不总是那么容易。

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

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

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

答案 2 :(得分:4)

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

git log --grep="<commit subject>" --all

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