针对裸存储库执行 git 提交的合法性

Legality of executing git commits against a bare repository

我在用作中央存储库的服务器上有一个裸 git 存储库。我已经安装了一个 post-receive 挂钩,这样当一个提交被推送到这个存储库时,提交的更改会使用以下命令部署到同一服务器上的工作目录:

git --git-dir=path-to-repository --work-tree=path-to-working-directory checkout -f

我意识到通过在 post-receive 挂钩中设置 GIT_DIRGIT_WORK_TREE 环境变量,我还可以从命令中发出任意 Git 命令线。我并不是说修改文件并从这个工作目录提交更改是好的开发实践,特别是如果这是我的生产环境,但我是否在 非法 [=] 21=] 观点?

... but am I doing anything illegal from a Git point of view?

没有。然而,重要的是要认识到这个稍微奇怪的状态的一些事情。

  1. Git 只有一个存储库,--git-dir 告诉它在哪里可以找到那个存储库。

  2. Git 只有一个工作树,1--work-tree 告诉它在哪里可以找到一个工作树(并覆盖 core.bare 设置)。

  3. Git 只有一个 HEAD(但请参阅脚注 1),--git-dir 告诉它在哪里可以找到那个 HEAD 文件。

  4. Git 只有一个索引,2 并且... --git-dir 告诉它在哪里可以找到那个索引,如果未被环境变量设置覆盖。

正是这些最后的部分让人们感到困惑,主要是在使用 post-receive 脚本部署某些特定分支时。

如果你只部署一个分支到一个工作树,一个索引不是问题。如果您开始将两个或多个分支部署到两个工作树,那么一个索引就会成为一个问题。

类似地,单个 HEAD 文件通常不是问题,特别是如果您仅部署分支 master 时以通常方式创建裸存储库,master 作为其当前分支。 (一个裸仓库仍然有一个当前分支,这是它的 HEAD 文件中的分支。)当人们克隆裸仓库时,他们的克隆默认检查裸仓库中当前的分支——所以如果你开始部署几个不同的分支,人们可能会惊讶于他们的克隆开始于存储库 QAtestdevelop 或其他任何地方,而不是 master.

(HEAD 的事情只需要人们意识到他们的默认克隆分支可能会让他们感到惊讶,如果他们想要的话,他们应该检查开发分支。这是导致真正的单一索引文件麻烦,所以看脚注1。)


1如果您使用 git worktree add,在 Git 2.5 及更高版本中可用,则不再适用。额外的工作树当然提供了它们自己的工作树,但也提供了它们自己单独的HEAD,还有它们自己的索引。

您可以使用环境变量 GIT_INDEX_FILE 提供您自己的索引,它总是覆盖 Git 的正常计算。这也提供了一种进行多分支部署的方法:让一个分支使用默认索引,并为其余部分提供自己的索引文件(每个分支一个)。

使用多个工作树和 push.denyCurrentBranch 的新 updateInstead 模式可能是自动化部署的更好方法,但我还没有实际测试过。

2Git 的最新版本引入了 "split index",其中非常大的索引文件 "split"为了使 Git 更快,' 改变了很多,以及所做的部分。索引拆分有点神奇(虽然最终显然是确定性和可预测的)并且知道如何处理备用索引文件,所以你真的不需要知道这方面的任何事情,但它使 "one index file" 声明有点怀疑。在任何情况下,从 git worktree add 添加的工作树仍然有自己的索引文件(或索引对),因为这是必要的。