Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a branch is present in section "local ref configured for git push" but absent in section "local branch configured for git pull"

I'm currently learning git by following the book "progit 2nd edi".

In the section "inspecting a remote", the author had the following example.

enter image description here

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.

like image 797
Thor Avatar asked Aug 06 '17 09:08

Thor


1 Answers

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 merges, 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.

An example

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!

like image 98
torek Avatar answered Nov 14 '22 22:11

torek