Im trying to setup a hook to push from my desktop to my server. This has worked countless times in the past but now I'm getting an error upon setting up a new site:
remote: fatal: You are on a branch yet to be born
I've done the same series as commands as always, as per this guide.
So on my server I make a git dir. For instance example.git
I then run git init --bare
. After which I go to my hooks:
cd hooks/
cat > post-receive
Inside my post-receive I place:
#!/bin/sh
git --work-tree=/home/username/public_html/example.com --git-dir=/home/username/example.git checkout -f
I Ctrl + D out to save. Then run chmod +x post-receive
Then locally I run: git remote add live ssh://username@domain.com:x/home/username/example.git
Then I can run: git push -u live master_prefix
The only thing I'm doing different is I'm within a branch called master_something, rather than master. Would this be causing the issue and if so, what do I need to do?
It is, as you suspected, because you're pushing a branch named
master_prefix
rather than master. As for what to do, well, that depends on what you want to happen. Skip to the end if you want to see several options.First, though, let's break this down a bit.
Any message that begins with:
is actually coming from the "other guy". When you do a push (or fetch, for that matter), your git calls up another git over the Internet-phone or equivalent. They exchange information using a protocol that helps them identify when they're talking to each other directly, and when your git is getting stuff from their end that's not from their git, but rather from something their git is using.
In this case, their git (on the server) is running their git's hooks. There's just the one hook—you created it, so we could call it "your" hook, but your computer running your git has no idea that the stuff on the server is authored by you: it doesn't know, doesn't need to know, and doesn't care; it just delivers messages. So we'll call it "their" hook.
Their hook says:
and you see it on your end prefixed with
remote:
to let you know it's not your git that's saying things, it's something on their end.At this point, the best thing to do is to change perspectives, by pretending "you" are now the server. On "your" end, your git fires up and receives stuff (successfully, and puts in the requested branch,
master_prefix
), then runs the one hook. That hook fires up another, separate, git command:This is pretty long so let's shorten it by ignoring the options for a moment. Aside from setting the work and git directories, it's just
git checkout -f
.If you ran this command by itself somewhere else, what branch will it check out? This isn't a rhetorical question, and the answer is in the documentation, although it may be unclear and even misleading:
Because of the
--work-dir
and--git-dir
options and the fact that the (bare) repository might be changed, it's not "a glorified no-op" after all, but it does use:That's the key, right there: the current branch. What is the "current branch" of this bare repository?
The answer is the same as for any repo (bare or not): the current branch is the one named in the
HEAD
file. If you poke around in this bare repository, you'll find that file; examine it and it will say:In other words,
HEAD
names the current branch, which—since thegit init
set it that way and nothing since then has changed it—ismaster
.So your
git checkout -f
command is attempting to check out branchmaster
.What branches actually exist? You can find out, by going into the bare repository and running
git branch
:I got this with
git version 2.3.0
: note that there's no* master
output. Other (future, really) versions of git might show you* master
since that is the branch you're on—even though it does not exist yet!What's going on? The answer is that any time you create a new branch that's not connected to any existing revision—which is always true for the
master
branch in a newly created repository—git handles this by writing the branch name intoHEAD
, but not writing any revision ID into the appropriate file(s) for that branch. This is how git records the idea that the named branch has not yet been created, but will be once you provide the first commit(s) for that branch.(If you use
git checkout -b newbranch --orphan
you get in this same "yet to be born" state for the new branch. It's most common formaster
of course, since that's how any brand-new, empty repository starts out.)So what to do?
As I noted before, this really depends on what you want to have happen.
You have a new (initially empty) bare repository with no
master
branch (but a post-receive hook that tries to export the current branch, which is stillmaster
). Then you supply, from another system, a new branch, but it's notmaster
. I see two obvious possible "want"s although perhaps you want something fancier than either of these:You want to export nothing since there's no
master
to export: modify your hook to check whether the current branch exists:You want to export something other than the current (
master
) branch. Decide whether that means "forever" or "untilmaster
appears" or whatever; modify your deployment script if needed or desired, or just change git's idea of the current-branch.Let's say you want
master_prefix
deployed now and forever. Normally, you'd switch the bare repo tomaster_prefix
with a simplegit checkout
, but you can't because (1) it's a--bare
repo and (2) there is nomaster_prefix
yet (unless you're doing this post-push as a fixup step).There are two easy ways, on the server, to update its own idea of the current branch, even if the new one does not yet exist:
does the trick by (c)rudely bypassing git entirely, or:
does the same thing using git.
Alternatively, you can specify the precise branch that the post-receive script should check out:
Note that this will cause git to change the current branch (in the bare repository) to
master_prefix
on each push.Since your hook does not look at which branch(es) have been updated if any, there's no way to tell which branch(es) to deploy, other than to use whatever is the default (in
HEAD
) or explicitly deploy a particular branch (add an argument).It's also worth noting a subtle tricky bit: the
index
file in the bare repository will record what's been checked-out to the specified work-tree. As long as you have a single deployment location and/or a single branch deployed, this will be fine. If you start getting fancy (e.g., deployingmaster
to the regular server, buttest
to a test service on the same server), you may want to modify the deployment script, either to clean out and rebuild the target or to use multiple index files.Most of the above doesn't matter until you start getting fancy. The main thing is that you must decide what you want deployed, and maybe create a
master
branch.