获取给定提交的所有子提交列表

13

我想在给定提交的所有子提交上运行git filter-branch。这似乎不是一项容易的任务,因为没有办法告诉git rev-list仅返回特定提交的子提交。使用..语法是不可行的,因为它还会包括该范围内任何合并的父提交。我错过了什么吗?

编辑

为了澄清:我有一个名为base的分支,已多次合并到derivative中。我想列出并最终在仅从最近提交派生的提交上运行filter-branch。我还想列出其他分支上类似的提交。

(简化后的)情况如下图所示(derivative 是左侧的分支):

$ git rev-list --graph --oneline base derivative
*   f16fd151b374b2aeec8b9247489c518a6347d001 merged in the latest from the base branch
|\
| * 564d795afb63eab4ffe758dbcd726ca8b790f9f6 spelling correction
* |   2f2ed5f1d429492e1491740e30be5a58ec20af21 snogg before flarg
|\ \
| |/
| * 0c520ea33ef57b30846b122781d41fcef5e62f9b now with added flarg
* | 5068c34c3862856f511b6b4d48f2adb766e1bde4 now with added snogg
|/
* b51f227e931f830cbda042bc372087398ae7e50d initial commit

@araqnid的建议似乎不起作用,除非我没有正确阅读它:

$ git rev-list --oneline derivative --not base
f16fd151b374b2aeec8b9247489c518a6347d001 merged in the latest from the base branch
2f2ed5f1d429492e1491740e30be5a58ec20af21 snogg before flarg
5068c34c3862856f511b6b4d48f2adb766e1bde4 now with added snogg

这将显示derivative中除base之外的所有提交。这有点说得通,因为它只是删除了否定提交的祖先。我想它只显示第一行。

4个回答

10
从一组提交记录中展示到提交A的祖先路径:

git log--ancestry-path^Aothers

展示库中所有不可达的提交记录:

git fsck --unreachable --no-reflogs \
| awk '$2 == "commit" {print $3}'

在库中跟踪提交A的所有后代:
git log --ancestry-path --graph --decorate --oneline ^A \
   --all $(git fsck --unreachable --no-reflogs | awk '$2=="commit" {print $3}')

自从本答案撰写以来,Git已经学会了一种更简单的方法来显示所有历史记录包含一个提交的引用:
git for-each-ref --contains A

您可以添加--format='%(refname:short)'来简化输出。


5

好的,"--branches"或"--all"将包括所有分支提示,然后"--not A"将排除A及其所有祖先。但是,"--branches --not A"将包括不包括A的分支,这不是您所需要的。

没有简单的方法可以获取您想要的所有内容,尽管您可以解决这个问题。这将列出包含提交A的所有分支:

git for-each-ref refs/heads/* | while read rev type name; do
  git rev-list $rev | grep $(git rev-parse A) >/dev/null && echo $rev
done

那么你需要列出所有可达的修订版本,但不包括A本身和任何向后的修订版本。
git rev-list $(git for-each-ref refs/heads/* | while read rev type name; do
      git rev-list $rev | grep $(git rev-parse A) >/dev/null && echo $rev
    done) --not A

请注意,我只进行了非常简短的测试:p 但是我认为基本原理是正确的。

我猜就是这样。没有更直接的方法来做这件事似乎有点奇怪。我想这是因为git提交总是与它们的父级链接而不是子级。我会试一试并告诉你结果如何。 - intuited
嗯...似乎不起作用。我有一个“base”(例如开发)分支,已经多次合并到“derivative”(例如测试)分支中。我想列出仅为最近的“base”提交的后代提交。然而,“git rev-list derivative --not base --oneline”向我展示了这个列表包括具有与“base” HEAD 共同祖先的“derivative”提交。也就是说,任何具有从基础合并的祖先的提交。我将更新我的问题以澄清这一点。 - intuited
git for-each-ref refs/heads/\* 不包括斜杠 / 在分支名中的分支名称。 - hraban

1

我做了一个替代版本,不知道是更好还是更差。

getGitChildren(){
    git rev-list --all --parents | grep "^.\{40\}.*${1}.*" | awk '{print $1}' | xargs -I commit git log -1 --oneline commit | cat -
}

被用于这样的方式:
$ getGitChildren 2e9df93
f210105376 feat(something): did that feature
9a1632ca04 fix(dummy): fix something

它只是提供一个提交的直接子项列表。

0

看起来是这样做的:

$ for rev in $(git rev-list --branches); do
    git rev-list $rev \
      | grep $(git rev-parse base) &>/dev/null \
    && echo $rev;
  done \
  | xargs -L 1 git rev-list -n 1 --oneline
f16fd151b374b2aeec8b9247489c518a6347d001 merged in the latest from the base branch
564d795afb63eab4ffe758dbcd726ca8b790f9f6 spelling correction

最后一个带有 xargs 的管道部分只是显示每个提交的提交消息。
除了其子级,这将列出目标提交,这实际上是我想要的。 这相当慢,需要超过3秒才能在40个提交的存储库上运行。 这并不奇怪,因为它几乎像安德烈巨人一样粗暴。 我想更优雅的方法是为每个引用通过rev-list构建一个哈希树,其中包含与其子代链接的每个提交的哈希,然后从目标提交开始遍历该树。 但那有点复杂,所以我希望有一个git命令可以做到这一点:) 我仍然需要弄清楚如何将这组提交放入filter-branch中。 我想我可以从我的--tree-filter 命令内部的$ GIT_COMMIT rev-list中grep。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接