From: Dragan Simic Date: Sun, 31 Dec 2023 17:41:15 GMT Subject: Re: Concurrent fetch commands Message-ID: In-Reply-To: On 2023-12-31 18:27, Junio C Hamano wrote: > Stefan Haller writes: > >> 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. Thank you very much for this highly detailed explanation.