Skip to content

operations: Fix transactions when deleting refs

Patrick Steinhardt requested to merge pks-operations-manual-reftx-hook-only into master

When deleting a reference, git needs to delete both the loose reference and the packed-refs reference which would get unshadowed by deleting the loose ref. Due to implementation details of git, this is done in two transactions: first git deletes the packed-refs ref and then it will delete the loose ref so that there cannot be a race where the packed ref can briefly be seen by other processes.

Given that git uses two transactions, it will also invoke the reference-transaction hook twice: for the first transaction we'll see a deletion of the reference with no old value provided, and only afterwards will we see the second deletion of the ref with the actual old value which we expect git to delete. This is problematic though in the context of strong consistency: we now depend on how refs are packed. If one node taking part in a transaction has the reference both as packed and as loose ref while a second node only has it as loose ref, then we would see two invocations of the reference-transaction hook on the former node, but only a single invocation on the latter node. As a result, the transaction would fail.

Unfortunately, we cannot really discern cleanups of the packed-refs file, and neither can we carry any state across different transactional votes right now. It's thus not really infeasible to try and come up with logic which filters the votes based on whether git is just trying to remove currently-shadowed refs or not. But luckily, we don't have to in this context: we are already performing a vote manually by executing the reference-transaction hook. And given that we vote on the old value which we've looked up which we then also pass to git-update-ref(1), this manual vote is also race free.

So let's fix the issue by disabling hooks for git-update-ref(1).

Fixes #3443 (closed)

Merge request reports