Git log:如何识别(甚至删除)包含提交的主题分支?

时间:2016-03-31 20:34:59

标签: git git-branch git-log

在某些情况下,查看分支名称会很有帮助(即使它已删除) 当我贪图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提交?或者我怎么能找到它?

1 个答案:

答案 0 :(得分:1)

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

那就是说,git branch --all --contains <commit>基本上尽可能接近你没有搜索reflogs(如果为删除的分支保留reflogs,这将有助于你原来的问题,但是(a)他们不是和( b)reflog只持续很长时间你将它们配置为无论如何 - 对于无法到达的提交默认为30天,对于可到达的提交为90天。)在您的特定情况下,添加和使用--tags可能更合适。请注意,标签是永久性的和全局的,就像Mercurial的分支一样,所以在某些方面标签就是这样做的方式(但是git的答案是你不应该这样做,这不是那个非常好的答案,真的:-))。

解决导致您询问具体问题的相关问题

如果我们放弃你提出的问题(&#34;确定提交提交的分支&#34;)并回到原来的问题陈述 - 我将在此重述为&#34;查找提交是否通过日志消息中记录的pull请求合并&#34; - 一个git可以解决,尽管您需要编写一些脚本。在这种情况下,我们拥有:

  • 提交ID $commit
  • 可能(或可能不是)&#34;以下&#34;一个合并提交,其日志消息是&#34;合并提取请求#[digits]来自[string]&#34;,从该合并提交的第二个父项开始的链上,直到这个第二个父链的点在第一个父链上重新加入提交流,可能就在第一个父级链接上(但是允许它低于这一点会很好,事实上它显然更容易这样做。)

如果$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称这些 4 我们通过他们的分支找到它们;他们定义了那些分支的末端。由于每个提交都记录其父提交标识符(或两个ID) 在合并的情况下,我们可以使用这些头来到达分支中的每个其他提交(或者实际上,在整个图中)。其他提交的DAG路径为我们提供了相对关系。

4 在正常的DAG中,我们会查看out-degree而不是in-degree:out-degree 0的节点是我们借用的形式定义1中的叶子。我们的提交DAG弧有一切都被逆转了,所以我们改变了观点。 “leaf”这个词来自pre-reversal视图,但我们继续在这里使用它:Git调用out-degree 0的提交“root commit”,因此调用另一端“离开”是合理的。 Git通常不会为它们添加术语,但就目前而言,我们需要一种简洁的方式来讨论它们。

[剪断]

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

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

结果是,在绘制Git DAG时,我们可能有多个分支名称指向一个提交,我们可能会提交(似乎) no 名称指向它们。我们稍后会详细说明。现在,让我们重新考虑图1.6并考虑Git。我们将分支名称移到右侧,每个分支名称都指向 到那个分支的尖端。为了强调提交节点的位置与哪个分支包含它几乎没有关系,我们可以在任何方便的地方绘制它们。根节点包含在每个分支中,因此没有理由更喜欢标记为master的行。为了显示一个提交如何同时是两个不同的分支提示,或者在提交链中可能发生分支提示,我们再添加两个Git分支名称:A指向与{{{0}相同的提交。 1}},master指向B中间的提交。 (这些名称是说明性的,而不是立即有用,但release-v2 branch将是开始开发尚未准备好成为A一部分的新功能的好地方。)

Figure 2.9: Git variant of Figure 1.6.

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

有些用户认为这证明Mercurial优于Git,因为我们总能跟踪特定分支的个别提交。一些用户认为,出于同样的原因,这证明了相反的情况,并指出像master上的“提交1417ae2”这样的陈述在几年之后没有(甚至是否定的)价值。我有点遗憾地同意后一组,但发现这使得Git的使用起初更加困难且容易出错,因为用户有模糊定义的分支概念,模糊(如果有的话)关于提交DAG的概念,并且不想要必须一直表达子集(见下一节)。 Mercurial的分支最初是正确的,但随着时间的推移,分支名称变得非常混乱。 Mercurial的分支关闭功能,隐藏了正常使用的名称,最初起作用,但隐藏的分支名称仍然存在:您必须创建一个新的(通常相当尴尬)名称或重新打开旧分支,这是老分支突然有负值。

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

6 可能更好的想法包含在某些分支中的提交。 Git具有hotfix选项的命令,以查看哪些分支和/或标记包含特定提交。

7 Git的垃圾收集器或GC进行删除。它遵守保护项目一段时间的规则,直到它们被引用或老化,因此“在任何时候”都不是真的。您也可以禁用自动GC。