After checking out the branch of a colleague, at some point
git push origin branch_name
everything up to date
git push -f origin HEAD:origin/branch_name
fatal: You are not currently on a branch.To push history leading to current (detached HEAD) state now, use: git push origin HEAD:<name-of-remote-branch>
You should probably edit (parts of) your last two ... er, now, three—comments into your question, but for now, I'll just quote them here:
I found where I might have off road. When I checked-out the branch I was going to work on, I got this message (let's called the branch
Branch b1 set up to track remote branch b1 from origin. Switched to a new branch 'b1'.
I checked-out the branch this way:
git checkout b1.
Then when I tried to push I did:
git push --set-upstream origin b1. Branch b1 set up to track remote branch b1 from origin. Everything up to date
OK, in that case you are probably fine.
The problem you are running into here (well, in my opinion it's a problem) is that
git checkout crams three or four (or more, depending on how you count) different things into one command.
Normally you would use:
git checkout somebranch
to check out (switch to) your local branch
somebranch. Of course, that's great for branches you already have, but no good for branches you don't have locally yet. So Git crams another, different, command into
git checkout: the "create new branch, then switch to it" command.
Normally this command is spelled
git checkout -b newbranch. The
-b flag means "create new". It's pretty reasonable to have this command spelled the same as
git checkout, with just a flag, since we're switching to this newly created branch, but it probably would be clearer if it were a separate command, such as
Now, pretty often, when you are creating a new local branch, you are doing so with the intent of having it "track" (as its "upstream") some existing remote-tracking branch,
origin/b1 or whatever. In this case, you originally had to type in:
git checkout -b b1 --track origin/b1
which is still really obvious: create new branch
b1, base it off remote-tracking branch
origin/b1, and make it track (have as its upstream)
origin/b1. Again, this might be clearer as
git create-and-then-switch-to, but it's not so bad to have it shoved into
git checkout, plus
checkout is a lot shorter to type!
Now, many years ago (back in 2013 or so), the Git folks saw that this action was pretty common, and decided to make Git do it "magically" for you under certain conditions. If you write:
git checkout b1
and you don't currently have a branch
b1 and you do currently have an
origin/b1 and you don't have any other remote-tracking branch whose name ends in
b1, then (and only then!),
git checkout uses the create-and-then-switch-to-new-branch command, with the
--track flag. So:
git checkout b1
git checkout -b b1 --track origin/b1
in this one special (but common) case.
--trackmeans "set upstream"
Each branch (well, each named, local, branch) can have one (1) "upstream" set. The upstream of a branch has a bunch of uses:
git rebase, and
git push all look at the upstream. Having an upstream set makes
git status show how many commits you are ahead and/or behind of the current branch's upstream. And, it lets you run all the other commands with no additional arguments: they can figure out where to fetch from, or what to merge or rebase, or what to push, using the current branch's name and its upstream setting.
Branches do not have to have an upstream, and a new branch you create doesn't, by default. Moreover, if it's a "very new" branch—one that does not exist on
origin, for instance—there's no
origin/name yet to have as an upstream in the first place. But when you create a new branch from a remote-tracking branch, setting the remote-tracking branch as the upstream of the new branch is almost always the right thing.
(Note: having an upstream also affects
git pull because
git pull is just
git fetch followed by either
git merge or
git rebase. Until they are very familiar with Git, I think most people are noticeably better off running
git fetch first, then
git rebase or
git merge second, depending on which one they want—and more often, that's actually
git rebase, which is not the default for
git pull defaults to using
git merge second. Once they are familiar with the fetch-and-whatever sequence, then people can configure
git pull to do the one they intend, and use
git pull as a shortcut to run both commands. However, there are times to keep them separate anyway.)
The other things that
git checkout can do, that don't change the current branch, are:
git checkout -- <paths>, including the special
git checkout --oursand
git checkout --theirsvariations
git checkout <tree-ish> -- <paths>
git checkout -m -- <paths>(as with
--theirs, this only works during a conflicted merge)
git checkout -p(this variant gets especially complicated and I'm not going to address it further)
checkout command can also "detach HEAD" (see previous answer below) and create "orphan" branches, but both of these effectively change your current branch, so they don't fall into this special "non-branch-changing" class of
When you ran:
git push --set-upstream origin b1
you told your Git to contact the other Git on
origin, give it the commit ID to which your branch
b1 pointed, see if it needed any of those commits and files (it didn't), and then ask it to set its branch name
b1 to point to the same commit.
Now, you'd just created your own local
b1 from your
origin/b1, which you recently
git fetch-ed from
origin, so your
b1 already pointed to the same commit (you did not make any new commits) and hence your
git push gave them their own commit hash back and they said "Well, gosh, that's what I already have! We're all up-to-date!" And then their Git and your Git said goodbye to each other, and your Git carried out your last instruction:
This changed the upstream of your local branch
origin/b1. Of course, this was already the upstream for your local branch
b1, so that was not a big change. :-) But your Git did it anyway, and then reported that everything was still up to date.
... I had one file committed with changes.
git statusdidn't return nothing after I committed.
git status should always print something, such as (two actual examples):
On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean
HEAD detached at 08bb350 nothing to commit, working directory clean
In this second case, you are in "detached HEAD" mode. This special mode means you are not on a branch—or it may be more accurate to say that you are on the (single, special-case) anonymous branch that goes away as soon as you get on any other branch.
Any commits you make while in detached HEAD mode are perfectly fine, normal commits—except that there is no branch name that will make them permanent. This means these commits can go away once you switch to some other branch.
All my attempts to
git push output might help here, so one could tell why the push failed or did nothing. If it complained about being in "detached HEAD" mode, that would be significant: we would know that you were in the detached HEAD mode.
git fetch -adidn't return nothing as well.
(Just an aside: It's a bit odd to use
-a here: that flag is almost never useful to humans and is intended more for scripting purposes. It just makes your
fetch append to
FETCH_HEAD rather than overwriting it. The special
FETCH_HEAD name is meant for scripts to use.)
the last step I had were to
git checkout origin/branch_name.
This will take you off whatever branch you were on before, and put you in "detached HEAD" mode. If you used to be in "detached HEAD" mode, it will abandon your previous anonymous branch and put you on a new, different anonymous branch.
Any commits you made while on the previous anonymous branch are ... well, not lost, precisely, but are now difficult to find (and set to expire after 30 days).
When I tried to push from there I got the following message:
fatal: You are not currently on a branch. To push history leading to current (detached HEAD) state now, use: git push origin HEAD:<name-of-remote-branch>.
Which I did [
... HEAD:origin/branch_name] and it worked
Yes, but alas, this did nothing useful, because you are now on an anonymous branch that is exactly the same as
origin/branch_name. This ends up asking the remote to create—on the remote, as a local branch there—the name
origin/branch_name. That's probably not a good idea, since having a local branch named
origin/branch_name is like having a bicycle named "motorcycle". If you also have a motorcycle and ask your friend to bring you "motorcycle", which will he bring you, the bicycle named "motorcycle", or the motorcycle?