ref^
指的是之前的提交ref
,那之后 的提交又ref
如何呢?
例如,如果我git checkout 12345
如何签出下一个提交?
谢谢。
PS是的,无论如何git都是DAG节点指针结构树。 我如何在此之后找到提交?
git children-of
”!
ref^
指的是之前的提交ref
,那之后 的提交又ref
如何呢?
例如,如果我git checkout 12345
如何签出下一个提交?
谢谢。
PS是的,无论如何git都是DAG节点指针结构树。 我如何在此之后找到提交?
git children-of
”!
Answers:
要列出所有提交,从当前提交开始,然后列出其子进程,依此类推-基本上是标准的git log,但是随着时间的流逝,请使用类似
git log --reverse --ancestry-path 894e8b4e93d8f3^..master
其中894e8b4e93d8f3是您要显示的第一个提交。
HEAD^
了894e8b4e93d8f3^
。
...
,^..
静默失败
fatal: unrecognized argument: --ancestry-path
git版本1.7.1
刚刚出版(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
则将是第一个父级。
即:第一个父对象是您合并时所在的分支,第二个父对象是您合并到的分支上的提交。
git rev-list --children
当然看起来像我想要的,但它不是DWIM。它似乎列出了所有的父母及其子女。我想我可以列出所有内容并通过它们进行解析...等等,但是有一些东西。
git rev-list --children
是的,不是为了列出孩子,而是为了列出父母和孩子 ……您总是需要分析。
$ git children0of 9dd5932
fatal: No annotated tags can describe '71d7b5dd89d241072a0a078ff2c7dfec05d52e1f'.
However, there were unannotated tags: try --tags.
您得到什么输出?
git-children-of
是它使用git describe尝试将SHA格式化为人类可读的格式,这可能会因@TomHale的错误而失败,并且v1.0.4-14-g2414721
如果您期望使用SHA,则给出的结果会令人困惑。用一个简单的替换它就echo
可以使它成为一个很好的工具,谢谢!
我发现的是
git rev-list --ancestry-path commit1..commit2
我将其设置commit1
为当前提交和commit2
当前头部。这会向我返回所有构建在commit1
和之间的路径的提交的列表commit2
。
输出的最后一行是commit1的子代(在commit2的路径上)。
| tail -1
即可生下孩子。
我知道你的意思。对于上一次提交有足够的语法,而对下一次提交则没有语法,这是令人沮丧的。在复杂的历史中,“下一次提交是什么”的问题变得相当棘手,但随后在复杂的合并中,同样的难度又出现了“先前的”提交。在简单的情况下,在具有线性历史记录的单个分支内(即使对于某些有限数量的提交,甚至在本地也是如此),向前和向后前进都很好并且很有意义。
但是,真正的问题是未引用子提交,它仅是一个向后链接的列表。查找子提交需要进行搜索,这并不算太糟,但git可能不想将其放入refspec逻辑中。
无论如何,我之所以提出这个问题,是因为我只是想向前迈进一次历史,一次提交,进行测试,有时您必须向前而不是向后前进。好吧,经过更多的思考,我想出了这个解决方案:
在您所在的位置之前选择一个提交。这可能是分支头。如果您位于分支〜10,则依次单击“ git checkout分支〜9”,“ git checkout分支〜8”,“ git checkout分支〜7”,依此类推。
如果需要,在脚本中减少数字应该非常容易。比解析git rev-list容易得多。
BRANCH=master; git co $BRANCH~$[ $(git rev-list HEAD..$BRANCH | wc -l) - 1 ]
”您必须去一个分支,没有办法解决。
根据@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
为提交式菜单,以仅显示该提交的祖先的子级,换句话说,仅显示“在给定提交的方向上”的子级。这可以帮助您将输出范围从许多孩子缩小到一个孩子。
没有唯一的“下一次提交”。由于Git中的历史记录是DAG,而不是一行,因此许多提交可以具有一个公共父级(分支),并且提交可以具有多个父级(合并)。
如果您有一个特定的分支,则可以查看其日志并查看哪些提交将当前分支列为其父分支。
<rev>^
是“父提交”(合并提交的“第一父提交”)。
如果您没有考虑特定的“目标”提交,而是想查看可能在任何分支上的子提交,则可以使用以下命令:
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)。
${COMMIT}
而言,不需要,但您可以$(git rev-parse HEAD)
改用
${COMMIT}
。
(这是对一个重复问题的回答。我做了一些简单的编辑来清理它。)
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 J
,G
和I
,F
并且H
按某种顺序。随着--ancestry-path
我们的淘汰H
和I
:他们不是的后代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 1
到git rev-list
命令中也很诱人--reverse
。别做!这使得git rev-list
停车后步行一步回来,然后反向访问提交的(一个条目)列表。因此,这<id2>
每次都会产生。
请注意,带有“钻石”或“苯环”图片段:
I--J
/ \
...--H M--... <-- last
\ /
K--L
移动一个承诺“前进”从H
朝last
将让你无论是 I
或 K
。您对此无能为力:两次提交都向前迈了一步!然后,如果您从生成的提交开始并进行下一步,那么您现在将遵循开始的任何路径。
解决方法是避免一次只移动一个步骤,而不会陷入与路径相关的链中。相反,如果您打算访问整个祖先路径链,则在进行其他操作之前,请完整列出链中所有提交的列表:
git rev-list --topo-order --reverse --ancestry-path A..B > /tmp/list-of-commits
然后,一次访问此列表中的每个提交,您将获得整个链。该--topo-order
会确保你打I
-和- J
的顺序,和K
-和- L
的顺序(虽然有没有简单的方法来预测你是否会在KL对之前或之后做IJ对)。
我有这个别名 ~/.gitconfig
first-child = "!f() { git log --reverse --ancestry-path --pretty=%H $1..${2:-HEAD} | head -1; }; f"
f()
?它必须head -1
是第一个孩子,否则它将仅报告HEAD。
f()
。是的,这head -1
是一个勇敢的猜测。
nextref = "!f() { git log --reverse --ancestry-path --pretty=%H $1..HEAD | head -${2:-1} | tail -1; }; f"
这样你就可以选择如何遥遥领先,可选
我设法通过以下方式找到下一个孩子:
git log --reverse --children -n1 HEAD (where 'n' is the number of children to show)
如果子提交全部在某个分支上,则可以使用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'
将生成一行包含该提交的所有子项的行,大概是是否涉及分支。
每个提交都存储一个指向其父级的指针(如果是merge(标准)提交,则为父级)。
因此,没有办法指向父项提交的子项(如果有)。
这篇文章(http://www.jayway.com/2015/03/30/using-git-commits-to-drive-a-live-coding-session/#comment-282667)显示了一种简洁的方法您可以在提交堆栈的末尾创建一个定义良好的标签。本质上
git config --global alias.next '!git checkout `git rev-list HEAD..demo-end | tail -1`'
,“ demo-end”是最后一个标签。
现有答案假定您有一个包含要查找的提交的分支。
就我而言,git rev-list --all
由于没有分支包含该内容,因此我未在寻找该提交。
我最终gitk --reflog
手动浏览。
如果即使在引用日志中也找不到您的提交,请尝试以下任一方法:
git fsck --full
列出悬空的提交(即不在任何分支中),或者git fsck --lost-found
使引用指向悬空的引用将在其他答案中应用技巧。