Git tracking branches
Asked Answered
H

2

5

I have created a repository in local and pushed all the changes to the github. Later i have created a new branch("git branch v2") called "v2" and did some modification and pushed that branch to github as well. Later when i was executing the command "git remote show origin" i am getting the following output.

  * remote origin
  Fetch URL: https://github.com/mayuran19/se24_P03.git
  Push  URL: https://github.com/mayuran19/se24_P03.git
  HEAD branch: master
  Remote branches:
    master tracked
    v2     tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local refs configured for 'git push':
    master pushes to master (local out of date)
    v2     pushes to v2     (local out of date)

But when i was executing the command "git branch -vv" it is showing the the branch "v2" is not a tracking branch.

  master bad4ed9 [origin/master] Correct name
  * v2     6ec46b0 Data files

My question is, why the branch v2 is not showing as a tracked branch even though the remote branch is available in github and i am able to do the pull and push of this branch?

The output of the command "git branch -a" shows the following output

  master
* v2
  remotes/origin/master
  remotes/origin/v2

But not showing the mapping between the local and remote branches.

Hautemarne answered 10/4, 2016 at 8:27 Comment(0)
F
10

First we need a few definitions.

A local branch (also just called "a branch", with no modifier) is one whose full name starts with refs/heads/. When using git branch, you will see your local branches by default. The git branch command strips off the refs/heads/ part, leaving you with names like master and v2.

A remote-tracking branch is one whose full name starts with refs/remotes/ (and then has the name of a remote after that). When using git branch -r, the command will show you your remote-tracking branches. The git branch -r command strips off the refs/remotes/ part, leaving you with names like origin/master and origin/v2.

The prefix-stripping works both ways: git branch takes it off, and you can leave it off too. This is meant for convenience, and works well as long as you do not accidentally give your (regular, local) branches names starting with origin/. (If you do accidentally name a local branch origin/abc, for instance, you may confuse yourself and git's helpful stripping of prefixes becomes harmful.)

(Note that all these entities are local to your own repository, despite the name "remote-tracking". Additional references may also exist and you can see all of them with git for-each-ref, which will show you every reference using its full name. Most of the time you don't need this, and git branch suffices.)

A (regular, local) branch can be set to track another branch. Making one branch track another does a few things for you, such as make git status tell you when you are ahead and/or behind, and including the other branch in git branch -vv output. (Setting tracking is not the same as a remote-tracking branch. Again, a local branch is one whose name starts with refs/heads/, and its name does not change whether or not it is set to track another branch. However, the terminology is certainly confusing.)

To make one branch track another, first check out the first branch (the one you want to do the tracking). Then, run git branch --set-upstream-to otherbranch. For instance, to make v2 track origin/v2:

git checkout v2
git branch --set-upstream-to origin/v2

To make a local branch track another local branch, simply use a local branch name rather than a remote-tracking branch name. To make a local branch stop tracking anything, use git branch --unset-upstream.

There's one more trick to all of this,1 which is that when you ask git checkout to check out (but not create) a local branch that does not exist, git checkout will search to see if there is a remote-tracking branch with a similar name. If so, it will create the local branch and set it up to track the remote-tracking branch. That is, if branch v2 does not exist—for instance, if you rename or delete the existing local v2—and origin/v2 still does exist, then:

git checkout v2

creates local branch v2 and sets it to track origin/v2, all at once.

A branch need not track another branch to push and fetch/merge/rebase/pull, but setting it up as tracking can make all of those operations more convenient.


1As usual with git, there are actually more methods to make local branches track something else. You can set up a local branch to track a remote-tracking branch on a successful git push by adding -u to the push. You can use the (deprecated) git branch --set-upstream command. You can use flags to git checkout or git branch to create or re-create a branch with tracking set. And, you can use git config (with two separate git config commands) to make a local branch track some other branch.

Fishplate answered 10/4, 2016 at 12:50 Comment(2)
Good answer. I wonder why git does not set the tracking for a new local branch when git push from that branch?Midland
@Artyom: git push will set the upstream if you add the -u flag, as I noted in the footnote. This feature was new in git 1.7.0.Fishplate
L
4

TL;DR v2 is not a tracked branch - no upstream is set. pull won't work (the way you think). push works due to default push rules.

My question is, why the branch v2 is not showing as a tracked branch

If you look at your .git/config, you'll see a branch "master" stanza with tracking info, but you won't see a branch "v2" stanza, i.e. v2 isn't a tracking branch.

even though the remote branch is available in github

Pushing a non-tracking branch doesn't make it a tracking branch automatically. You need to add -u to your push to do that. You probably meant to do this the first time you pushed a non-tracking branch:

$ git push -u origin v2

i am able to do the pull and push of this branch

pull won't do what you expect since v2 doesn't track an upstream. It will update the remote tracking branch origin/v2 in your local repo, but it won't reconcile (merge or rebase) the local commits in the local v2 branch with any new commits made on the remote. However, if no one else is making updates to the v2 branch on the remote, then you probably won't notice an issue.

push works because of the default push rules, which matches up based on branch names.

Remote branches:
   master tracked
   v2     tracked
 Local branch configured for 'git pull':
   master merges with remote master
 Local refs configured for 'git push':
   master pushes to master (local out of date)
   v2     pushes to v2     (local out of date)
  • Remote branches: section shows the remote tracking branch origin/v2in your local repo tracks the remote's branch v2. (The remote tracking branch origin/v2 is different from your local v2 branch.)
  • Local branch configured ... section shows only local branch master is affected by pull, i.e. master tracks remote master. v2 is not listed - pull won't affect it because it has no upstream set.
  • Local refs configured ... section shows your v2 branch will push/update to the remote's v2 (and update origin/v2) - this is based on the push command's default matching rules (also depending on how your push.default config is set and what version of git you are using).

Note there's a little inconsistency or counterintuitive behavior between push and pull. Traditionally, push without a fully specified refspec arg, by default, doesn't care about the upstream - it simply pushes the same-named branch on the remote. Since the tracked remote branch is often named the same as the local branch, things work and the push and pull commands appear to both use the configured tracking branch. However, push may not work as expected if the local branch and remote branch are named differently. Certain changes to various versions of git with respect to push and push.default, i.e. tracking, current, and simple, try to reconcile those differences.

Additional reading:

Lemcke answered 10/4, 2016 at 13:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.