Re: Concurrent fetch commands
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Dec 31, 2023, 17:27 UTC
- Message-ID
- <xmqqy1daffk8.fsf@gitster.g>
- In-Reply-To
- <c11ca0b3-aaf4-4a8d-80a1-3832954aa7aa@haller-berlin.de>
Stefan Haller <lists@haller-berlin.de> writes:
Show 6 quoted lines
> I can reliably reproduce this by doing > > $ git fetch&; sleep 0.1; git pull > [1] 42160 > [1] + done git fetch > fatal: Cannot rebase onto multiple branches.
I see a bug here.
How this _ought_ to work is
- The first "git fetch" wants to report what it fetched by writing
into the $GIT_DIR/FETCH_HEAD file ("git merge FETCH_HEAD" after
the fetch finishes can consume its contents).- The second "git pull" runs "git fetch" under the hood. Because it also wants to write to $GIT_DIR/FETCH_HEAD, and because there is already somebody writing to the file, it should notice and barf, saying "fatal: a 'git fetch' is already working" or something.
But because there is no "Do not overwrite FETCH_HEAD somebody else is using" protection, "git merge" or "git rebase" that is run as the second half of the "git pull" ends up working on the contents of FETCH_HEAD that is undefined, and GIGO result follows.
The "bug" that the second "git fetch" does not notice an already running one (who is in possession of FETCH_HEAD) and refrain from starting is not easy to design a fix for---we cannot just abort by opening it with O_CREAT|O_EXCL because it is a normal thing for $GIT_DIR/FETCH_HEAD to exist after the "last" fetch. We truncate its contents before starting to avoid getting affected by contents leftover by the last fetch, but when there is a "git fetch" that is actively running, and it finishes _after_ the second one starts and truncates the file, the second one will end up seeing the contents the first one left. We have the "--no-write-fetch-head" option for users to explicitly tell which invocation of "git fetch" should not write FETCH_HEAD.
Running "background/priming" fetches (the one before "sleep 0.1" you have) is not a crime by itself, but it is a crime to run them without the "--no-fetch-head" option. Since you have *NO* intention of using its contents to feed a "git merge" (or equivalent) yourself, you are breaking your "git pull" step in your example reproduction yourself.