Subject: Re: bug: Removing branch and creating branch-directory with same name breaks

From: "brian m. carlson" <[email-masked]>
Date: Mon, 6 Jan 2025 22:25:39 +0000

On 2025-01-06 at 19:07:01, Matthias Braun wrote:
> (Note that I also tried this with latest git-2.47.1 after creating the repro script and it still fails there).
> 
> What did you do before the bug happened? (Steps to reproduce your issue)
> - Removed remote branch. Created new directory (for branch names)
>   with same name directory name as the previously used branch name.
>   After that `git fetch` fails.
> 
> Reproduction script for your convenience:

Thanks for the reproduction steps.  This is expected, and I'll explain
more below.

> ```
> #!/bin/bash
> 
> mkdir -p repro
> git init repro/remote.git
> git clone repro/remote.git repro/cloned
> pushd repro/cloned
> echo "hello" > hello.txt
> git add hello.txt
> git commit -m "test commit"
> git branch mystuff
> git push origin mystuff
> popd
> 
> git clone repro/remote.git repro/clone2
> 
> pushd repro/cloned
> git branch -D mystuff
> git push -d origin mystuff
> git branch mystuff/branch_in_subdir
> git push origin mystuff/branch_in_subdir
> popd
> 
> pushd repro/clone2
> git fetch    #  This fails as branch turned into directory
> popd
> ```
> 
> What did you expect to happen? (Expected behavior)
> 
> `git fetch` should work...
> 
> What happened instead? (Actual behavior)
> 
> `git fetch origin`
> error: cannot lock ref 'refs/remotes/origin/mystuff/branch_in_subdir': 'refs/remotes/origin/mystuff' exists; cannot create 'refs/remotes/origin/mystuff/branch_in_subdir'

git fetch does not by default delete remote tracking branches which no
longer exist on the remote.  That's because sometimes you want to keep
those around even though upstream does not.[0]

In this case, or if you just don't want to keep them around, you can use
`git fetch --prune origin` to prune those old branches when fetching, or
`git remote prune origin` to just prune and not fetch (and, of course,
these work with any remote, not just `origin`).  The `git fetch` manpage
mentions the `fetch.prune` and `remote.<name>.prune` options for you to
control this automatically as you see fit.

[0] At a previous employer, large projects were squashed-and-merged, and
I found keeping around the original history—and thus the original
branches—was invaluable to understanding why a change was made or who I
should talk to about a particular change if I had questions.
-- 
brian m. carlson (they/them or he/him)
Toronto, Ontario, CA