【问题标题】:Find containing module's commit corresponding to given submodule commit查找与给定子模块提交对应的包含模块的提交
【发布时间】:2022-03-22 20:40:44
【问题描述】:

在 Git 中,我在模块 A 中有子模块 B。我想转到 B 中的特定提交,然后使用 B 的特定提交(如果有)在 A 中找到相应的提交。例如,使用该特定 B 版本的 A 的最新提交就可以了。如何做到这一点?

【问题讨论】:

    标签: git git-submodules


    【解决方案1】:

    在合理的限制下,可以使用git bisect 找到此提交:

    #!/bin/bash
    #
    # Find superproject commit introducing given submodule's commit
    #
    # Usage: git submodule-introduced path/to/submodule <submodule-commit>
    #
    # Bisect is performed. On success found commit is displayed and written to the
    # 'bisect/containing' ref
    #
    # Limitations:
    # 1. Submodule must have monotonous history (all submodule updates are fast-forward)
    # 2. Commit adding a submodule must have parents
    set -e
    
    export submodule=${1?specify submodule path}
    export commit=${2?specify submodule commit}
    
    from=$(git rev-list HEAD -- $submodule | tail -n 1)
    
    git bisect start --no-checkout --term-bad=containing HEAD $from~ -- $submodule
    
    git bisect run sh -c '! git -C $submodule merge-base --is-ancestor $commit $(git rev-parse BISECT_HEAD:$submodule)'
    

    【讨论】:

      【解决方案2】:

      这个问题和@Max O 的回答促使我创建了mod-from-sub.bash(免责声明:这是我的个人github)。

      脚本目标:find the most recent module's ancestor commit for a given submodule's hash/branch

      下面的示例输出 (Module=A, Submodule=B),当前工作目录 (cwd) 作为 A 的根目录:

      $ PATH_CONTAINING_SHELL_DIR/shell/bash/git/mod-from-sub.bash --submodule 'relative/path/A/to/B'
      INFO: mod-from-sub.bash: module is empty, using cwd='/path/to/A'.
      INFO: mod-from-sub.bash: remote_module is empty, using 'origin'.
      INFO: mod-from-sub.bash: ref_module is empty, using 'origin/master'.
      INFO: mod-from-sub.bash: ref_sub is empty, using 'HEAD'.
      ################################################################################
      INFO: mod-from-sub.bash: SUCCESS: submodule='relative/path/from/A/to/B' with ref='HEAD' has nearest ancestor for module='/path/to/A' on the below line.
      90f6c749140e5efe2361b40ae7612c25f869b116
      

      注意事项: 这不会从 A 获得引入 B 的提交的提交(不是 B 的每个提交甚至都会有来自 A 的相应提交)

      通过下图,如果我们寻找 B2 的最近祖先,我们会得到 A1,而不是 A2。我还没有获得 A2 的实际目的,但如果需要,请随时发表评论并尝试为您提供有用的东西。

      A2 -> B3
      |      |
      |     B2
      |      |
      A1 -> B1
      

      注意:即使存在指向 B1 的提交 A0,我们仍然会获得 A1,因为 A1 是 B2 的最新祖先。

      此外,截至目前,这不是一个独立的脚本。需要整个 shell 目录(一小部分 .bash 和 .sh 文件);在某些时候,我计划制定一种机制来部署脚本及其包含作为独立脚本,但我还没有开始。

      【讨论】:

        【解决方案3】:

        无法保证存在这样的提交。如果确实存在一个,它可能不是唯一的(可能不止一个)。

        当然,不能保证任何事情都会奏效,但这不是我的意思。子模块背后的设计原则是相反的:超级项目,在你的例子中是“模块 A”,被认为是控制项。您检查一些给定的超级项目提交——通过分支名称、标签名称、或原始哈希 ID 或其他方式——并且在该签出的提交中,超级项目包含子模块中特定提交的哈希 ID。

        因此,对于模块 A 中的每个提交(或者每个使用 B 的提交),B 都有一些特定的哈希 ID。我们暂时假设 A 中只有三个提交,编号为 A1、A2 和A3,以及 B 中的三个提交,编号为 B1、B2 和 B3。如果我们检查 A1,我们会得到一个 B 号。假设这是B2。如果我们检查 A2,我们会得到另一个 B 号码。假设又是 B2。最后,如果我们检查 A3,我们会得到另一个 B 数字……很可能又是 B2。

        在这种情况下,对应于提交 B1 和 B3 的“A”提交集合都是 ,对应于 B2 的“A”提交集合具有基数 3。对于某些B 提交,有 no A 提交,对于其他 B 提交,没有 unique A 提交。

        这对于子模块的使用通常是正确的,所以给定一些 B 提交哈希,不可能找到 对应的 A 提交。但是,您可以查看任意数量的 A 提交并找到它们对应的 B 哈希。这些是提交树中的 gitlink 条目,请参阅How can I get a git submodule's associated commit ID from a past commit in the parent clone?(请注意基于git rev-parse 的答案,如果您知道子模块的 gitlink 的特定路径,这是要走的路)。如果您制作一个包含所有 A->B 映射的完整表,则很容易反转该表并找到给定 B 的所有 A 值的集合 值,因此集合是否为空。

        【讨论】:

        • 不是我的问题的答案,抱歉。我知道的前 4 段,修正了我的问题的措辞,所以人们不会专注于此。最后一段解决了相反的问题:给定 A 的提交,B 的哪个提交?但这我知道该怎么做。只有结尾暗示了我需要什么,而没有实际建议一种方法。
        • 那是因为没有方法可以做到!
        • 嗯,真的好吗?在整个 git 及其所有克隆、扩展和附加组件中?好的。然后我们不能设计一个自制的东西,我们循环遍历 A 的所有提交并过滤 B 的相应提交以获得我想要的那个,并输出命中的 A 提交吗?即使没有,也没关系。我自己没有足够的 git bash 知识。
        • 是的,我担心您必须编写一些代码。你知道 B 中的提交哈希,所以你需要的可能是(这完全未经测试):git rev-list --all | while read ahash; do abhash=$(git rev-parse --quiet --verify ${ahash}:path/to/b/submodule) || continue; test $abhash = $bhash &amp;&amp; echo "$bhash found in $ahash"; done。这假设您已将 bhash 设置为所需的哈希 ID。如果您要重复执行此操作,而不是每次检查子模块是否存在时都循环遍历所有哈希,而是通过检查循环一次,将所有 (ahash, abhash) 对写入 [续]
        • ... 到地图文件中(这是您可以反转的地图)。然后,例如,只需 grep ${bhash}\$ mapfile 即可找到以所需 B 哈希结尾的行。
        猜你喜欢
        • 1970-01-01
        • 2012-05-31
        • 2012-06-06
        • 1970-01-01
        • 2019-04-28
        • 1970-01-01
        • 2012-12-06
        • 2013-01-03
        相关资源
        最近更新 更多