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

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

问题描述

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

例子:

- 在主分支处

- 樱桃选择从开发分支处提交A

- A在主分支处变为D



之前:

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

After:

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

是否有可能找出D是从A挑选的(除了搜索提交消息)?

编辑:

尽管我会用狡猾的修正(参见VonCs答案),但我接受了Chris Johnsens的回答,因为它更接近实际问题。谢谢你们。

解决方案

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

在提交消息中记录源提交



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


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


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


git樱桃 git patch-id



如果您可以限制搜索到历史DAG的两个特定分支, href =http://www.kernel.org/pub/software/scm/git/docs/git-cherry.html =noreferrer> git cherry 可以找到挑剔和挑选樱桃。

注意:此命令(和相关的 git patch-id )免费的樱桃,不经过额外的更改而单独挑选。如果在挑选樱桃时发生冲突(例如,您必须稍微修改它才能使用樱桃),或者您使用 -n / - -no-commit 来执行额外的更改(例如,在一次提交中多个樱桃),或者在提交后重写了提交的内容,那么您将不得不依赖于提交消息比较 -x 信息)。



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



鉴于以下历史DAG(如原始海报的示例):

  1 --- 2 --- 3 --- B --- D主
\
A --- C dev
#D是C

你会看到类似这样的内容:

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


$ b

由于我们在每个列表中看到一个樱桃( - 行),它们必须形成一个樱桃对。 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 [ (b> 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是C
#E的樱桃选择版本,是A
的挑选版本

输出可能如下所示:

  match_cherries master dev 
DC $ b $ (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 的参数实际上是一个正则表达式,所以您可能需要转义任何正则表达式元字符( [] * ?. \ )。

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


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天全站免登陆