I'm currently learning git by following the book "progit 2nd edi".
In the section "inspecting a remote", the author had the following example.
I have noticed that the "markdown-strip" branch is absent in the section "local branch configured for git pull" but present in section "local ref configured for git push". I was wondering why this is the case.
PS: I understand how "git pull" and "git push" works. It is the absence of "markdown-strip" branch in "local branch configured for git pull" that's puzzling me.
This seems to be a synthetic example, so it could just be a mistake. However, it could also be a side effect of a particular configuration, where local branch markdown-strip
has no upstream set.
Remember, the upstream of any branch is a two-part setting that you can set with one command:
git branch --set-upstream-to=<upstream> <branch>
such as:
git branch --set-upstream-to=origin/master master
or configure rather clumsily with a two separate git config
commands:
git config branch.master.remote origin
git config branch.master.merge refs/heads/master
Every branch name, such as master
, can have one upstream set, or it can have no upstream set. (That is, you cannot set two or more upstreams. You can set one remote
and two or more merge
s, and git show
does something special with them; but this is not a normal configuration, and git branch --set-upstream-to
cannot and will not do this.)
To remove the upstream the normal way, use git branch --unset-upstream
. Below, I do it an abnormal way, although the effect on git remote show origin
is the same either way. (I deleted one of the two settings in my editor, because that lets me undo the delete in the editor, which is easier than typing in a git branch
command. Of course I have now taken much more time explaining this than just doing it the normal way. :-) )
The upstream for any local branch can be another local branch, but more typically it's what Git calls a remote-tracking branch.1 You don't normally want or need to un-set an upstream. You do sometimes want to set an upstream, but if you use the normal method, you cannot set the upstream for a new branch until you have first pushed that new branch:
$ git checkout -b newbr
... the usual stuff here ...
$ git commit
$ git branch --set-upstream-to=origin/newbr
This complains and fails, because origin/newbr
does not exist yet, because we created newbr
locally but have not yet pushed it to origin
, so there is no origin/newbr
in our repository. Once we do run git push origin newbr
, that creates newbr
on origin. That in turns creates our own origin/newbr
to remember the newbr
we just created on origin, and—whew!—now we can finally set origin/newbr
as the upstream for newbr
.
I think in this case the Pro Git authors had a repository where they created a branch locally, then pushed it to remote named origin
, but never got around to running git branch --set-upstream-to
on the branch.
For instance, my copy of the Git repo for Git has local branch master
configured with its upstream set to origin/master
. If I run git remote show origin
I get (after the usual earlier output):
Remote branches:
maint tracked
master tracked
next tracked
pu tracked
todo tracked
Local branches configured for 'git pull':
master merges with remote master
stash-exp merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
(stash-exp
is where I put a bug fix for git stash
ages ago). If I delete the line merge = refs/heads/master
from .git/config
and run git remote show origin
again, I get this:
Remote branches:
maint tracked
master tracked
next tracked
pu tracked
todo tracked
Local branch configured for 'git pull':
stash-exp merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
Note that this still claims master pushes to master
. In fact, nothing pushes to anything as the origin
repository is read-only.
This claim is just about what Git would attempt, were I to run git push origin master
. In this case my Git would call up their Git and discover that we both have a branch named master
. My Git would then suggest to their Git that they should set their refs/heads/master
to point to the same commit as my refs/heads/master
. They would refuse—their repository is set to reject such an attempt—but my Git doesn't know that.
When I removed the branch.master.merge = refs/heads/master
setting, my Git stopped saying master merges with remote master
. As soon as I put that setting back, my Git starts saying it again. This does not mean that my master
always merges with their master
: it just means that if I were to run git pull
, and their master
had new commits, my Git would, as its second step for git pull
, run git merge origin/master
(more or less). The git pull
command uses the upstream setting to determine what to do. But I never2 run git pull
, because git pull
is a terrible tool.
(I always git fetch
first, then generally inspect things, then run git rebase
if appropriate, or use my git mff
alias, which is short for git merge --fast-forward
. Note that git rebase
and git merge
also use the upstream setting. So does git status
, for that matter—so it's quite useful to set the upstream, even if you avoid git pull
.)
1Remember, a so-called remote-tracking branch like origin/master
is (a) in your repository (it's not remote at all, it's local); and (b) is just your Git's way of remembering what your Git saw on origin
for origin
's master
the last time your Git called up origin
's Git. You cannot get "on" origin/master
the way git checkout master
gets you on your own origin
branch, which means that (c) a remote-tracking branch is not even a branch! So a remote-tracking branch (1) isn't remote, (2) does remember what your Git saw on another Git, and (3) isn't a branch. Only one of the three words, tracking, in its name is halfway correct! :-)
The hyphenated form, remote-tracking, makes this better, because it's a thing that "tracks a branch as seen on a remote". The whole thing then makes a sort of sense, but the name starts out very misleading. People think that a remote-tracking branch is like a local branch, and it isn't. But that's not the worst problem: they used to be called remote branches, and some people still use that phrase. In any case, both these local names and these remote-tracking names are just names; the branch itself is yet another entity. See What exactly do we mean by "branch"?
2What, never? Well, hardly ever!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With