Git:有没有办法弄清楚提交是从哪里挑选出来的?

标签 git version-control

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

例子:
- 在主分支
- 从开发分支挑选提交 A
- A 在 master 分支变成 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 cherry-pick-x选项:

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



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

gitcherry 和 git patch-id

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

备注 :此命令(以及相关的 git patch-id )只能识别没有额外更改的单独采摘的无冲突樱桃。如果在 cherry-pick 时发生冲突(例如,您必须稍微修改它才能应用),或者您使用了 -n/--no-commit要进行额外的更改(例如,单个提交中的多个樱桃),或者在选择后重写提交的内容,那么您将不得不依赖提交消息比较(或 -x 信息,如果已记录)。

git cherry 并不是真正旨在识别 cherry-pick 的来源,但我们可以滥用它来识别单个樱桃对。

给定以下历史 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

举一个有两个 cherry-pick 的扩展示例:
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 展示的那样。

关于Git:有没有办法弄清楚提交是从哪里挑选出来的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2922652/

相关文章:

java - 设置环境变量 Linux

ruby-on-rails - Solidus vs Spree - 应该使用哪个?

emacs - 如何使用组织模式与其他作者合作?

version-control - 有什么地方可以在线托管代码?

svn - `hg pull --rebase` 类似于 `svn update` 吗?

Git rebase 因冲突而失败,但没有冲突

git - 完全取消一个rebase

git - 在git中,是否有一个SHA1指的是路径和修订的组合?

GIT - 如何在所有分支中保持文件通用

version-control - 能否/应该避免频繁 merge (例如通过 rebase )?