Home > Enterprise >  How do I make `origin/HEAD` work with partial fetch settings?
How do I make `origin/HEAD` work with partial fetch settings?

Time:11-03

In a typical "regular" git clone, one ends up with .git/config as follows:

[remote "origin"]
    url = [email protected]:orgname/reponame.git
    fetch =  refs/heads/*:refs/remotes/origin/*     

and then git show origin/HEAD works fine.

However, I don't want all branches to be fetched, only prod and ones prefixed with jakub/, so my .git/config is as follows:

[remote "origin"]
    url = [email protected]:orgname/reponame.git
    fetch =  refs/heads/prod:refs/remotes/origin/prod
    fetch =  refs/heads/jakub/*:refs/remotes/origin/jakub/*

(I didn't do a git clone, but created a .git/config like above, and then did git fetch).

However, with that setup, git show origin/HEAD no longer works:

fatal: ambiguous argument 'origin/HEAD': unknown revision or path not in the working tree.

I tried to add the following to .git/config but it doesn't work:

    fetch =  refs/heads/HEAD:refs/remotes/origin/HEAD
$ git fetch
fatal: couldn't find remote ref refs/heads/HEAD

What's the proper way to make origin/HEAD work with partial fetching?

CodePudding user response:

If the HEAD branch of the remote repository is one of the branches configured in your fetch refspecs, then this should work:

git remote set-head origin -a

This will query the remote for its HEAD and set origin/HEAD to point to the corresponding remote-tracking branch in your repository.

If the remote HEAD points to a branch thst is not covered by your fetch refspec, then you would have to add a fetch refspec for that branch, fetch it, and then run the above command.

CodePudding user response:

The name origin/HEAD is a symbolic ref. Aside from the initial git clone, the user-facing command for working with this is git remote set-head.

For a symbolic ref to work, the target of that symbolic ref must exist. The target is shown on the right of the -> in git branch -r or similar output:

  origin/HEAD -> origin/master

Here, the target of origin/HEAD is origin/master. If I did not have the name origin/master in my own clone here, origin/HEAD would not work.

So: what you need is to fetch and create origin/thing, where thing is the name of the "default branch" in the repository over at origin. Since:

    fetch =  refs/heads/*:refs/remotes/origin/*

creates and updates a remote-tracking name for each branch name in that repository, whichever branch name is the default branch1 will2 exist here as origin/thing and it all works the way you want.

When you make a single-branch clone,3 however, you instruct your Git to fetch only one specific branch name. Adding more branches (with git remote set-branches) lets you add to the collection.

For Git to create origin/HEAD in the first place, Git demands that the target actually exist. So after, e.g.:

git clone --single-branch -b next https://github.com/git/git

I get a new clone of the Git repository for Git in which only two names exist:

$ git branch -a
* next
  remotes/origin/next

Note the lack of an origin/HEAD. But now comes the guessing game: which remote-tracking name(s) should I add? There are a few ways to find out, including using either of git ls-remote --symref or git remote set-head:

$ git ls-remote --symref origin HEAD
ref: refs/heads/master  HEAD
c03801e19cb8ab36e9c0d17ff3d5e0c3b0f24193        HEAD
$ git remote set-head origin --auto
error: Not a valid ref: refs/remotes/origin/master
origin/HEAD set to master

The last output line is a lie: because I don't have an origin/master, origin/HEAD did not get set to master. But the output here shows which branch I need to "git remote set-branches --add":

$ git remote set-branches --add origin master
$ git fetch origin
From github.com:git/git
 * [new branch]            master     -> origin/master
$ git branch -r
  origin/master
  origin/next
$ git remote set-head origin --auto
origin/HEAD set to master
$ git branch -r
  origin/HEAD -> origin/master
  origin/master
  origin/next

Now it is done.


1Git uses the term default branch to mean "whichever branch name is stored in HEAD in a repository that you cloned". GitHub in particular let you change this by navigating to the repository in their web interface and using various clicky buttons and such to choose any of the branch names. This of course assumes you have permission to set them.

2Technically, will is too strong: the default branch setting in HEAD is up to the server host system, and Google Code, for some reason known only to the Google Code people, do not provide a way to set this—and the setting is stuck on "master" for many repositories that have only a "main". In this case, origin/HEAD points to a nonexistent name.

3Note that while git clone --single-branch is the obvious way to do this, git clone --depth turns on single-branch-ness. Note, too, that the term for this is single-branch clone, even if it's a two or three branch clone; partial clone refers to a new feature that's gradually coming to Git.

  • Related