Edit: there's some very specific (and perhaps CentOS-specific) problem with separate Git and work-tree directories in the very old Git version 1.7.1 in use here, such that for this one specific case, --work-tree=/home/marweldc/app
causes Git to be unable to travel back and forth between the Git directory and the work-tree. (Other work-tree paths do not cause the problem.)
Git fails to notice its own failure to get back to the bare repository, and then is unable to do anything with branch names (since it could not get back to the repository it is likely to fail at everything at this point).
A more modern Git probably does not have the bug in the first place, or would notice the failure to switch back and forth between work-tree and bare repository.
Meanwhile, specifying --git-dir=<path>
seems to work around the problem.
Original (general) answer is below.
This:
fatal: You are on a branch yet to be born
means just what it says, although what it says may be confusing. :-) You really are "on" some branch that does not yet exist.
(It is not clear which branch you are on—you may have a "detached HEAD", as Git calls it—but it does seem as though you no longer have a master
branch, if you ever did.)
Short version
Use git branch
to see what branch you are on now, and what branches you have available. Use git symbolic-ref HEAD refs/heads/master
to forcibly set the bare repository's HEAD
back to the master
branch. For some other branch named B, use refs/heads/B
.
Long-form answer, i.e., what's going on, follows.
Whether or not a repository is bare, it still has a current branch
In any ordinary, non-bare repository, you can see what branch you are on by running git status
. But git status
looks at the work-tree, so in a bare repository, git status
refuses to run: there is no work-tree.
Another way to see what branch you are on is to run git branch
:
$ git branch
diff-merge-base
* master
stash-exp
This works in both bare and non-bare repositories. The *
goes by the name of the current branch.
How, in a regular repository, do you change which branch you're on?
The answer1 is: git checkout
. For instance, git checkout master
puts you (or me) on master
, and git checkout stash-exp
puts you (or me) on stash-exp
.
1There is one other way, using a plumbing command, but you don't normally want to use that as it can mess with the difference between current commit, index, and work-tree. But since a bare repository has no work-tree, this becomes ... well, "safe" is too strong, but we can say "much less dangerous".
How, in a bare repository, do you change which branch you're on?
The answer is still git checkout
.
When you check out a branch in a bare repository, this uses, and changes, your current branch in exactly the same way as when you check out a branch in a non-bare repository.
Of course, you can't git checkout
a branch in a bare repository, because that updates the work-tree. Except, you can, when you use git --work-tree=... checkout ...
. You supply the name of the branch to check out, and that writes the new branch name into HEAD
as usual. If you check out a commit by hash ID, that detaches HEAD
as usual.
Unborn (orphan) branches
But there's one more special case: if you set HEAD
to the name of a branch that does not yet exist (as you would with git checkout --orphan
for instance), that puts the name into HEAD
without creating the branch. That's normal enough in a regular (non-bare) repository, except that you only see it in two cases:
When you first create a new, empty, repository. You're on master
, but master
does not yet exist. You resolve this situation by putting a commit in the repository, which goes onto master
, which creates master
. (The new commit is a root commit, i.e., has no parent commit.)
When you use git checkout --orphan
: this sets you up in the same way as when you're in a new, empty, repository, by writing the name of the branch into HEAD
as usual, but without creating the branch. You resolve this situation by writing a new commit, which goes onto the unborn branch, which creates the branch, which is now born (exists, pointing to the new root commit you just made.)
Doing the same sort of thing in a bare repository
Obviously, you can't do this in the usual way in a bare repository, because the usual way is to work with the work-tree, git add
things into the index, and git commit
. A bare repository has no work-tree. (It does still have the index, and git checkout
, which you can do when you supply a work tree with --work-tree
, still writes through the index. This is kind of tricky and messes with many people's post-receive deployment hooks, since they don't understand the index.)
What you can, and do all the time, do in a bare repository is receive git push
es. When you receive a push, you accept requests (or commands) from another Git of the form:
- Please set your
master
branch to commit 1234567
- Delete branch
testing
(It's up to you to decide whether and how to check these requests, in a pre-receive
or update
hook. If you do nothing special, you get Git's default built-in checks, which allow anyone to create or delete any branch or tag, but only allow fast-forward pushes for branches.)
Suppose, for instance, that are, in your bare repository, on branch master
, and branch master
does not yet exist. Then someone out there on the Interwebs connects to your server and says: "hey, you, bare Git repository, have some commits here, and now create branch master
pointing to commit 1234567
!" In this case, assuming you accept this request / command, once your Git is done serving them, you do have a master
now. This takes you from:
fatal: You are on a branch yet to be born
to:
On branch master
because your current branch master
, which did not exist before, does exist now.
Using the plumbing commands
The git update-ref
and git symbolic-ref
plumbing commands are meant to be used in scripts. They assume you know exactly what you are doing. (If you use them without knowing what you are doing, you can make a mess: they have no built in safety checks.) The second of these, in particular, is how Git internally sets HEAD
to select which branch you are "on".
If you run:
git symbolic-ref HEAD refs/heads/branch
this writes ref: refs/heads/branch
into HEAD
, and you are now On branch branch
. It does not update the index and it does not update the work-tree—but in a bare repository, there is no work-tree, and receiving a push does not update the index, so this is pretty similar to what happens when you receive a push.
Thus, this is a reasonably safe thing to do. It lets you change which branch you are on, without having to use git checkout
. This is the normal and correct, albeit fiddly—make sure you spell the branch name correctly, and include the refs/heads/
prefix—way to set HEAD
in a bare repository.