查找具有给定祖先的提交

Posted

技术标签:

【中文标题】查找具有给定祖先的提交【英文标题】:Find commits with given ancestors 【发布时间】:2018-10-08 19:48:13 【问题描述】:

在某一时刻,我的 git 存储库包含以下结构:

A1    A2    A3
 o-----o-----o
        \     \
         o X   o Y
B1    B2/   B3/
 o-----o-----o
        \
         o Z
C1    C2/
 o-----o

我正在尝试检索作为多个指定提交的后代的最早提交。决胜局将是提交日期。例如:

descendant A1 B2 -> X
descendant A2 B3 -> Y
descendant A1 C1 -> nothing

合并提交可能有两个以上的父级。我找到了很多关于 git merge-base 的文档,它几乎完成了相反的任务,但找不到任何至少可以返回我可以排序的后代列表的函数。

【问题讨论】:

Git 只跟踪提交的 parents,而不跟踪子项。仅给定 A1B2,除了检查 every 提交以查看它是否具有 A1B2 作为祖先之外,没有其他方法可以找到它们的共同后代。 添加到@chepner 的评论中,这个术语是 DAG(有向无环图)。每个节点之间的边是一种方式。 【参考方案1】:

这是我经过更多研究后设法拼凑的内容。这很丑陋,可能非常效率低下,但看起来很有效。

#!/bin/bash

common_descendants=$(git rev-list --ancestry-path --all $1.. | sort)
shift

while [ $# -ne 0 ]; do
    common_descendants=$(
        echo "$common_descendants"
        | comm -12 --nocheck-order - <(
            git rev-list --ancestry-path --all $1.. | sort
        )
    )
    shift
done

git rev-list --reverse --date-order --no-walk $common_descendants | head -n 1

它使用git rev-list --ancestry-path --all 依次查找每个请求提交的所有后代。 这些列表在sortcomm 的帮助下相交以获得候选提交列表。 最后,git rev-list --ancestry-path --all 按提交日期排序,head -n 1 选择最旧的。

【讨论】:

--ancestry-path 会得到与我建议的结果相似的结果:在这里,您使用 HEAD 作为枚举向后运行的点,然后还丢弃既不是 @ 祖先的提交987654329@ 也不是您的限制提交的后代。但是,您排除了特定的限制提交本身,这可能是最低共同后代的答案。 @torek 在点击之前我得再考虑一下。我没有考虑到这些提示对于以正确的方式遍历图表很有用。谢谢指点!【参考方案2】:

作为chepner commented,Git 只有反向指针。 查找提交 C 的后代必须转化为一个新的不同的问题,而是:查找提交 T 的祖先,其自身具有提交 C 作为祖先。 这里 T 是一个提示提交,或者在您的情况下,可能是许多提示提交——所有分支,可能还有所有标签和所有其他引用。

git rev-list 命令适合解决问题。特别是,您可以让它遍历从提示(后代)到父母的图形,但收集在此过程中遍历的边,然后使用 --children 反转它们。正如the documentation 所说,这可以实现父级重写和历史简化。

(我认为您需要在您选择的任何起始提示提交上运行git rev-list --children,并自己解析其输出以应用其他约束。您可以使用您正在搜索的提交的父级作为停止点,使用the ^<em>hash</em>^@ gitrevisions syntax,用于剪切图迭代。请注意,这实际上是领先的^,类似于--not,但局部而不是全局,应用于rev^@。)

【讨论】:

以上是关于查找具有给定祖先的提交的主要内容,如果未能解决你的问题,请参考以下文章

在二叉树中查找给定节点的祖先

一个人如何在一组给定的数据中存储和查找祖先?

使用 Git,我如何显示所有共享一个共同祖先的提交树?

Git:查找所有标签,可从提交中访问

查找具有特定类的最近的祖先元素

查找具有特定类别的祖先。硒。网络驱动程序。使用 XPath