First, I know my question has already been asked and dismissed as a Git abuse (see for example this question). I'll try to explain my use case.
I need to make periodically (cron job) special lengthy processing on a source version in the repository. In order not to disturb the repo, I extract the desired version. Unfortunately, there is nothing like export
in Git. Documentation recommendes to use archive
for that. Since I want an exact copy of the source tree (as it appears in the working directory), I must untar the archive in some target location.
In fact, this really looks like a checkout
but checkout
also changes the index, which then causes mayhem for the user surprised by the unexpected change.
Many answers recommend to clone
the repo in this situation and then play innocuously on the clone. I don't want to proceed likewise because I must extract simultaneously many versions and I don't want to waste repo storage for each copy (think for example of monster repos like the Linux kernel).
I don't want either to use worktree
because my copies will be badly tweaked and I don't want to incur the risk of any commit from these fancy copies back into the repo. The copies must be forgotten by Git as soon as they are made.
I finally implemented an export
equivalent as a short script:
ref=$(git rev-parse --symbolic-full-name HEAD)
git --work-tree=<somewhere> checkout -f -q <branch_or_tag> -- '*'
git reset ${ref}
First line saves present position (commit id) in the repo. Second line checks out the desired version without changing HEAD
but simultaneously sets the index to the checked out commit. Third line restores the initial position.
This works fine against a bare repository since you are not supposed to commit
there, only to push
or pull
. Apart from the fact that you create an index file, the repo is apparently not disturbed.
However, if the script is run against a local repository (with an associated working directory), there is a small risk during its lifetime. checkout
though fast is not instantaneous. The index is changed until reset
completion. If any commit is attempted during this time frame, the repo will be damaged with faulty patches because the index is not what user expects.
Consequently, I ask again @schuess's question (see link above):
Is there a way to lock a Git repository to prevent any access?
The lock will be short-lived. It should protect against any state change in the repository.
Presently I live without but one day or later I will be caught; therefore I prefer to guard against this race condition.
Reminder: I am perfectly aware that I'm trying to play tricks on Git's back and I should not do that. A better solution would certainly be to implement a true export
script not relying on checkout
. See also above why I don't use clone
.