4

I've been using the following command to update the local master when I'm not on master:

git fetch origin master:master

However, today, it stopped working on one of the repo clones I'm working on. It fails with an error:

fatal: refusing to fetch into branch 'refs/heads/master' checked out at '/path/to/project/directory'

On another clone of the same repo it works fine. Any idea what might be the cause? Note that I am not on the master branch when invoking the command.

I'm on macOS Monterey 12.6 (21G115) with Git 2.38.0 from Homebrew.

More info (anonymized):

$ git worktree list
/path/to/project/directory  aa00aa0a0a0 [my-current-branch]
$ git branch -vv
  main                 bb11bb1b1b1 Title of the commit on main
  master               cc22cc2c2c2 [origin/master] Title of the commit on master
* my-current-branch    aa00aa0a0a0 [origin/my-current-branch] Title of the commit on my-current-branch

There are more branches on the list but that shouldn't be relevant. You can see master & my-current-branch are up to date and main is not right now.

Also:

$ git remote show origin
* remote origin
  Fetch URL: git@github.com:my-org/my-repo.git
  Push  URL: git@github.com:my-org/my-repo.git
  HEAD branch: master
  Remote branches:
    main                 tracked
    master               tracked
    my-current-branch    tracked

The output here is huge as we have a lot of branches but other ones should be irrelevant. There's only a single remote: origin.

mgol
  • 1,362
  • 15
  • 20
  • 3
    I _think_ that you have a worktree that is using that branch. Can you check with `git worktree list`? – eftshift0 Oct 19 '22 at 12:16
  • @eftshift0 no, it doesn't include that branch; the only thing printed is: `/path/to/project/directory aa00aa0a0a0 [my-current-branch]`. – mgol Oct 19 '22 at 12:44
  • 2
    The previous git error seems to suggest that master is checked out at that directory? – evolutionxbox Oct 19 '22 at 12:49
  • What is your current branch? The error message claims that it is `master`. – knittl Oct 19 '22 at 12:58
  • OK.... Maybe this kind of makes sense. If you are on `master`, why do you specify `master:master`? Sounds like git is making an extra check because of that. Try `git fetch origin master` – eftshift0 Oct 19 '22 at 13:00
  • Actually... you are not _pulling_.... that syntax for fetching looks _funky_ to me, though I might be wrong as git didn't complain. – eftshift0 Oct 19 '22 at 13:04
  • I am _not_ on master. That's the problem. – mgol Oct 19 '22 at 14:48
  • This is a common syntax for synchronizing a branch you are not on to its remote version and it worked fine so far... – mgol Oct 19 '22 at 14:49
  • I see, interesting. Glad to know you were able to solve. I, personally, try to avoid having local copies of remote branches _but_ I know it's not a particularly popular approach. – eftshift0 Oct 19 '22 at 15:44
  • I was not able to solve the issue. I still don't understand why this doesn't work. – mgol Oct 19 '22 at 16:17
  • Are there changes in master that do not exist in the remote? As stated [here](https://stackoverflow.com/a/40125870/10871900) or [here](https://stackoverflow.com/a/17722977/10871900), it needs to be able to be fast-forwarded. If you want to do a non fast-forward merge, try `git fetch origin +master:master` but not sure what would happen with merge conflicts... – dan1st Oct 19 '22 at 16:32
  • But the best solution is probably to stash, checkout, pull, checkout and pop the stash again as that would allow you to deal with merge conflicts etc. – dan1st Oct 19 '22 at 16:38
  • There are no changes on the local `master` that don't exist on the remote. Even if I checkout `master`, do a (successful) `git pull` and return to the original branch and invoke `git fetch origin master:master`, it still fails. At this point, the local & remote `master` point to the same commit and yet it still fails. – mgol Oct 19 '22 at 16:46
  • What is the output of `git branch -vv` and `git remote show origin`? – dan1st Oct 19 '22 at 16:48
  • @dan1st I added this info to the question as it's too large for a comment. – mgol Oct 19 '22 at 17:09

1 Answers1

1

The error message:

fatal: refusing to fetch into branch 'refs/heads/master' checked out at '/path/to/project/directory'

indicates that Git is certain that there is an added working tree. You should be able to see this working tree in git worktree list output, but if your Git is modern enough—and 2.38.0 certainly is—it should also show up in git branch -vv output, e.g.:

$ git worktree add ../xxx -b foo
Preparing worktree (new branch 'foo')
...
$ git branch -vv
+ foo             c3ff4ce (<path ending in xxx>) <commit subject>
* main            c3ff4ce <same commit subject>
  ...
$

What could have happened is that you did have an added working tree, but then you removed it, and git worktree prune cleaned it up:

$ git worktree list
<path1>                      c3ff4ce [main]
<path2, ending in xxx>       c3ff4ce [foo]
$ rm -rf ../xxx
$ git worktree prune
$ git worktree list
<path1>                      c3ff4ce [main]
$ 

Note that git worktree prune is a period maintenance task that git gc --auto will run if and when it thinks it should. (If you use git worktree remove to remove added working trees, pruning never does anything, but since it was designed with this kind of lazy update ever since Git 2.5 added git worktree add, the maintenance tasks still have to check.)

As for git fetch origin master:master itself, you added in a comment:

This is a common syntax for synchronizing a branch you are not on to its remote version and it worked fine so far...

I would not call it common myself, though it is known and mentioned in various StackOverflow answers. I would not recommend its use: don't do that, just refer to origin/master directly when you want to get the current hash ID stored in origin/master. If you're not actually using master here for anything, just go ahead and delete it entirely, so that you're not tempted to use it.

The one remaining note I'd add here is that since you're using a homebrew-installed Git on macOS, be aware of (and careful about) the multiple-Git-version issue: there's probably a /usr/local/bin/git or /opt/.../git and a /usr/bin/git, one being the Apple Git and one being the homebrew Git. Which one any particular command runs will depend on $PATH.

torek
  • 448,244
  • 59
  • 642
  • 775
  • `git worktree list` only shows my current branch. `git branch -vv` only prepends my current branch with `*` and no branch is prepended with `+`. I added these to my original post. – mgol Oct 20 '22 at 09:26
  • Has the problem also stopped occurring? – torek Oct 20 '22 at 09:27
  • There are valid reasons to want a current version of `master` locally, e.g. a tool I use to count the size of produced JS assets in one of my projects caches the values per branch and then shows a summary. If I want to have the data for `master` presented, I have to have it locally. I'm sure there are other reasons as well. – mgol Oct 20 '22 at 09:27
  • No, the problem is still there. – mgol Oct 20 '22 at 09:27
  • OK, then you have a setup ripe for debugging. Build a debug version of Git, plant a breakpoint at the place that reports this, and see what's going on. (Build on macOS is kind of a pain; I run a Linux VM with Ubuntu and build there, on my mac, for any Git development I do, but the problem might not show up there.) – torek Oct 20 '22 at 09:28
  • I must be using the Homebrew version, `which git` returns `/usr/local/bin/git`. All the commands, etc., work in the same way in the new Terminal tab as well. – mgol Oct 20 '22 at 09:29
  • @torek If you don't recommend `git fetch origin master:master`, can you be explicit about the alternative git command you recommend? – bit Mar 02 '23 at 12:02