如何在分支创建点或之后列出包含给定提交的分支

时间:2018-08-30 16:53:06

标签: git version-control branch revision-history

我意识到这个问题看起来很像1419623,但有所不同。

想象一下下面的树:

master
|
N
M
H-J-K-L-O  -- branch2
E  
C-D-F-G-I  -- branch1
B
A

我需要一种方法来确认提交C,D,F,G和我都属于branch1。 对于提交D,F,G,I git branch --contains来说效果很好。但是,对于提交C,它将列出masterbranch1branch2,因为它们都确实包含了它。有什么方法可以只列出在分支创建时或分支创建后具有给定提交的分支?

也就是说,我需要一些行为如下:

$ git some-command B
master
$ git some-command C
branch1
master
$ git some-command F
branch1
$ git some-command H
branch2
master
$ git some-command L
branch2
$ git some-command M
master

有没有?

3 个答案:

答案 0 :(得分:2)

没有办法做到这一点。 git不跟踪分支创建时间。在存储的物理级别上,C与三个分支之间的关系没有任何区别。

答案 1 :(得分:1)

在Git中,分支机构不存储有关何时,如何创建或谁创建它们的任何元数据。它们只是提交的指针。

实际上,存储该信息没有任何意义。例如,这是一个典型的工作流程:

git checkout master
// Make changes and commit A (on master)
git checkout -b my-branch
// Make changes and commit B (on my-branch)
git checkout master
// Make changes and commit C (on master)

...生成一个提交图,如:

* C  master
|
| * B  my-branch
|/
* A

...但是我无法告诉您我不小心在master而不是分支上提交了多少次。解决此问题的一种好方法是检出您所在的新分支,然后将master重设回此提交之前的位置。像这样:

git checkout master
// Make changes and commit A (on master)
// Make changes and commit B (on master)
// Oops... I meant to commit B on a branch
git checkout -b my-branch
git checkout master
git reset master^
// Make changes and commit C (on master)

这两个都生成相同的提交图,但是对每个分支“属于”的提交将有不同的解释(具体来说,my-branch既不包含A也不包含B,因为分支是在每个提交之后创建的。)

答案 2 :(得分:0)

到目前为止,您有几个不错的答案,但是我认为有必要指出,考虑到您的问题表达方式,该命令将不得不为提交BC打印多个分支名称。

如果您愿意生活在Git reflogs 的限制内(默认情况下,默认为90天),那么我认为还有另一种论坛可以满足您的需求。

让我按照自己喜欢的方式重新绘制图形,该图形从左(较早的提交)到右(较早的提交),其名称在右边缘:

        D--F--G--I   <-- branch1
       /
A--B--C--E--H--M--N   <-- master
             \
              J--K--L--O   <-- branch2

创建branch1时,您可能是这样的:

$ git checkout master   # which resolves to commit `C`, because ...

...,因为此时图形如下所示:

A--B--C   <-- master (HEAD)

现在运行:

$ git checkout -b branch1

使图看起来像这样:

A--B--C   <-- master, branch1 (HEAD)

也就是说,现在存在两个分支名称,它们都标识提交C 。由于使用了HEADbranch1的名称目前已附加到git checkout -b

此时,您:

... do some work ...
$ git commit -m message   # which creates commit `D`

给予:

        D   <-- branch1 (HEAD)
       /
A--B--C   <-- master

随着您提交更多的提交,它们会添加到附加了HEAD的位置,因此这会导致branch1累积提交。

您的问题包括以下措辞:

  

是否有任何方法仅列出在分支创建时或分支创建后具有给定提交的分支?

遇到两个问题:分支实际上没有“创建”,并且提交具有-或 containing ,实际上-每个提交都可以通过他们的尖端向后。

我们可能要问的是:对于每个提交,哪个分支reflog中有直接引用该提交的条目?假设没有reflog值已过期并被删除,我们会发现,点-branch1存在并指向提交D-提交D仅在branch1的引用日志中,提交C在{{1}中}和branch1的引用日志,提交master仅在B的引用日志中,而提交master仅在A的引用日志中。

后来,当我们通过masterA提交O时,我们会发现H就像C:在{{1} }和master。其余提交仅在一个引用日志中。

因此,我们将从询问基于reflog的问题开始。然后,对于出现在多个引用日志中的提交,我们将声明这样的提交与“创建的引用日志中的以后”更为“一致”。这是因为在创建提交branch2本身时创建了具有C作为master提交的reflog条目,因此reflog条目具有更早的日期。但是创建C并指向提交branch1时,实际上是将C提交到C中。

请注意,这种表述也有一个缺陷-当然,当reflog条目过期时会出现这种缺陷。假设我们现在运行:

branch1

并在git checkout -b branch3 <hash-of-C> 上进行新提交?我们的图现在是:

branch3

提交 ,--P <-- branch3 (HEAD) / | D--F--G--I <-- branch1 |/ A--B--C--E--H--M--N <-- master \ J--K--L--O <-- branch2 现在处于三个引用中:一个用于C,一个用于master,另一个用于branch1。 (branch3的完整引用日志由“提交branch3,然后提交P”组成。) latest C:通过附加{{ 1}}作为branch3的基础,我们已经有效地“窃取”了C的提交branch3

如果您不喜欢这样做,那么显而易见的替代方法是将提交C分配给包含它的最早 reflog,即branch3。但是现在:

C

master,而不是git who-owns <hash-of-C> ,这不是您要的。虽然很容易做任何一个。这是未经测试的伪代码框架,可以帮助您入门:

master

如果此脚本以branch1的身份位于您的#! /bin/sh # git-who-owns: pick a branch to "own" a commit . git-sh-setup case $# in 0) die "usage: git who-owns <commit> ...";; esac who-owns() { local b hash hash=$(git rev-parse $1^{commit}) || return 1 for b in $(git for-each-ref --format='%(refname:short) refs/heads); do git reflog --no-abbrev $b | awk '$1 == "$hash"' done } status=0 for arg do who-owns "$arg" || status=1; done exit $status 中,则运行$PATH将打印出所有匹配的引用日志。

还有一个更大的缺陷:如果一个提交可以属于一个或多个分支,但是通过诸如git-who-owns之类的en-masse操作而后接git who-owns <commit-specifier>而引入,则其哈希ID将不在任何更新。您可以将上述内容与git fetch操作混合使用,以将此类“中间”提交分配给分支。

(但是,一般而言,这个想法不太可行。我不会在此花费很多时间。相反,当您要生成提交的有界列表时,在边界提交上放一个标记(例如标签) 。然后git merge会为您提供所需的提交ID。这通常是用--contains拼写的,例如git rev-list branch-name ^marker。)