[某些现有裸存储库的接收后脚本包含该行]
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
错误本身当然是正确的。问题是/var/www/laravel 没有.git:既没有指向存储库位置的.git 文件,也没有包含存储库的.git 目录/文件夹(无论您喜欢哪个术语)。简而言之,它只是一个工作树,因为 确实 操作 Git 存储库的其他一些 git ... 命令包含 --work-tree=/var/www/laravel。
因此,直接的解决方案是运行:
git --git-dir=/var/repo/site.git submodule init
git --git-dir=/var/repo/site.git submodule update
或等价物。但是请注意,子模块涉及克隆其他 Git 存储库,而同样的推理(无论它是什么)导致您不首先将 Git 存储库本身放入 /var/www/laravel/.git 可能也 引导您避免在/var/www/laravel 的子目录中放置额外的.git 条目。这将更难实现。
如果——这是一个相当大的问题if——可以将.git 文件留在子模块工作树中,如果(另一个相当大的如果)测试表明一切正常,考虑让您的接收后脚本如下:
# 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(在接收后脚本中设置,但通常设置为 相对 路径,例如 .git 或 .,并将其转换为绝对路径。 (abspath 函数在这里可能会更好,但它不如 realpath 命令常用。)
-
然后我们使用git --worktree 来检查main 尖端的提交。如果这可能会覆盖一些未保存的文件,则需要此处的 -f 选项。这种方法非常不完善,最好一次准备一个完整的工作树,然后用近乎原子的mv 替换它,但我们在这里坚持使用现有的钩子方法。我们所做的只是删除--git-dir,无论如何它都隐含在$GIT_DIR 变量中。
-
然后我们在目标工作树中运行git submodule update --init,$GIT_DIR 仍设置为绝对路径。这结合了init 和update 步骤。与结帐步骤一样,它相当不完美。我们可以在第二步中使用git checkout --recurse-submodules 来达到类似的效果,并且在某些(更新的)Git 版本中可能会更好。
将替代方案(递归结账)与原子交换相结合,我们得到类似的东西作为我们的后接收:
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.$$
如果你愿意,可以将不同的行串成一个大的&&-chain,或者你可以在顶部使用set -e。请注意,以上内容完全未经测试。