I am following this tutorial and it has been working really well. We now want to run several accounts on the server with the same package and I am trying to modify post-receive but I am not doing something right and cannot find the answer. The goal is to have separate cpanel type accounts running the same code from our github repo, with updates happening to all accounts whenever we push changes.
The original code in post-receive is this:
#!/bin/bash
git --work-tree=/path/to/firstInstance --git-dir=/var/control/project.git checkout -f
and it works as expected, whenever we push from our local repo and update github our remote server is also updated to /var/control/project.git which then gets pushed to the first account.
When I add another line for a different work-tree, so there are 3 lines which read:
#!/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
I can add new files to both instances but deleting only happens on the second instance. Clearly I am not doing it right but I cannot find what I am looking for here or elsewhere online. Any help would be greatly appreciated.
You are (presumably1) using a bare repository, which is the right thing to do, but you're hitting a snag that is only obvious after you have become a Git Guru. The trick is that you need one index per work-tree.2 We'll get to defining all these terms in a moment, but the TL;DR part is to use this somewhat magic sequence:
This can definitely be simplified; to see how, read on.
1The instructions in your link say to use
git init --bare, so I assume you are doing that.2There are other tricks that will work, but I'm going with this one.
What's going on here
A normal Git clone consists of three parts, as it were:
Using one of these normal repositories, the
git worktree addcommand can add more work-trees. Each one has an index-and-work-tree pair. They are bound together (somewhat loosely, but enough to always treat them as a pair).A bare clone omits the work-tree without omitting the index. This means that your bare repository has a free index: the work-tree that it would be bound to doesn't exist. You can therefore run
git --work-tree=path command argument1 argument2 .... This assigns, temporarily, a work-tree to this bare repository. The (single) index and this work-tree are now bound together. The one command you supply is run, using the standard index and that work-tree.The problem is that that one standard index now describes that work-tree, and not any other work-tree. If you run
git --work-tree=otherpath command ..., you invoke Git with its standard index and that other path bound together. Git assumes that the index correctly describes this other work-tree. When it doesn't, things sometimes fail. More precisely, the index keeps track of what's in the work-tree, and Git partly just assumes that it's correct.33Git does some checking. The index has in it cached data about that work-tree, and Git will verify that at least some of that data remain correct. Exactly how much data it trusts and how much it doesn't trust depend on what it sees as it does these checks. This means the effect, when the cache data don't describe the work-tree correctly, is very difficult to predict. Sometimes everything works! But sometimes it doesn't. When it fails, it fails unpredictably and is very hard to debug.
What we do about it
We make use of the fact that Git is capable of using more than one index. As we noted above, if you add extra work-trees to a standard (non-bare) repository, each added work-tree gets its own index.4 But when we use
--work-treeorGIT_WORK_TREEto override the standard work-tree, or supply one for an otherwise bare repository, we have not overridden the standard index for the standard work-tree. Using theGIT_INDEX_FILEenvironment variable allows us to override the standard index (whose name is justindex).We need to do this for all but one "extra" work-tree. One of the work-trees we use with the bare repository can use the standard index, so we really only need one
GIT_INDEX_FILEenvironment variable assignment on one of the twogitcommands here. But for symmetry, or the ability to add a third checkout, we can just override the standard index each time.Note that the
--git-diroption (orGIT_DIRenvironment variable) is not required if the current working directory of the bash script is already the bare repository directory, so in many cases you could omit the--git-dir=. To simplify the script, you could run:at the front of the script and omit each of the
--git-dir=options.Note also that these
git checkout -fcommands do not supply a commit hash ID or branch name, so they always check out whatever commit is identified by the special nameHEAD.4These added work-trees get their own
HEADreference and others as well. We aren't taking care of this issue here. Whether and when that is a problem is another topic.