您(大概1)正在使用一个裸存储库,这是正确的做法,但是您遇到了一个问题,只有在您拥有之后 成为一名 Git 大师。 ? 诀窍是每个工作树需要一个 index。2 我们稍后会定义所有这些术语,但 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链接中的说明说使用git init --bare,所以我假设你正在这样做。
2还有其他技巧也可以,但我会用这个。
这里发生了什么
一个普通的 Git 克隆由三个部分组成:
- 存储库本身,它本身由两个主数据库和许多辅助数据库组成;和
- 一个索引和一个工作树,它们配对在一起。
使用这些普通存储库之一,git worktree add 命令可以添加更多工作树。每个都有一个索引和工作树对。它们绑定在一起(有点松散,但足以始终将它们视为一对)。
bare 克隆会省略工作树而不省略索引。这意味着您的裸存储库有一个空闲索引:它将绑定到的工作树不存在。因此,您可以运行git --work-tree=<em>path command argument1 argument2</em> ...。这会临时为这个裸存储库分配一个工作树。 (单个)索引和此工作树现在绑定在一起。使用标准索引和该工作树运行您提供的一个命令。
问题在于,一个标准索引现在描述了那个工作树,而不是任何其他工作树。如果你运行 git --work-tree=<em>otherpath command ...</em>,你调用 Git 时会使用它的标准索引和绑定在一起的 other 路径。 Git 假设索引正确地描述了这个 other 工作树。如果没有,事情有时会失败。更准确地说,索引会跟踪工作树中的内容,Git 部分只是假设它是正确的。3
3Git 会进行一些检查。索引中有缓存数据关于该工作树,Git 将验证至少其中一些数据保持正确。它信任多少数据以及不信任多少数据取决于它在进行这些检查时所看到的内容。这意味着当缓存数据不正确描述工作树时,效果很难预测。有时一切正常!但有时它不会。当它失败时,它会意外失败并且很难调试。
我们对此做了什么
我们利用了 Git 能够使用多个索引这一事实。如上所述,如果您将额外的工作树添加到标准(非裸)存储库,每个添加的工作树都有自己的索引。4 但是当我们使用 --work-tree 或 @987654327 @ 覆盖标准工作树,或者为其他裸存储库提供一个,我们没有覆盖标准工作树的标准索引。使用GIT_INDEX_FILE 环境变量允许我们覆盖标准索引(其名称只是index)。
我们需要对除一个“额外”工作树之外的所有工作树执行此操作。我们与裸存储库一起使用的其中一个工作树可以使用标准索引,因此我们实际上只需要在此处的两个 git 命令之一上分配一个 GIT_INDEX_FILE 环境变量。但是为了对称性,或者添加第三个结帐的能力,我们可以每次都覆盖标准索引。
请注意,如果 bash 脚本的当前工作目录已经是裸存储库目录,则不需要 --git-dir 选项(或 GIT_DIR 环境变量),因此在许多情况下您可以省略 --git-dir=。为了简化脚本,您可以运行:
cd /var/control/project.git
在脚本的前面并省略每个 --git-dir= 选项。
还请注意,这些 git checkout -f 命令不提供提交哈希 ID 或分支名称,因此它们始终检查由特殊名称 HEAD 标识的任何提交。
4这些添加的工作树有自己的HEAD 引用和其他引用。我们这里不处理这个问题。这是否以及何时出现问题是另一个话题。