如何将子模块推送到远程存储库
How to push a submodule to a remote repository
我在服务器上设置了一个远程存储库。我从我的本地计算机推送到存储库,并设置了一个挂钩以将推送重定向到另一个目录。它看起来像这样:
post-receive
#!/bin/sh
git --work-tree=/var/www/laravel --git-dir=/var/repo/site.git checkout -f main
当我去 /var/www/laravel 并尝试做
git submodule init
git submodule update
它给出:
fatal: not a git repository (or any of the parent directories): .git
我知道我可能必须在重定向推送之前启动和更新子模块。我可能必须创建另一个挂钩命令,但我不知道它应该是什么。谢谢!
[某些现有裸存储库的 post-receive 脚本包含行]
git --work-tree=/var/www/laravel --git-dir=/var/repo/site.git checkout -f main
[但是]
When I go to /var/www/laravel
and try to do
git submodule init
git submodule update
It gives:
fatal: not a git repository (or any of the parent directories): .git
错误本身当然是正确的。问题是 /var/www/laravel
没有 .git
:既没有指向存储库位置的 .git
文件,也没有 .git
目录/文件夹(无论您喜欢哪个术语)包含存储库。简而言之,它是一个工作树只是因为 执行 操作 Git 包含 --work-tree=/var/www/laravel
.[=46= 的一些其他 git ...
命令]
因此,直接的解决方案是 运行:
git --git-dir=/var/repo/site.git submodule init
git --git-dir=/var/repo/site.git submodule update
或同等学历。但是请注意,子模块涉及克隆额外的 Git 存储库,并且相同的推理 - 无论它是什么 - 导致你 not 将 Git 存储库本身放入/var/www/laravel/.git
首先可能 也 会导致您避免在 /var/www/laravel
的子目录中放置额外的 .git
条目。这将更难实现。
If—这是一个相当大的 if—可以将 .git
文件留在子模块工作树中,如果(另一个相当大的 if)测试显示如果一切正常,请考虑阅读您的 post-receive 脚本:
# configuration: where the directory and submodules go
wt=/var/www/laravel
export GIT_DIR=$(realpath $GIT_DIR) &&
git --work-tree=$wt checkout -f main &&
cd $wt &&
git submodule update --init
这里的想法是:
我们采用 $GIT_DIR,它在 post-receive 脚本中设置,但通常是 相对 路径,例如 .git
或 .
,并将其转换为绝对路径。 (abspath
函数在这里可能会更好,但它不如 realpath
命令可用。)
然后我们使用 git --worktree
来检查 main
末尾的提交。如果这可能会覆盖一些未保存的文件,则需要此处的 -f
选项。这种方法非常不完美,一次准备一个完整的工作树会好得多,然后用 nearly-atomic mv
交换它,但我们在这里坚持使用现有的钩子方法。我们所做的只是删除 --git-dir
,它隐含在 $GIT_DIR
变量中。
然后我们在目标工作树中 运行 git submodule update --init
,$GIT_DIR
仍然设置为绝对路径。这结合了 init
和 update
步骤。与结帐步骤一样,它相当不完善。我们可以在第二步中使用 git checkout --recurse-submodules
来达到类似的效果,并且在某些(更新的)Git 版本中可能会更好。
将备选方案(递归结帐)与原子交换相结合,我们得到类似这样的东西作为我们的 post-receive:
wt=/var/www/laravel.update-tmp.$$
rm -rf $wt # just in case
export GIT_INDEX_FILE=$GIT_DIR/index.tmp.$$
rm -f $GIT_INDEX_FILE # also just in case
mkdir $wt
git --work-tree=$wt checkout --recurse-submodules main
rm -f $GIT_INDEX_FILE
t=/var/www/laravel
# We now try to put $wt in place of $t with as little
# interruption as possible. This means renaming the
# existing $t out of the way (using a pid-based directory
# name), renaming $wt into place, and only then removing
# (recursively) the backup.
mv $t $t.backup.$$ && mv $wt $t && rm -rf $t.backup.$$
如果您愿意,可以将各个单独的行 运行g 组合成一个大的 &&
链,或者您可以在顶部使用 set -e
。请注意,以上内容完全未经测试。
我在服务器上设置了一个远程存储库。我从我的本地计算机推送到存储库,并设置了一个挂钩以将推送重定向到另一个目录。它看起来像这样:
post-receive
#!/bin/sh
git --work-tree=/var/www/laravel --git-dir=/var/repo/site.git checkout -f main
当我去 /var/www/laravel 并尝试做
git submodule init
git submodule update
它给出:
fatal: not a git repository (or any of the parent directories): .git
我知道我可能必须在重定向推送之前启动和更新子模块。我可能必须创建另一个挂钩命令,但我不知道它应该是什么。谢谢!
[某些现有裸存储库的 post-receive 脚本包含行]
git --work-tree=/var/www/laravel --git-dir=/var/repo/site.git checkout -f main
[但是]
When I go to
/var/www/laravel
and try to dogit submodule init git submodule update
It gives:
fatal: not a git repository (or any of the parent directories): .git
错误本身当然是正确的。问题是 /var/www/laravel
没有 .git
:既没有指向存储库位置的 .git
文件,也没有 .git
目录/文件夹(无论您喜欢哪个术语)包含存储库。简而言之,它是一个工作树只是因为 执行 操作 Git 包含 --work-tree=/var/www/laravel
.[=46= 的一些其他 git ...
命令]
因此,直接的解决方案是 运行:
git --git-dir=/var/repo/site.git submodule init
git --git-dir=/var/repo/site.git submodule update
或同等学历。但是请注意,子模块涉及克隆额外的 Git 存储库,并且相同的推理 - 无论它是什么 - 导致你 not 将 Git 存储库本身放入/var/www/laravel/.git
首先可能 也 会导致您避免在 /var/www/laravel
的子目录中放置额外的 .git
条目。这将更难实现。
If—这是一个相当大的 if—可以将 .git
文件留在子模块工作树中,如果(另一个相当大的 if)测试显示如果一切正常,请考虑阅读您的 post-receive 脚本:
# configuration: where the directory and submodules go
wt=/var/www/laravel
export GIT_DIR=$(realpath $GIT_DIR) &&
git --work-tree=$wt checkout -f main &&
cd $wt &&
git submodule update --init
这里的想法是:
我们采用 $GIT_DIR,它在 post-receive 脚本中设置,但通常是 相对 路径,例如
.git
或.
,并将其转换为绝对路径。 (abspath
函数在这里可能会更好,但它不如realpath
命令可用。)然后我们使用
git --worktree
来检查main
末尾的提交。如果这可能会覆盖一些未保存的文件,则需要此处的-f
选项。这种方法非常不完美,一次准备一个完整的工作树会好得多,然后用 nearly-atomicmv
交换它,但我们在这里坚持使用现有的钩子方法。我们所做的只是删除--git-dir
,它隐含在$GIT_DIR
变量中。然后我们在目标工作树中 运行
git submodule update --init
,$GIT_DIR
仍然设置为绝对路径。这结合了init
和update
步骤。与结帐步骤一样,它相当不完善。我们可以在第二步中使用git checkout --recurse-submodules
来达到类似的效果,并且在某些(更新的)Git 版本中可能会更好。
将备选方案(递归结帐)与原子交换相结合,我们得到类似这样的东西作为我们的 post-receive:
wt=/var/www/laravel.update-tmp.$$
rm -rf $wt # just in case
export GIT_INDEX_FILE=$GIT_DIR/index.tmp.$$
rm -f $GIT_INDEX_FILE # also just in case
mkdir $wt
git --work-tree=$wt checkout --recurse-submodules main
rm -f $GIT_INDEX_FILE
t=/var/www/laravel
# We now try to put $wt in place of $t with as little
# interruption as possible. This means renaming the
# existing $t out of the way (using a pid-based directory
# name), renaming $wt into place, and only then removing
# (recursively) the backup.
mv $t $t.backup.$$ && mv $wt $t && rm -rf $t.backup.$$
如果您愿意,可以将各个单独的行 运行g 组合成一个大的 &&
链,或者您可以在顶部使用 set -e
。请注意,以上内容完全未经测试。