【问题标题】:Git log: How to identify (even deleted) topic branch which contains commit?Git日志:如何识别(甚至删除)包含提交的主题分支?
【发布时间】:2016-07-20 11:43:49
【问题描述】:

在某些情况下,查看分支名称会很有帮助(即使已删除) 其中包含我 grepping Git 历史记录时匹配的提交。

问题

例如Unite.vim's repositorygit log --grep 'count to G'的输出为:

commit 7b173ac0ebeadbb1eec17fd12faa1efdcaaa2bb1
Author: Kevin Ballard <kevin@sb.org>
Date:   Sun Jul 26 17:30:15 2015 -0700

    Support passing a count to G

    The mapping for gg supported a count, but the mapping for G did not. Add
    support, and make it avoid redrawing candidates if a count is provided
    that is within the list of current candidates.

本次提交的分支日志为git log --oneline --graph 515b01c~..15db364:

*   15db364 Merge pull request #974 from kballard/better-gg-G-mappings
|\
| * 0b39984 Map <C-Home> and <C-End> as well
| * 79daa61 Teach gg to jump to the first candidate instead of the prompt
| * 7b173ac Support passing a count to G
|/
* 515b01c Fix #973 use buflisted()

如何显示pull request #974 from kballard/better-gg-G-mappings(或 branch 'name-of-the-branch'等)在git log --grep 'count to G的提交描述中?

自己的经历

我发现找到分支名称的可能解决方案是搜索 对于git log --oneline --graph --all 中的SHA。它适用于存在和 也删除了分支,但我必须跟踪图表直到合并提交。

另一个解决方案是git log --grep 'count to G' --source:它显示 在 SHA 之后提交所属的 ref,但它给出了 false 合并分支被删除时的信息(不再存在)。

我发现最后一个有用的是将分支名称存储在提交本身中, 但是如果写到主题会占用太多空间,如果 它在体内,因为--oneline 没有显示它)。如果 提交后分支被重命名,所以我不赞成这样做 解决方案。

问题

是否可以显示每个(可能已删除)分支的名称 提交git log?或者我怎样才能知道呢?

【问题讨论】:

  • 在 Git 中,分支只不过是一个指向提交的命名指针。一个提交在任何时候都可以在 1 到 N 个分支中,并且该组分支可以更改。

标签: git git-branch git-log


【解决方案1】:

作为Jonathon Reinhart noted in a comment,你想要的信息在git中根本不可用,它可以动态变化。在其他一些版本控制系统(例如 Mercurial)中可能的(因为信息是静态的)。我将从我一直在(慢慢地)研究的书的图论章节中粘贴另一个(这一次相当长)。脚注六在这里特别重要。当然,没有人需要阅读任何内容。 :-)

也就是说,git branch --all --contains &lt;commit&gt; 基本上与您在不搜索 reflog 的情况下尽可能接近(如果为已删除的分支保留了 reflog,这将有助于解决您最初的问题,但是 (a) 它们不是并且 (b) reflogs 只会持续多久,无论您将它们配置为持续多久——默认 30 天用于无法访问的提交,90 天用于可访问的提交。)在您的特定情况下,添加和使用 --tags 可能更合适。请注意,标签是永久性的和全球性的,就像 Mercurial 的分支一样,所以在某些方面标签是做到这一点的方式(但 git 的回答是你根本不应该这样做,这并不是一个很好的答案,真的 :- ) )。

解决导致您提出特定问题的相关问题

如果我们放弃您提出的问题(“确定提交的分支”)并返回您最初的问题陈述——我将在此将其改写为“查找提交是否通过拉取请求合并正如日志消息中所记录的那样”- 一个 git 可以解决,尽管您需要编写一些脚本。在这种情况下,我们拥有的是:

  • 提交 ID $commit
  • 它可能(或可能不是)“低于”一个合并提交,其日志消息是“合并拉取请求 #[digits] from [string]”,在从该合并提交的第二个父级开始的链上,一直到这条第二父链重新加入第一父链上的提交流的点,可能就在第一父链上(但最好让它低于该点,事实上它明显更容易 这样做)。

如果$commit实际上在这样一个链上,你想要合并提交的日志消息。

为此,我们需要运行git rev-list 来查找要检查的合并,然后再次运行git rev-list 以查看约束(提交出现在合并的第二父侧)是否适用。以下内容未经优化,甚至未经测试,但显示了这个想法:

git rev-list --merges --all |
while read mhash; do
    msg=$(git log --no-walk --format=%s $mhash)
    case $msg in
    "Merge pull request #"*" from "*) ;;
    *) continue;; # apparently not a pull request
    esac
    if git rev-list ${mhash}^..${mhash}^2 | grep "^${commit}$" >/dev/null; then
        # we found it!
        echo "commit ${commit} is under merge ${mhash}: $msg"
        break
    fi
done

这可能应该被重写为更健壮(例如,如果拉取请求合并消息没有确切的字符串格式)和/或聪明。它还假设拉取请求合并永远不会像章鱼合并那样完成(可以修改使用两个父选择器的特定 git rev-list 命令以避免这种假设;为了清楚起见,它再次意味着更多)。


TL;DR 书摘录 - 随意跳过

我们终于准备好解决 Git 和 Mercurial 之间的一个关键区别。回想一下第 1 章中关于定位、识别和关联提交以及将提交从一个分支移动到另一个分支的较早问题。在 Mercurial 中,提交被永久附加到一个分支上。其中一些提交的入度可能为 0,即,可能位于分支的多叶末端。 Mercurial 称这些为heads4我们通过它们的分支定位它们;它们定义了这些分支的末端。由于每个提交记录其父提交标识符(或两个 ID 在合并的情况下),我们可以使用这些头来到达分支中的每个其他提交(或者实际上,在整个图中)。其他提交的 DAG 路径为我们提供了它们的相对关系。

4在正常的 DAG 中,我们会查看出度而不是入度:出度为 0 的节点是我们借用的正式定义 1 中的叶子。我们的提交 DAG 弧有一切都被颠倒了,所以我们改变了观点。 “叶子”一词来自反转前的观点,但我们在这里继续使用它:Git 将出度为 0 的提交称为“根提交”,因此将另一端称为“叶子”是足够合理的。 Git 通常不会为它们命名,但现在,我们需要一种简洁的方式来谈论它们。

[剪辑]

Git 使用完全不同的方案。提交节点保留分支信息。他们确实保留了它们的父提交标识符,就像 Mercurial 所做的那样,但是找到所有叶子提交需要遍历整个存储库。5 为了加快这一速度,Git 提供了一个通用形式外部参考在与图本身分离的数据结构中。这些外部引用包括 Git 的所有分支(以及 Git 的标签,以及许多其他形式)。

Git 调用分支名称指向的提交 tip 提交。 Git 的分支名称​​不必指向叶子节点,多个外部引用可以指向任何给定的节点(包括叶子节点)。实际上,每个外部引用都会向其节点添加一个传入弧。这为(某些)叶节点提供了可访问性,但也是提交可能在多个分支上的原因。6 这些可访问的叶节点将我们带到其余的可访问节点,就像在 Mercurial 中一样。无法到达的叶子(在添加外部引用后,度数为 0 的节点)可能随时被删除。7

结果是,在绘制 Git DAG 时,我们可能有多个分支名称指向一个提交,并且我们可能有(似乎)有 no 个名称指向它们的提交。稍后我们将对此进行更多说明。现在,让我们用 Git 重新审视图 1.6。我们将分支名称向右移动,每个分支名称指向 到那个树枝的顶端。为了强调提交节点的位置与包含它的分支无关,我们可以在任何方便的地方绘制它们。根节点包含在每个分支中,因此没有理由更喜欢标记为master 的行。为了展示一个提交如何同时成为两个不同的分支提示,或者一个分支提示提交可能发生在提交链的中间,我们添加了另外两个 Git 分支名称:A 指向与 master 相同的提交,而B 指向release-v2 branch 中间的一个提交。 (这些名称是为了说明,而不是立即有用,尽管A 将是开始开发尚未准备好成为master 一部分的新功能的好地方。)

[这里剪得很大——请注意,下一点包含一些意见,我将来可能会重新修改它。这两种立场都有优点:Git 凭借其轻量级、短暂的分支系统获得了很大的灵活性,但在此过程中肯定会失去一些东西。]

一些用户争辩说,这证明 Mercurial 优于 Git,因为我们总是可以跟踪到特定分支的单个提交。出于同样的原因,一些用户认为这证明了相反的情况,并指出像“commit 1417ae2 was made on hotfix”这样的声明在几年后没有(甚至是负面的)价值。我有点遗憾地同意后一组,但发现这首先使 Git 的使用更加困难和容易出错,因为用户对分支的定义模糊不清,关于提交 DAG 的概念模糊(如果有的话),并且不希望必须一直表达子集(见下一节)。 Mercurial的分支最初是恰到好处,但随着时间的推移,分支名称变得非常混乱。 Mercurial 的分支关闭功能,它隐藏了正常使用的名称,最初可以解决问题,但隐藏的分支名称仍然存在:您必须发明一个新的(通常相当尴尬)名称或重新打开旧分支,这是旧分支突然有负值的地方。


5有几个维护 git 命令可以执行此操作,它们需要一些时间才能在更大的存储库中运行。不过,用户通常不需要自己运行这些。

6最好将提交包含在一些分支中。 Git 有带有--contains 选项的命令,可以查看哪些分支和/或标签包含特定的提交。

7Git 的垃圾收集器或 GC 执行删除操作。它遵守保护项目一段时间的规则,直到它们被引用或过期,所以“在任何时候”并不完全正确。您也可以禁用自动 GC。

【讨论】:

    猜你喜欢
    • 2014-03-23
    • 1970-01-01
    • 2023-03-11
    • 2020-09-08
    • 1970-01-01
    • 2022-10-15
    • 1970-01-01
    • 1970-01-01
    • 2015-11-16
    相关资源
    最近更新 更多