git post-在同一台服务器上接收多个工作树

git post-receive for multiple worktrees on the same server

我正在关注 this tutorial,它一直运行良好。我们现在想 运行 服务器上的多个帐户使用相同的包,我正在尝试修改 post-receive 但我没有做正确的事情并且找不到答案。目标是从我们的 github 存储库中分离出不同的 cpanel 类型帐户 运行ning 相同的代码,每当我们推送更改时,所有帐户都会发生更新。

post-receive中的原代码是这样的:

#!/bin/bash 
git --work-tree=/path/to/firstInstance --git-dir=/var/control/project.git checkout -f

并且它按预期工作,每当我们从本地仓库推送并更新 github 时,我们的远程服务器也会更新为 /var/control/project.git 然后被推送到第一个账号。

当我为不同的工作树添加另一行时,有 3 行内容如下:

#!/bin/bash
git --work-tree=/path/to/firstInstance --git-dir=/var/control/project.git checkout -f
git --work-tree=/path/to/secondInstance --git-dir=/var/control/project.git checkout -f

我可以向两个实例添加新文件,但删除只发生在第二个实例上。显然我做的不对,但我无法在这里或在线其他地方找到我要找的东西。任何帮助将不胜感激。

您(大概1)使用的是裸存储库,这是正确的做法,但您遇到了一个显而易见的障碍 之后,您已成为 Git 大师。诀窍是每个工作树需要一个 index2 我们稍后会定义所有这些术语,但是 TL ;DR 部分是使用这个有点神奇的序列:

GIT_INDEX_FILE=index.firstInstance git --work-tree=/path/to/firstInstance --git-dir=/var/control/project.git checkout -f
GIT_INDEX_FILE=index.secondInstance git --work-tree=/path/to/secondInstance --git-dir=/var/control/project.git checkout -f

这绝对可以简化;要了解如何操作,请继续阅读。


1您的 link 中的说明说要使用 git init --bare,所以我假设您正在这样做。

2还有其他技巧可以使用,但我要使用这个。


这是怎么回事

一个正常的Git克隆体由三部分组成,可以说是:

  • 存储库本身,它本身由两个主数据库和许多辅助数据库组成;和
  • 一个索引和一个工作树,它们配对在一起。

使用这些普通存储库之一,git worktree add 命令可以添加更多工作树。每个都有一个索引和工作树对。它们绑定在一起(有点松散,但足以始终将它们视为一对)。

A bare 克隆省略了工作树而不省略索引。这意味着您的裸存储库有一个免费索引:它将绑定到的工作树不存在。因此,您可以 运行 git --work-tree=<em>path command argument1 argument2</em> ...。这会暂时为这个裸存储库分配一个工作树。 (单个)索引和此工作树现在绑定在一起。您提供的一个命令是 运行,使用标准索引和该工作树。

问题是一个标准索引现在描述了那个工作树,而不是任何其他工作树。如果你 运行 git --work-tree=<em>otherpath 命令...</em>,你调用 Git 及其标准索引和 other 路径绑定在一起。 Git 假定索引正确描述了此 other 工作树。如果没有,事情有时会失败。更准确地说,索引跟踪工作树中的内容,Git 部分 只是假设它是正确的。3


3Git 做了一些检查。索引中有缓存数据 about 该工作树,并且 Git 将验证至少部分数据保持正确。它究竟信任多少数据,不信任多少取决于它在进行这些检查时看到的内容。这意味着当缓存数据 正确描述工作树时,效果很难预测。有时一切正常!但有时它不会。当它失败时,它会不可预测地失败并且很难调试。


我们对此做了什么

我们利用了 Git 能够使用多个索引这一事实。正如我们上面提到的,如果您向标准(非裸)存储库添加额外的工作树,每个添加的工作树都有自己的索引。4 但是当我们使用 --work-treeGIT_WORK_TREE 来覆盖标准工作树,或者为其他裸存储库提供一个,我们没有覆盖标准工作树的标准索引。使用 GIT_INDEX_FILE 环境变量允许我们覆盖标准索引(其名称只是 index)。

我们需要为除一个“额外”工作树之外的所有工作树执行此操作。我们与裸存储库一起使用的工作树之一 可以 使用标准索引,因此我们实际上只需要在两个 [=19] 之一上分配一个 GIT_INDEX_FILE 环境变量=] 命令在这里。但是为了对称性,或者添加第三个结帐的能力,我们可以每次都覆盖标准索引。

注意,如果 bash 脚本的当前工作目录已经是裸仓库目录,则不需要 --git-dir 选项(或 GIT_DIR 环境变量),因此在许多您可以省略 --git-dir= 的情况。为了简化脚本,您可以 运行:

cd /var/control/project.git

在脚本的前面并省略每个 --git-dir= 选项。

另请注意,这些 git checkout -f 命令不提供提交哈希 ID 或分支名称,因此它们总是检查由特殊名称 HEAD.

标识的任何提交

4这些添加的工作树有自己的 HEAD 参考和其他参考。我们不在这里处理这个问题。这是否以及何时成为问题是另一个话题。