Issues with Git (HEAD points to an unborn branch (master))

This happened to me due to some corruption, and the answer from @CBBailey didn't work at first.

To fix the previous corruption I had pushed from my working clone like:

git push origin :refs/heads/master

This caused the refs/heads/ directory of the bare repo to be empty, hence why I encountered this problem of HEAD pointing to an "unborn branch". In my case this was resolved by just doing another:

git push --all

This put refs/heads/master back in place, so HEAD worked again.


In a non-bare repository this the checked out branch, in a bare repository it just means it's the default branch checked out for clones.

Git will now be aware If that default branch does not exist yet.

With Git 2.31 (Q1 2021), "git clone"(man) tries to locally check out the branch pointed at by HEAD of the remote repository after it is done, but the protocol did not convey the information necessary to do so when copying an empty repository.
The protocol v2 learned how to do so.

See commit 4f37d45, commit 3983540, commit 59e1205 (05 Feb 2021) by Jonathan Tan (jhowtan).
(Merged by Junio C Hamano -- gitster -- in commit 69571df, 17 Feb 2021)

ls-refs: report unborn targets of symrefs

Signed-off-by: Jonathan Tan

When cloning, we choose the default branch based on the remote HEAD.
But if there is no remote HEAD reported (which could happen if the target of the remote HEAD is unborn), we'll fall back to using our local init.defaultBranch.

(This is what CB Bailey's answer mentioned)

Traditionally this hasn't been a big deal, because most repos used "master" as the default.

But these days it is likely to cause confusion if the server and client implementations choose different values (e.g., if the remote started with "main", we may choose "master" locally, create commits there, and then the user is surprised when they push to "master" and not "main").

To solve this, the remote needs to communicate the target of the HEAD symref, even if it is unborn, and "git clone"(man) needs to use this information.

Currently, symrefs that have unborn targets (such as in this case) are not communicated by the protocol.

Teach Git to advertise and support the "unborn" feature in "ls-refs" (by default, this is advertised, but server administrators may turn this off through the lsrefs.unborn config).
This feature indicates that "ls-refs" supports the "unborn" argument; when it is specified, "ls-refs" will send the HEAD symref with the name of its unborn target.

This change is only for protocol v2.
A similar change for protocol v0 would require independent protocol design (there being no analogous position to signal support for "unborn") and client-side plumbing of the data required, so the scope of this patch set is limited to protocol v2.

The client side will be updated to use this in a subsequent commit.

git config now includes in its man page:

lsrefs.unborn

May be "advertise" (the default), "allow", or "ignore".
If "advertise", the server will respond to the client sending "unborn" (as described in protocol-v2.txt) and will advertise support for this feature during the protocol v2 capability advertisement.
"allow" is the same as "advertise" except that the server will not advertise support for this feature; this is useful for load-balanced servers that cannot be updated atomically (for example), since the administrator could configure "allow", then after a delay, configure "advertise".

technical/protocol-v2 now includes in its man page:

If the 'unborn' feature is advertised the following argument can be included in the client's request.

unborn
The server will send information about HEAD even if it is a symref pointing to an unborn branch in the form "unborn HEAD symref-target:<target>".

technical/protocol-v2 now includes in its man page:

obj-id-or-unborn = (obj-id | "unborn")
ref = PKT-LINE(obj-id-or-unborn SP refname *(SP ref-attribute) LF)


Again, this feature is available only when using protocol v2, as illustrated in Git 2.31.1 (Q1 2021):

See commit 5f70859 (17 Mar 2021) by Jonathan Tan (jhowtan).
(Merged by Junio C Hamano -- gitster -- in commit cc930b7, 19 Mar 2021)

t5606: run clone branch name test with protocol v2

Signed-off-by: Jonathan Tan

4f37d45 ("clone: respect remote unborn HEAD", 2021-02-05, Git v2.31.0-rc0 -- merge listed in batch #9) introduces a new feature (if the remote has an unborn HEAD, e.g. when the remote repository is empty, use it as the name of the branch) that only works in protocol v2, but did not ensure that one of its tests always uses protocol v2, and thus that test would fail if GIT_TEST_PROTOCOL_VERSION=0 (or 1) is used.
Therefore, add "-c protocol.version=2" to the appropriate test.

Example:

git -c init.defaultBranch=foo init --bare empty
git -C empty config lsrefs.unborn advertise
git -c init.defaultBranch=up -c protocol.version=2 clone empty whats-up

The default branch name for the local cloned repository (git -C whats-up symbolic-ref HEAD) won't be up (even though init.defaultBranch was explicitely set to 'up'), but whatever the default name was for the remote (empty) repository: in this case 'foo' (because the remote repository has set lsrefs.unborn to advertise)


Before Git 2.34 (Q4 2021), "git clone"(man) from a repository whose HEAD is unborn into a bare repository didn't follow the branch name the other side used, which is corrected.

See commit 6b58df5 (20 Sep 2021) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit ac162a6, 03 Oct 2021)

clone: handle unborn branch in bare repos

Signed-off-by: Jeff King

When cloning a repository with an unborn HEAD, we'll set the local HEAD to match it only if the local repository is non-bare.
This is inconsistent with all other combinations:

remote HEAD       | local repo | local HEAD
-----------------------------------------------
points to commit  | non-bare   | same as remote
points to commit  | bare       | same as remote
unborn            | non-bare   | same as remote
unborn            | bare       | local default

So I don't think this is some clever or subtle behavior, but just a bug in 4f37d45 ("clone: respect remote unborn HEAD", 2021-02-05, Git v2.31.0-rc0 -- merge listed in batch #9).
And it's easy to see how we ended up there.
Before that commit, the code to set up the HEAD for an empty repo was guarded by "if (!option_bare)".
That's because the only thing it did was call install_branch_config(), and we don't want to do so for a bare repository (unborn HEAD or not).

That commit put the handling of unborn HEADs into the same block, since those also need to call install_branch_config().
But the unborn case has an additional side effect of calling create_symref(), and we want that to happen whether we are bare or not.

This patch just pulls all of the "figure out the default branch" code out of the "!option_bare" block.
Only the actual config installation is kept there.

Note that this does mean we might allocate "ref" and not use it (if the remote is empty but did not advertise an unborn HEAD).
But that's not really a big deal since this isn't a hot code path, and it keeps the code simple.
The alternative would be handling unborn_head_target separately, but that gets confusing since its memory ownership is tangled up with the "ref" variable.

There's just one new test, for the case we're fixing.
The other ones in the table are handled elsewhere (the unborn non-bare case just above, and the actually-born cases in t5601, t5606, and t5609, as they do not require v2's "unborn" protocol extension).


"git clone"(man) from a repository with some ref whose HEAD is unborn did not set the HEAD in the resulting repository correctly, which has been corrected with Git 2.38 (Q3 2022).

See commit daf7898 (11 Jul 2022), and commit cc8fcd1, commit 3d8314f, commit f77710c (07 Jul 2022) by Jeff King (peff).
(Merged by Junio C Hamano -- gitster -- in commit cf92cb2, 19 Jul 2022)

clone: move unborn head creation to update_head()

Signed-off-by: Jeff King

Prior to 4f37d45 ("clone: respect remote unborn HEAD", 2021-02-05, Git v2.31.0-rc0 -- merge listed in batch #9), creation of the local HEAD was always done in update_head().
That commit added code to handle an unborn head in an empty repository, and just did all symref creation and config setup there.

This makes the code flow a little bit confusing, especially as new corner cases have been covered (like the previous commit to match our default branch name to a non-HEAD remote branch).

Let's move the creation of the unborn symref into update_head().
This matches the other HEAD-creation cases, and now the logic is consistently separated: the main cmd_clone() function only examines the situation and sets variables based on what it finds, and update_head() actually performs the update.

See also "How to clone a bare git repo with no commits and get the correct HEAD ref during the clone?".


You don't have to have a master branch but you do have to have a "default" branch in any git repository. In a non-bare repository this the checked out branch, in a bare repository it just means it's the default branch checked out for clones.

This default branch is called HEAD and must always exist in a valid git repository. If you've removed the branch that HEAD was pointing at you can reset to a valid branch it with:

git symbolic-ref HEAD refs/heads/new-main-branch

Tags:

Git