如何在git中找到下一个提交?(裁判的子女)


Answers:


185

要列出所有提交,从当前提交开始,然后列出其子进程,依此类推-基本上是标准的git log,但是随着时间的流逝,请使用类似

git log --reverse --ancestry-path 894e8b4e93d8f3^..master

其中894e8b4e93d8f3是您要显示的第一个提交。


3
对于原来的问题的特定情况下,刚刚替补HEAD^894e8b4e93d8f3^
索伦Løvborg

2
也许添加--oneline是更好的简短输出结果。
firo

1
我需要使用...^..静默失败
TankorSmash 2015年

1
进入fatal: unrecognized argument: --ancestry-pathgit版本1.7.1
2015年

6
仅当master位于当前提交的祖先路径上时,这才起作用。请参阅我的答案的第二个代码片段,以获取在所有情况下均适用的解决方案。
汤姆·黑尔

37

刚刚出版(2013年11月)的哈德逊(现为詹金斯)川口浩辅的创作者:
kohsuke / git-children-of

给定一个提交,找到该提交的直接子级。

#!/bin/bash -e
# given a commit, find immediate children of that commit.
for arg in "$@"; do
  for commit in $(git rev-parse $arg^0); do
    for child in $(git log --format='%H %P' --all | grep -F " $commit" | cut -f1 -d' '); do
      git describe $child
    done
  done
done

该线程所示,在基于DAG(有向无环图)表示的历史记录的VCS中,没有“一个父”或“一个子”。

        C1 -> C2 -> C3
      /               \
A -> B                  E -> F
      \               /
        D1 -> D2 ----/

提交的顺序是通过“ topo-order”或“ date-order”完成的(请参阅GitPro书

但是从Git1.6.0开始,您可以列出提交的子代。

git rev-list --children
git log --children

注意:对于父提交,您会遇到相同的问题,后缀^为修订版参数,表示该提交对象的第一个父提交。^<n>装置<n>第母体(即rev^ 等同于rev^1)。

如果您在分支机构foo并发出“ git merge bar”,foo则将是第一个父级。
即:第一个父对象是您合并时所在的分支,第二个父对象是您合并到的分支上的提交。


6
git rev-list --children当然看起来像我想要的,但它不是DWIM。它似乎列出了所有的父母及其子女。我想我可以列出所有内容并通过它们进行解析...等等,但是有一些东西。
Schwern 2010年

@Schwern:git rev-list --children是的,不是为了列出孩子,而是为了列出父母和孩子 ……您总是需要分析。
VonC'2

我在有两个孩子的一次提交上尝试了该代码:$ git children0of 9dd5932 fatal: No annotated tags can describe '71d7b5dd89d241072a0a078ff2c7dfec05d52e1f'. However, there were unannotated tags: try --tags. 您得到什么输出?
汤姆·黑尔

@TomHale我现在无法测试,但是提出一个新问题(使用OS和Git版本),这样每个人都可以测试。
VonC

1
唯一的问题git-children-of是它使用git describe尝试将SHA格式化为人类可读的格式,这可能会因@TomHale的错误而失败,并且v1.0.4-14-g2414721如果您期望使用SHA,则给出的结果会令人困惑。用一个简单的替换它就echo可以使它成为一个很好的工具,谢谢!
Nickolay

18

我发现的是

git rev-list --ancestry-path commit1..commit2

我将其设置commit1为当前提交和commit2当前头部。这会向我返回所有构建在commit1和之间的路径的提交的列表commit2

输出的最后一行是commit1的子代(在commit2的路径上)。


3
因此,只需添加| tail -1即可生下孩子。
杰西·格里克

8

我知道你的意思。对于上一次提交有足够的语法,而对下一次提交则没有语法,这是令人沮丧的。在复杂的历史中,“下一次提交是什么”的问题变得相当棘手,但随后在复杂的合并中,同样的难度又出现了“先前的”提交。在简单的情况下,在具有线性历史记录的单个分支内(即使对于某些有限数量的提交,甚至在本地也是如此),向前和向后前进都很好并且很有意义。

但是,真正的问题是未引用子提交,它仅是一个向后链接的列表。查找子提交需要进行搜索,这并不算太糟,但git可能不想将其放入refspec逻辑中。

无论如何,我之所以提出这个问题,是因为我只是想向前迈进一次历史,一次提交,进行测试,有时您必须向前而不是向后前进。好吧,经过更多的思考,我想出了这个解决方案:

在您所在的位置之前选择一个提交。这可能是分支头。如果您位于分支〜10,则依次单击“ git checkout分支〜9”,“ git checkout分支〜8”,“ git checkout分支〜7”,依此类推。

如果需要,在脚本中减少数字应该非常容易。比解析git rev-list容易得多。


虽然有用,但找不到下一个提交。它走向当前的提交。
Schwern

1
那么,我想您可以这样做:“ BRANCH=master; git co $BRANCH~$[ $(git rev-list HEAD..$BRANCH | wc -l) - 1 ]”您必须去一个分支,没有办法解决。
冯特拉普

8

两个实际答案:

一个小孩

根据@Michael的回答,我在中修改了child别名.gitconfig

在默认情况下,它可以正常工作,并且用途广泛。

# Get the child commit of the current commit.
# Use $1 instead of 'HEAD' if given. Use $2 instead of curent branch if given.
child = "!bash -c 'git log --format=%H --reverse --ancestry-path ${1:-HEAD}..${2:\"$(git rev-parse --abbrev-ref HEAD)\"} | head -1' -"

默认情况下,通过将祖先向当前分支的尖端移动一步(除非将另一个commit-ish作为第二个参数给出),来赋予HEAD的孩子(除非给出了另一个commit-ish参数)。

如果要使用简短的哈希表形式,请使用%h代替%H

多个孩子

使用分离的HEAD(没有分支)或获取所有孩子而不管分支如何:

# For the current (or specified) commit-ish, get the all children, print the first child 
children = "!bash -c 'c=${1:-HEAD}; set -- $(git rev-list --all --not \"$c\"^@ --children | grep $(git rev-parse \"$c\") ); shift; echo $1' -"

更改$1$*打印所有的孩子们。

您也可以更改--all为提交式菜单,以仅显示该提交的祖先的子级,换句话说,仅显示“在给定提交的方向上”的子级。这可以帮助您将输出范围从许多孩子缩小到一个孩子。


7

没有唯一的“下一次提交”。由于Git中的历史记录是DAG,而不是一行,因此许多提交可以具有一个公共父级(分支),并且提交可以具有多个父级(合并)。

如果您有一个特定的分支,则可以查看其日志并查看哪些提交将当前分支列为其父分支。


37
按照这种逻辑,也没有“先前的提交”,但是有很多语法可以获取父对象。
Schwern 2010年

7
@Schwern:也没有“先前的提交”;<rev>^是“父提交”(合并提交的“第一父提交”)。
JakubNarębski10年

6

我尝试了许多不同的解决方案,但没有一个对我有用。不得不拿出我自己的。

查找下一个提交

function n() {
    git log --reverse --pretty=%H master | grep -A 1 $(git rev-parse HEAD) | tail -n1 | xargs git checkout
}

查找先前的提交

function p() {
    git checkout HEAD^1
}

6

如果您没有考虑特定的“目标”提交,而是想查看可能在任何分支上的子提交,则可以使用以下命令:

git rev-list --children --all | grep ^${COMMIT}

如果要查看所有子代和孙子代,则必须rev-list --children递归使用,如下所示:

git rev-list --children --all | \
egrep ^\($(git rev-list --children --all | \
           grep ^${COMMIT} | \
           sed 's/ /|/g')\)

仅提供孙子代的版本将使用更复杂的sed和/或cut。)

最后,您可以将其输入log --graph命令以查看树结构,如下所示:

git log --graph --oneline --decorate \
\^${COMMIT}^@ \
$(git rev-list --children --all | \
  egrep ^\($(git rev-list --children --all | \
             grep ^${COMMIT} | \
             sed 's/ /|/g')\))

注意:以上命令均假设您已将shell变量设置为${COMMIT}您感兴趣的子提交的某个引用(分支,标签,sha1)。


2
这回答了我不知道如何为谷歌和stackoverflow制定公式的问题,但是试图问这个问题。感谢您主动认识到这一需求
Tommy Knowlton

对我${COMMIT}而言,不需要,但您可以$(git rev-parse HEAD) 改用
Radon8472

抱歉,添加了有关的注释${COMMIT}
马特·麦克亨利

5

(这是对一个重复问题的回答。我做了一些简单的编辑来清理它。)

Git的所有内部箭头都是单向的,向后指向。因此,没有前进的简短便捷语法:这是不可能的。

可能的“反箭头移动”,但做到这一点是令人惊讶的方式,如果你以前没有见过它,然后明显之后。假设我们有:

A <-B <-C <-D <-E   <-- last
        ^
        |
         \--------- middle

使用middle~2跟随箭头两次,从C返回到A。那么我们如何从C转到D?答案是:我们从E使用名称开始last,然后向后工作直到到达middle记录沿途访问的点。然后,我们只要将据我们希望的方向last:移动一步D,或两个E

当我们有分支机构时,这尤其重要:

          D--E   <-- feature1
         /
...--B--C   <-- master
         \
          F--G   <-- feature2

下一步是哪一个提交C?在您添加到问题之前,没有正确的答案:朝Feature___方向(填写空白)。

要枚举C(不包括C)本身与,例如之间的提交G,我们使用:

git rev-list --topo-order --ancestry-path master..feature2

这样--topo-order可以确保即使存在复杂的分支和合并,这些提交也可以按照拓扑排序的顺序出现。仅当链不是线性时才需要。该--ancestry-path约束意味着,当我们从进行反向操作时feature2,我们仅列出已将提交C作为自己祖先之一的提交。也就是说,如果图形(或无论如何相关图)实际上看起来像这样:

A--B--C   <-- master
 \     \
  \     F--G--J   <-- feature2
   \         /
    H-------I   <-- feature3

表单的简单请求feature2..master枚举了commits JGIF并且H按某种顺序。随着--ancestry-path我们的淘汰HI:他们不是的后代C,只是的后代A。随着--topo-order我们确保实际的枚举顺序J,然后G,然后F

git rev-list命令将这些哈希ID溢出到其标准输出中,每行一个。要向方向前feature2进一步,我们只需要最后一行。

这是可能的(和诱人的和有用的)添加--reverse,使git rev-list打印出提交相反的顺序生成它们之后。确实可以,但是如果您在这样的管道中使用它:

git rev-list --topo-order --ancestry-path --reverse <id1>...<id2> | head -1

为了仅获取“沿id2方向的下一个提交”,并且提交列表非常长,该git rev-list命令在尝试写入时将得到一个中断的管道,该管道head已停止读取其输入并退出。由于外壳通常会忽略断线错误,因此大多数情况下都可以使用。只要确保它们在您的用法中被忽略即可。

与一起添加-n 1git rev-list命令中也很诱人--reverse。别做!这使得git rev-list停车后步行一步回来,然后反向访问提交的(一个条目)列表。因此,这<id2>每次都会产生。

重要注意事项

请注意,带有“钻石”或“苯环”图片段:

       I--J
      /    \
...--H      M--...  <-- last
      \    /
       K--L

移动一个承诺“前进”从Hlast将让你无论是 I K。您对此无能为力:两次提交都向前迈了一步!然后,如果您从生成的提交开始并进行下一步,那么您现在将遵循开始的任何路径。

解决方法是避免一次只移动一个步骤,而不会陷入与路径相关的链中。相反,如果您打算访问整个祖先路径链,则在进行其他操作之前,请完整列出链中所有提交的列表:

git rev-list --topo-order --reverse --ancestry-path A..B > /tmp/list-of-commits

然后,一次访问此列表中的每个提交,您将获得整个链。该--topo-order会确保你打I-和- J的顺序,和K-和- L的顺序(虽然有没有简单的方法来预测你是否会在KL对之前或之后做IJ对)。


在添加到问题之前,没有正确的答案:朝Feature___的方向前进 ”这是一个很好的观点。感谢您的回答。
Schwern

4

我有这个别名 ~/.gitconfig

first-child = "!f() { git log  --reverse --ancestry-path --pretty=%H $1..${2:-HEAD} | head -1; }; f"


是什么f()?它必须head -1是第一个孩子,否则它将仅报告HEAD。
Xerus

@Xerus因为它使用了一些“复杂的” shell语法,并且如果不使用git,它将无法识别f()。是的,这head -1是一个勇敢的猜测。
弱化了

真好!调整了雷到了:nextref = "!f() { git log --reverse --ancestry-path --pretty=%H $1..HEAD | head -${2:-1} | tail -1; }; f"这样你就可以选择如何遥遥领先,可选
Z. Khullah

2

我设法通过以下方式找到下一个孩子:

git log --reverse --children -n1 HEAD (where 'n' is the number of children to show)

1
对我来说,这不是显示第一个孩子,而是显示当前的提交
Radon8472 '19

2

如果子提交全部在某个分支上,则可以使用gitk --all commit^..,其中“提交”是标识提交的内容。例如,如果提交的缩写SHA-1是c6661c5,则键入gitk --all c6661c5^..

您可能需要在gitk的“ SHA1 ID:”单元格中输入完整的SHA-1。您将需要完整的SHA-1,对于此示例,可以通过以下方式获取git rev-parse c6661c5

或者,git rev-list --all --children | grep '^c6661c5883bb53d400ce160a5897610ecedbdc9d'将生成一行包含该提交的所有子项的行,大概是是否涉及分支。


0

每个提交都存储一个指向其父级的指针(如果是merge(标准)提交,则为父级)。

因此,没有办法指向父项提交的子项(如果有)。


提交不能存储指向其子级的指针,因为可以在以后添加其他子级提交(分支点)。
JakubNarębski10年

@Jakub我不太喜欢。以后不能添加吗?
Schwern 2010年

1
雅库布:那正是我说的话。“每个提交只存储指向其父级的指针。”
Lakshman Prasad

@Schwern:git中的提交是不可变的(这很有责任感),因此指向儿童的指针不会“稍后添加”。原因之一是提交的标识符(例如在“父”链接中使用)取决于提交内容;这是分布式系统中唯一没有中央编号授权的解决方案。提交的“子级”也取决于您拥有的分支,这又因存储库而异(并且每个存储库中的提交都相同)。
JakubNarębski2010年

4
@becomingGuru我不赞成。可能是正确的,但不能回答我的问题。问题是“如何在git中找到下一个提交?” 它不是“ git commit是否存储指向其子代的指针?”
Schwern 2010年


0

现有答案假定您有一个包含要查找的提交的分支。

就我而言,git rev-list --all由于没有分支包含该内容,因此我未在寻找该提交。

我最终gitk --reflog手动浏览。

如果即使在引用日志中也找不到您的提交,请尝试以下任一方法:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.