I am new to git and was following the following excellent instruction from Missing Semester. About 1 hour in, they discuss remotes. I went through the process of creating a remote (as a sub-directory for testing), however, I purposefully deviated from the instructions because that helps my understanding. I pushed a branch to the remote but did not name it "master". I eventually realized there was no HEAD in this remote, and things just didn't work right. I looked at the git remote set-head command, and thought that would solve the problem. I don't think it did. What eventually worked was creating a branch called "master" on the remote, and HEAD automatically pointed to it. I did not see this requirement in the documentation. Is there a way to have a repository without a branch named "master"? Alternatively, if there is no branch named "master", how does one get the HEAD pointing to a branch after the remote is created?
TL;DR: you need to reach into the server (somehow—the how depends on the server) and have the server's Git set its HEAD
. (Note that GitHub have a clicky web button interface for this, under settings
and then branches
.)
Usually, though, you just start by having the server create its first branch having the name master
, after which everything works the way everyone expects. Note that if a server Git already has a branch named br1
, you can clone that server Git repository with:
git clone -b br1 url
on your client side, followed by:
git push origin br1:master
to ask that server to create the name master
, pointing to the same commit as your own br1
in your clone. Now the server does have a master
and all is back to normal.
All Git repositories have a HEAD. This is a basic requirement of Git: when Git goes to look for a repository, it makes several sanity checks on each directory it inspects. The directory must:
HEAD
that appears valid;refs/
sub-directory; andobjects/
sub-directory (unless overridden by setting GIT_OBJECTS_DIRECTORY
in the environment).Failing any one of these tests makes Git move on to the next candidate for a repository directory, or, if it has run out of candidates, give up and declare that there is no Git repository to be found.
The code that does this checking is in setup.c. The is_valid_ref
test is elsewhere (path.c
) and basically tests whether HEAD
is a symbolic link to refs/*
, or starts with the literal ASCII text ref: refs/
, or contains a valid hash ID. The first two tests are the same as testing whether a reference is a symbolic ref (see the git symbolic-ref
command).
A HEAD
file that contains a commit hash ID is a detached HEAD. This indicates that the Git repository is not on a branch at all. There is little more to be said about this (until we get to cloning, below, anyway). To set a detached HEAD in a repository in which you can run Git commands directly, use git switch --detach
or git checkout --detach
or git checkout
with any argument that automatically causes a detached HEAD condition, i.e., any reference to a commit that is not literally a branch name.
(There is no way to set a detached HEAD with the GitHub web interface.)
A symbolic reference can be made to a reference that does not exist. This is how a fresh, empty Git repository, with no branches, can be on branch master
even though branch master
does not yet exist. Hence, the branch to which HEAD
links, if HEAD
is not detached, may or may not actually exist—but there definitely will be a HEAD
.
A new, totally-empty repository, created by git init
, has a symbolic HEAD
that refers to the name master
.
(There is no way to set a HEAD reference to a branch that does not exist with the GitHub web interface, as far as I can tell. But a new repository is still created with HEAD
symbolically referring to master
.)
Note that a remote is just a string in your own local Git repository. That is, you might create the name origin
to hold the url https://github.com/user/project.git
or ssh://[email protected]/user/project.git
or some such.
Nothing you do with your local repository will change anything in some other Git over on GitHub or Bitbucket, so any tweaks you make here have no effect. You need to cause the Git over at GitHub, or Bitbucket, or whatever other site actually hosts the server, to do something to its Git repository, before any change you make will actually have any effect.
(For GitHub, you simply log in to GitHub and manipulate your repositories using their web pages. This lets you do exactly those things they allow you to do, which is less than everything you could do if you could log in to their servers.)
When you clone a repository using:
git clone [<options>] <url>
the options
allow you to specify, among other things:
What to call the other Git: the name of the remote. Use -o xyzzy
to change the name from the default origin
to xyzzy
, for instance.
What branch name to check out in step six (see below). For instance, git clone -b plugh
tells your Git to git checkout plugh
in step six.
If you leave out the -b
option, your Git asks their Git which branch they recommend. Your Git will, in general, then attempt to git checkout
this branch name in step six.
The method and details behind this recommendation have changed over time. In the distant past, your Git read their Git's HEAD
hash ID, if they supplied one, and guessed which branch name that meant. In modern Git, their Git can supply the literal text string read from the symbolic HEAD
reference. Your Git can choose to use this, or ignore it.
The git clone
command is shorthand for a six-step process:
Run mkdir
(or whatever your computer's command may be) to create a new, empty directory, in which the new Git repository will be created. The remaining five steps run in this new empty directory.
Run git init
to create a Git repository (a .git
sub-directory within the new directory).
Run git remote add
to add a remote. The name of the remote will be origin
unless you used the -o
option. The URL for the remote will be the URL you gave to git clone
.
Run any extra git config
commands required, e.g., from -c
options.
Run git fetch origin
(or whatever remote name you used), to obtain commits and populate your repository with remote-tracking names like origin/master
based on whatever branch names exist in the other repository.
Run git checkout
(pre-2.23) or git switch -c
(Git 2.23 or later), to create a new branch and check out its commit.
The branch name used in step six is the one from your -b
option. Your Git will look at their branch (and tag!) names and if your -b
option matches one of their branch or tag names, will use that name. If the name is a tag name, your Git will go into detached HEAD mode on the appropriate commit.
If you did not use -b
, your Git will ask their Git which branch they recommend, as described above. If that is a name that works, your Git will create that name and check out that commit.
If both of those fail, your Git will fall back on the name master
. If that name also fails, your Git will tell you that step six failed: that you have a valid repository, and you got it all cloned, but there is no current branch and commit. It will be up to you to rectify this situation.
master
Suppose you clone a repository from some URL, and that repository:
br1
and br2
, for instance; butmaster
.Suppose further that you, on your git clone
line, did not supply a -b
option. Then:
In step 5, your git fetch
obtained their br1
and br2
names and made your origin/br1
and origin/br2
names. Since they have no master
, your Git did not make an origin/master
.
In step 6, you did not supply -b
, so your Git asks their Git which branch they recommend.
If you have not taken any special action, the branch they'll recommend is the one whose symbolic name is in their HEAD
. If that symbolic name is master
, they will recommend their master
—which of course does not exist. Your Git will be puzzled by this recommendation (it doesn't work) and will use its own built in fallback: try master
. This too will not work and you will see what you saw.
Of course, if they do have a branch named master
, your step 5 will have created your origin/master
so your step 6 will be able to create your own master
based on their origin/master
, and all will be well.
If you have them change their symbolic name HEAD
to point to their br2
branch, the recommendation you will get in step 6 will be that your Git should create a branch named br2
based off their br2
, which is now (via step 5) your origin/br2
, and that will all work well too. But you need to reach into the server somehow and get them to change their recommendation.