查找与给定子模块提交对应的包含模块提交



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

由于合理的限制,可以使用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)'

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

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

下面的示例输出(模块=A,子模块=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

警告: 这不会从引入 B 提交的 A 那里获得提交(并非来自 B 的每个提交甚至都会有来自 A 的相应提交)

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

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

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

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

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

当然,不能保证任何事情都有效,但这不是我在这里的意思。 子模块背后的设计原则则相反:超级项目,在您的例子中是"模块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 提交,没有 A 提交,对于其他 B 提交,没有唯一的A 提交。

这通常适用于子模块的使用,因此给定一些B提交哈希,无法找到相应的A提交。但是,您可以查看任意数量的A提交并找到它们对应的B哈希。 这些是提交树中的gitlink条目,请参阅如何从父克隆中的过去提交中获取 git 子模块的关联提交 ID?(请注意基于git rev-parse的答案,如果您知道子模块 gitlink 的特定路径,这就是要走的路)。 如果您制作所有A->B 映射的完整表,则很容易反转该表并找到给定B值的所有A值的集合,从而找到该集合是否为空。

最新更新