Git:有没有办法弄清楚提交是从哪里挑选出来的? [英] Git: Is there a way to figure out where a commit was cherry-pick'ed from?

查看:13
本文介绍了Git:有没有办法弄清楚提交是从哪里挑选出来的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

示例:
- 在主分支
- 从开发分支中挑选提交 A
- A 在 master 分支变成 D

之前:

* B (master) Feature Y|* C(开发)功能Z|* 功能 X|/* 3* 2* 1

之后:

* D (master) Feature X* B 特征 Y|* C(开发)功能Z|* 功能 X|/* 3* 2* 1

是否可以确定 D 是从 A 中挑选出来的(除了搜索提交消息)?


尽管我会使用 daggy-fixes(请参阅 VonCs 答案),但我接受了 Chris Johnsens 的答案,因为它更接近实际问题.谢谢各位.

解决方案

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

在提交消息中记录源提交

如果您可以强制使用特定的工作流程/选项,git cherry-pick-x 选项:

<块引用>

在记录提交时,在原始提交消息中附加一条注释,指出此更改是从哪个提交中挑选出来的.

如果您不能依赖使用该选项的樱桃采摘器,这显然是无用的.此外,由于记录的信息只是纯文本——就 Git 而言不是实际的参考——即使你使用 -x,你仍然必须采取措施确保原始提交是保持活动状态(例如是标签或非回绕分支的 DAG 的一部分).

git cherrygit patch-id

如果您可以将搜索限制在历史 DAG 的两个特定分支,则 git cherry 可以找到未采摘"和采摘"的樱桃.

注意:这个命令(以及相关的git patch-id) 只能识别没有额外更改的单独采摘的无冲突樱桃.如果在挑选樱桃时发生冲突(例如,您必须稍微修改它以使其适用),或者您使用 -n/--no-commit阶段额外的更改(例如,单个提交中的多个樱桃),或者在选择后重写提交的内容,那么您将不得不依赖提交消息比较(或 -x 信息,如果它被录下来了).

git cherry 并不是真正设计用来识别采摘樱桃的来源,但我们可以滥用它来识别单个樱桃对.

鉴于以下历史记录 DAG(如原始海报示例中所示):

1---2---3---B---D 大师A---C 开发# D 是 C 的精选版本

你会看到这样的:

% gitcherry master dev+ A- C% git 樱桃开发大师+ 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 补丁 ID |awk '{ p[$1] = p[$1] " " $2 }结尾 {对于(我在 p){l=长度(p[i])if (l>41) 打印 substr(p[i],2,l-1)}}'}match_cherries 开发大师

举一个有两个采摘樱桃的扩展示例:

1---2---3---B---D---E masterA---C 开发# D 是 C 的精选版本# E 是 A 的精选版本

输出可能如下所示:

match_cherries master dev直流电EA

(A、C、D 和 E 是真实输出中的完整 SHA-1 哈希值)

这告诉我们 C 和 D 代表相同的变化,而 E 和 A 代表相同的变化.和以前一样,除非您还考虑(例如)每个提交的提交日期,否则无法判断每对中的哪一个是第一个".

提交消息比较

如果您的樱桃不是用 -x 采摘的,或者它们是脏的"(有冲突,或添加了其他更改(即使用 --no-commit> 加上暂存额外的更改,或使用 git commit --amend 或其他历史重写"机制)),那么您可能不得不依赖较少的比较提交消息的不太可靠的技术.>

如果您能找到一些可能是提交独有的提交消息,并且不太可能在樱桃选择导致的提交中发生更改,则此技术最有效.最有效的位取决于项目中使用的提交消息的样式.

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

git log --grep='提交消息的唯一部分' dev...master

--grep 的参数实际上是一个正则表达式,因此您可能需要对任何正则表达式元字符 ([]*?.) 进行转义.

如果您不确定哪些分支可能包含原始提交和新提交,您可以使用 --all 如 Jefromi 所示.

If I cherry-pick from multiple branches, is there a simple way to figure out where the commit was coming from (e.g. the sha of the original commit)?

Example:
- at master branch
- cherry pick commit A from a dev branch
- A becomes D at the master branch

Before:

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

After:

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

Is it possible to figure out that D was cherry-picked from A (aside from searching for the commit message)?

Edit:
Although I will go with daggy-fixes (see VonCs answer) I accepted Chris Johnsens answer because it is closer to the actual question. Thanks guys.

解决方案

By default, the information about the original, "cherry" commit is not recorded as part of the new commit.

Record the Source Commit in the Commit Message

If you can force the use of particular workflows/options, git cherry-pick has the -x option:

When recording the commit, append to the original commit message a note that indicates which commit this change was cherry-picked from.

This is obviously useless if you can not rely on the cherry pickers using the option. Also, since the recorded information is just plain text—not an actual reference as far as Git is concerned—even if you use -x, you still have to take steps to make sure that the original commit is kept alive (e.g. is is part of the DAG of a tag or a non-rewinding branch).

git cherry and git patch-id

If you can restrict your search to two particular branches of the history DAG, then git cherry can find both "unpicked" and "picked" cherries.

Note: This command (and the related git patch-id) can only identify conflict-free cherries that were individually picked without extra changes. If there was a conflict while picking the cherry (e.g. you had to slightly modify it to get it to apply), or you used -n/--no-commit to stage extra changes (e.g. multiple cherries in a single commit), or the content of the commit was rewritten after the picking, then you will have to rely on commit message comparison (or the -x information if it was recorded).

git cherry is not really designed to identify the origin of picked cherries, but we can abuse it a bit to identify single cherry pairs.

Given the following history DAG (as in the original poster’s example):

1---2---3---B---D  master
         
          A---C    dev
# D is a cherry-picked version of C

you will see something like this:

% git cherry master dev
+ A
- C
% git cherry dev master
+ B
- D

(A, B, C, and D are full SHA-1 hashes in the real output)

Since we see one cherry (the - lines) in each list, they must form a cherry pair. D was a cherry picked from C (or vice versa; you can not tell by the DAG alone, though the commit dates might help).

If you are dealing with more than one potential cherry, you will have to "roll your own" program to do the mapping. The code should be easy in any language with associative arrays, hashes, dictionaries, or equivalent. In awk, it might look like this:

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

With an extended example that has two picked cherries:

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

The output might look like this:

match_cherries master dev
D C
E A

(A, C, D, and E are full SHA-1 hashes in the real output)

This tells us that C and D represent the same change and that E and A represent the same change. As before, there is no way to tell which of each pair was "the first" unless you also consider (e.g.) the commit dates of each commit.

Commit Message Comparison

If your cherries were not picked with -x, or they are "dirty" (had conflicts, or other changes added to them (i.e. with --no-commit plus staging extra changes, or with git commit --amend or other "history rewriting" mechanism)), then you may have to fall back on less the less reliable technique of comparing commit messages.

This technique works best if you can find some bit of the commit message that is likely to be unique to the commit and is unlikely to have changed in the commit that resulted from the cherry pick. The bit that would work best would depend on the style of commit messages used in your project.

Once you have picked out an "identifying part" of the message, you can use git log to find commits (also demonstrated in Jefromi’s answer).

git log --grep='unique part of the commit message' dev...master

The argument to --grep is actually a regular expression, so you might need to escape any regexp metacharacters ([]*?.).

If you are not sure which branches might hold the original commit and the new commit, you can use --all as Jefromi showed.

这篇关于Git:有没有办法弄清楚提交是从哪里挑选出来的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆