threads / discuss / 44897

"git fetch -p" incorrectly deletes branches

Subject: "git fetch -p" incorrectly deletes branches

## tl;dr

2 messages between Jan 17, 2017 and Jan 26, 2017.

replies: 1people: 2as markdown or json

Reimar Döffinger· Jan 17, 2017, 06:04 UTC · lore

Hello! The command: git fetch -p -v origin master:refs/heads/test

Deletes refs/heads/test every second time when run repeatedly:
$ git fetch -p -v origin master:refs/heads/test
From https://github.com/git/git
 * [new branch]          master     -> test
 = [up to date]          master     -> origin/master
$ git fetch -p -v origin master:refs/heads/test
From https://github.com/git/git
 - [deleted]             (none)     -> test
 = [up to date]          master     -> test
 = [up to date]          master     -> origin/master

(the command is the result of cutting down the test case, so yes it is rather silly, but the issue appears in much less obviously silly cases and causes a lot of confusion) This is specific to the case of specifying the origin branch without "full path" AND the right side with. Wild-guess on cause: "master" is auto-expanded into both "refs/tags/master" and "refs/heads/master" and instead of fetching either/merging the result, both are fetched. Combined with a time-of-check/time-of-use style race condition on the code that checks if a ref is "up to date" on top of it, it would result in this behaviour. Also note that this behaviour appears also when fetch.prune=yes is set in the config (instead of -p on the command-line), which makes it much less obvious and there is no option to turn of prune just for that command to work-around this. I hope someone has the time to make sure nobody else has to debug this ever again ;-)

Regards, Reimar Döffinger

Jeff King· Jan 26, 2017, 21:18 UTC · re: Reimar Döffinger · lore

Re: "git fetch -p" incorrectly deletes branches

On Tue, Jan 17, 2017 at 07:04:28AM +0100, Reimar Döffinger wrote:
Show 11 quoted lines
> Deletes refs/heads/test every second time when run repeatedly:
> 
> $ git fetch -p -v origin master:refs/heads/test
> From https://github.com/git/git
>  * [new branch]          master     -> test
>  = [up to date]          master     -> origin/master
> $ git fetch -p -v origin master:refs/heads/test
> From https://github.com/git/git
>  - [deleted]             (none)     -> test
>  = [up to date]          master     -> test
>  = [up to date]          master     -> origin/master

Hmm. It seems like the problem is that "-p" is saying "the other side does not have refs/heads/test; we must prune it". But I think it is probably nonsense to apply pruning to a non-wildcard refspec.

> Also note that this behaviour appears also when fetch.prune=yes
> is set in the config (instead of -p on the command-line),
> which makes it much less obvious and there is no option to turn
> of prune just for that command to work-around this.

There is a separate issue of whether it is sane to apply fetch.prune to a refspec given on the command line; I can imagine it as surprising, to say the least.

I think "--no-prune" would disable it, though.
-Peff

← back to recent threads