我们有一个超级项目和一个包含在其中的子模块。两者都有相同的分支
master, staging, featureBranch
。
我希望
master
上的超级项目跟踪 master
上的子模块,staging
上的超级项目跟踪 staging
上的子模块。
对于超级项目中的 master
.gitmodules
看起来像这样:
[submodule "submodule"]
path = submodule
url = http://fpr-dev/submodule.git
branch = master
和分期
[submodule "submodule"]
path = submodule
url = http://fpr-dev/submodule.git
branch = staging
现在当我在 master 上做一个
git submodule
我看到以下输出:
$ git submodule
+e3782f37b1ae23aa0d5537ef3061dfdfec70f77f submodule (heads/Staging)
请注意它说的是分期。但是当我在子模块中执行 git status 时,我看到:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
为什么会这样,我该如何解决?
现在,当我切换到
staging
并尝试拉 (git.exe pull -v --progress "origin"
) 子模块时,我收到以下错误:
You asked to pull from the remote 'origin', but did not specify
a branch. Because this is not the default configured remote
for your current branch, you must specify a branch on the command line.
我只想做:
实现这种行为的最简单方法是什么?
当您运行
git submodule
时,它会为您的子模块显示正确的提交 SHA,因为这是您在超级项目中设置的。该命令不会告诉您当前本地子模块代码引用的提交 SHA;它告诉你想要超级项目想要参考。
不幸的是,你必须采取额外的步骤来告诉你的超级项目在本地拉下那个特定的子模块代码。这是通过运行这些命令来完成的:
git submodule init
git submodule update
在此之后,您应该在本地的子模块中看到正确的代码。您唯一可以绕过这些额外命令的时间是您第一次克隆存储库时。你可以这样称呼:
git clone <repo_name> --recursive
并且所有子模块都将在正确的提交 SHA 处检出。但是,一旦签出新分支,就必须再次运行
init
和 update
命令。
要自动执行此行为,您可以创建一个脚本来运行,而不是直接使用
git checkout
命令。该脚本可以接受一个分支名称,看起来像这样:
git checkout <branch_name>
git submodule init
git submodule update
我不确定你是否成功过,但我们使用了一个涉及 Git 钩子的解决方案,特别是结帐后钩子。这样一来,当您在超级项目中切换分支时,它将尝试检出子模块中的同名分支;如果子模块中不存在该分支,它将尝试签出“开发”(在您的情况下,您可能需要不同的分支名称,如“暂存”)。 注意:无论检出哪个分支,超级项目仍将确保子模块在分支检出后位于正确的提交 $SHA 上。
例如如果超级项目在
staging
上时期望子模块 A 在 commit_hash=848f7b,那么无论子模块 A 是否正在跟踪分支,都会发生这种情况。
在你的超级项目的 .git/hooks 文件夹中,添加一个名为
post-checkout
的文件并将以下代码放入其中。
#!/bin/bash
# NOTE: This hook runs before the --recursive part of
# the checkout. This means that the submodules have not
# yet been updated to their required commit.
PREV_COMMIT=$1;
POST_COMMIT=$2;
CURRENT_DIRECTORY=$(pwd);
# If we update the parent repo to a named branch that
# should also exist in the child repos, checkout that
# branch in the child repos
# [parent checks out Develop, children should also check
# out develop... not just move HEAD ref]
#
if git branch | grep -Eqx '^\* [^ ]*$'; #if we just checked out a named branch(not a HEAD checkout)
then
BRANCH_NAME=$(git branch | sed -E 's/^\* ([^ ]*)$/\1/;t;d');
# if the branch exists in a submodule, check out that branch.
#If the branch doesn't exist, but the hash of the commit to
# checkout is the same as develop, then checkout develop instead of the hash
git submodule foreach "
develop_sha=\$(git rev-parse develop);
if git branch | grep -Eq '$BRANCH_NAME'; then
git checkout '$BRANCH_NAME';
elif [ \"\$sha1\" = \"\$develop_sha\" ]; then
git checkout develop;
fi || :";
fi