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