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.