What are the differences between local branch, local tracking branch, remote branch and remote tracking branch?

GitVersion ControlGit BranchGit Remote

Git Problem Overview


I just started using Git and I got really confused between different branches. Can anyone help me to figure out what the following branch types are?

  • local branches
  • local tracking branches
  • remote branches
  • remote tracking branches

What is the difference between them? And how do they work with each other?

A quick demo code will be really helpful I guess.

Git Solutions


Solution 1 - Git

Here's the long answer.

Remotes:

If you're using Git collaboratively, you'll probably need to sync your commits with other machines or locations. Each machine or location is called a remote, in Git's terminology, and each one may have one or more branches. Most often, you'll just have one, named origin. To list all the remotes, run git remote:

$ git remote
bitbucket
origin

You can see which locations these remote names are shortcuts for, by running git remote -v:

$ git remote -v
bitbucket git@bitbucket.org:flimm/example.git (fetch)
bitbucket git@bitbucket.org:flimm/example.git (push)
origin git@github.com:Flimm/example.git (fetch)
origin git@github.com:Flimm/example.git (push)

Each remote has a directory under .git/refs/remotes/:

$ ls -F .git/refs/remotes/
bitbucket/ origin/

Branches on your machine:

TLDR: on your local machine, you've got three types of branches: local non-tracking branches, local tracking branches, and remote-tracking branches. On a remote machine, you've just got one type of branch.

1. Local branches

You can view a list of all the local branches on your machine by running git branch:

$ git branch
master
new-feature

Each local branch has a file under .git/refs/heads/:

$ ls -F .git/refs/heads/
master new-feature

There are two types of local branches on your machine: non-tracking local branches, and tracking local branches.

1.1 Non-tracking local branches

Non-tracking local branches are not associated with any other branch. You create one by running git branch <branchname>.

1.2. Tracking local branches

Tracking local branches are associated with another branch, usually a remote-tracking branch. You create one by running git branch --track <branchname> [<start-point>].

You can view which one of your local branches are tracking branches using git branch -vv:

$ git branch -vv
master      b31f87c85 [origin/master] Example commit message
new-feature b760e04ed Another example commit message

From this command's output, you can see that the local branch master is tracking the remote-tracking branch origin/master, and the local branch new-feature is not tracking anything.

Another way to see which branches are tracking branches is by having a look at .git/config.

Tracking local branches are useful. They allow you to run git pull and git push, without specifying which upstream branch to use. If the branch is not set up to track another branch, you'll get an error like this one:

$ git checkout new-feature
$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream new-feature <remote>/<branch>

2. Remote-tracking branches (still on your machine)

You can view a list of all the remote-tracking branches on your machine by running git branch -r:

$ git branch -r
bitbucket/master
origin/master
origin/new-branch

Each remote-tracking branch has a file under .git/refs/remotes/<remote>/:

$ tree -F .git/refs/remotes/
.git/refs/remotes/
├── bitbucket/
│   └── master
└── origin/
    ├── master
    └── new-branch

Think of your remote-tracking branches as your local cache for what the remote machines contain. You can update your remote-tracking branches using git fetch, which git pull uses behind the scenes.

Even though all the data for a remote-tracking branch is stored locally on your machine (like a cache), it's still never called a local branch. (At least, I wouldn't call it that!) It's just called a remote-tracking branch.

Branches on a remote machine:

You can view all the remote branches (that is, the branches on the remote machine), by running git remote show <remote>:

$ git remote show origin
* remote origin
  Fetch URL: git@github.com:Flimm/example.git
  Push  URL: git@github.com:Flimm/example.git
  HEAD branch: master
  Remote branches:
    io-socket-ip            new (next fetch will store in remotes/origin)
    master                  tracked
    new-branch              tracked
  Local ref configured for 'git pull':
    master     merges with remote master
    new-branch merges with remote new-branch
  Local ref configured for 'git push':
    master     pushes to master     (up to date)
    new-branch pushes to new-branch (fast-forwardable)

This git remote command queries the remote machine over the network about its branches. It does not update the remote-tracking branches on your local machine, use git fetch or git pull for that.

From the output, you can see all the branches that exist on the remote machine by looking under the heading "Remote branches" (ignore lines marked as "stale").

If you could log in to the remote machine and find the repository in the filesystem, you could have a look at all its branches under refs/heads/.

Cheat sheet:

  • To delete a local branch, whether tracking or non-tracking, safely:

      git branch -d <branchname>
    
  • To delete a local branch, whether tracking or non-tracking, forcefully:

      git branch -D <branchname>
    
  • To delete a remote-tracking branch:

      git branch -rd <remote>/<branchname>
    
  • To create a new local non-tracking branch:

      git branch <branchname> [<start-point>]
    
  • To create a new local tracking branch: (Note that if <start-point> is specified and is a remote-tracking branch like origin/foobar, then the --track flag is automatically included)

      git branch --track <branchname> [<start-point]
    

    Example:

      git branch --track hello-kitty origin/hello-kitty
    
  • To delete a branch on a remote machine:

      git push --delete <remote> <branchname>
    
  • To delete all remote-tracking branches that are stale, that is, where the corresponding branches on the remote machine no longer exist:

      git remote prune <remote>
    

You may have noticed that in some commands, you use <remote>/<branch>, and other commands, <remote> <branch>. Examples: git branch origin/hello-kitty and git push --delete origin hello-kitty.

It may seem arbitrary, but there is a simple way to remember when to use a slash and when to use a space. When you're using a slash, you're referring to a remote-tracking branch on your own machine, whereas when you're using a space, you're actually dealing with a branch on a remote machine over the network.

Solution 2 - Git

A local branch is a branch that only you (the local user) can see. It exists only on your local machine.

git branch myNewBranch        # Create local branch named "myNewBranch"

A remote branch is a branch on a remote location (in most cases origin). You can push the newly created local branch myNewBranch to origin. Now other users can track it.

git push -u origin myNewBranch   # Pushes your newly created local branch "myNewBranch"
                                 # to the remote "origin".
                                 # So now a new branch named "myNewBranch" is
                                 # created on the remote machine named "origin"

A remote tracking branch is a local copy of a remote branch. When myNewBranch is pushed to origin using the command above, a remote tracking branch named origin/myNewBranch is created on your machine. This remote tracking branch tracks the remote branch myNewBranch on origin. You can update your remote tracking branch to be in sync with the remote branch using git fetch or git pull.

git pull origin myNewBranch      # Pulls new commits from branch "myNewBranch" 
                                 # on remote "origin" into remote tracking
                                 # branch on your machine "origin/myNewBranch".
                                 # Here "origin/myNewBranch" is your copy of
                                 # "myNewBranch" on "origin"

A local tracking branch is a local branch that is tracking another branch. This is so that you can push/pull commits to/from the other branch. Local tracking branches in most cases track a remote tracking branch. When you push a local branch to origin using the git push command with a -u option (as shown above), you set up the local branch myNewBranch to track the remote tracking branch origin/myNewBranch. This is needed to use git push and git pull without specifying an upstream to push to or pull from.

git checkout myNewBranch      # Switch to myNewBranch
git pull                      # Updates remote tracking branch "origin/myNewBranch"
                              # to be in sync with the remote branch "myNewBranch"
                              # on "origin".
                              # Pulls these new commits from "origin/myNewBranch"
                              # to local branch "myNewBranch which you just switched to.

Solution 3 - Git

Local Branch:

A branch on your machine that you can work in and add commits to. You can list these branches with git branch.

Local Branch (With Tracking):

An ordinary local branch configured to correspond to a remote branch. This has benfits like the ability to git pull and git push without having to specify the repository and branch name. Tracking also causes git status to inform you when your branch is ahead or behind the remote.

Remote Branch:

Simply a branch on a remote repository—typically on a server such as GitHub etc.

Remote Tracking Branch:

A local copy of a remote branch. This branch should never be edited. Its purpose is to keep track of the current state of a remote branch. Remote tracking branches can be viewed with git branch -r and typically look something like origin/master (repo name followed by a slash followed by the branch name). Running git fetch will update the remote tracking branches to reflect the state of the corresponding remote branches.

git branch -avv is my personal favorite for displaying a quick overview of which branches are on my machine, which branches are on the remote, and the latest commit in each. The -a part specifies that all branches should be shown (remote and local). The v's on the end stand for verbose (it shows the last commit hash and message). Thanks to @Flimm for pointing out that the second v adds info about which local branch is tracking which remote.

Solution 4 - Git

Overview

TL;DR - This is organized so you can skip down to what you need to know.

Here is what I'll cover below:

  • QUICK OVERVIEW - What the 4 types of branches are and where you find them
  • SHORT GLOSSARY - Basic principles and terminology related to branches
  • INVESTIGATION - How to inspect your local and remote branches
  • RELATED FILES - Configuration files
  • CONFIGURATION - How to see and setup your branch configuration
  • COLLABORATING - How to use remote branches

QUICK OVERVIEW

A local branch is a name, on our local repository, that refers to a head here.

A remote branch is a name, on a remote repository, that refers to a head there.


A simple branch is a local name that references one thing:

  1. it directly points to a local head, (i.e. to a specific commit; the growing tip)

A tracking-branch is a local name that references two things:

  1. it directly points to a local head, (i.e. to a specific commit; the growing tip), and
  2. it symbolically points to a second branch on a remote repository.

There are two kinds of tracking-branches:

  • local - where the branch points to a local head.
    These are called local-tracking-branches. (More on these below.)

  • remote - where the branch points to a local copy of a remote head.
    These are called remote-tracking-branches. (More on these below.)


Here are the 4 types of branches, where we see them, and how they map:

WHERE    ---BRANCH TYPE--------     --REFERENCE TARGETS-------

--------------------------------------------------------------
Remote   simple branch -----------> remote head (a commit ID)

--------------------------------------------------------------
Local    simple branch -----------> local  head (a commit ID)


Local    local  tracking-branch --> local  head (a commit ID1)
                                --> Remote-name/branch-name

Local    remote tracking-branch --> local  head (a commit ID2)
                                --> Remote-name/branch-name
--------------------------------------------------------------

SHORT GLOSSARY

The terms Remote and Branch appear to be overloaded.

And the phrase tracking branch is especially confusing, because it's not really the same thing as a tracking-branch.

'a snapshot'      - A recording of the state of one or more files 
                    and their contents at a given moment in time.

'a commit'        - A container holding one snapshot, the date and
                    time it was  recorded, who recorded it, and a
                    comment to say what it's all about.

'a repository'    - A repository of commits, organized so we can 
                    look thru them, going backwards in time.

                    Much like photos added in sequence to a photo
                    album book, to record our own history, each commit
                    contains a snapshot of the exact state of our
                    project at a given moment in time.
                    
                    It is used to be able to look backwards in time to
                    how it was at any recorded previous time.

'Remote'          - (Upper case) Short for 'a named remote repository'
                                 (of commits, of snapshots)

'remote'          - (Lower case) Located on  another     git repository
'local'           -              Located on  your local  git repository  

'a head'          - A specific young commit, with no children yet of
                    it's own (i.e. no other commits yet pointing to it),
                    but which may link backwards in time to one or more
                    of it's natural parents.

                    Also called a growing tip.
                    Initially set to a <start-point>. 


'a branch'        - A symbolic name (i.e. an identifier) pointing
                    to one specific head, and possibly, depending on
                    the branch type, also pointing to a remote branch.

                    The term 'branch' can also refer to a specific
                    linked list of multiple commits (plural), starting 
                    from the growing tip (or most recent baby), and 
                    linking offspring to their parent(s) backwards in
                    time.
                   

'tracks'          - As we move forward, tracks are what we leave behind.

'tracked'         - To be followed, as in, to come afterwards, or after
                    the fact, by way of the evidence left behind, of the
                    a state of being of the thing being tracked, as it
                    moves forwards in time.

'tracking'        - The process of capturing and organizing snapshots of
                    our project so we can later look backwards in time
                    to find how it previously was.

'tracking-branch' - This term is somewhat redundant, and confusing, 
                    but does have a specific, important meaning.

                    I have deliberately added the hyphen, because this
                    term does NOT mean simply 'tracking branch'.  (Grab
                    your aspirin, and a cold pack for your head, lol.)


                    Because all branches in git are used for, and only
                    used for, tracking your project, therefore it could
                    be said that ALL branches are actually 
                    'tracking-branches', but we don't call them that.

                    Instead we call them, simply 'branches'.


                    But then what is a 'tracking-branch'?

         TL;DR      A 'tracking-branch' is a local name that points to
                    two branches at the same time.
                    
                      So when you read  'tracking-branch,  it might be 
                      helpful to instead think:  'branch-pair'.

                        (Normal branches only point to one thing, the
                        head, which is the commit at a growing tip.
                        And they do not have any symbolic pointers.)


                    1) The first branch a 'tracking-branch' points to
                    is the same as for any other branch:  a local head,
                    (i.e. a young commit in our local repository without 
                    any children.)  This is where a tracking-branch
                    keeps a full local copy of a remote branch.

                      Note that it doesn't necessiarialy hold a full
                      duplicate copy of the entire second, remote 
                      repository.  If you have cloned the remote 
                      repository then you already have most, if not all
                      of their commits in your own local repository.


                    2) The second branch a 'tracking-branch' points to
                    is a branch on a remote repository.

                      It does this with a <remote-name>/<branch-name>.
                      The 'remote-name' is used to find the URL to the 
                      remote repository.  See `git remote -v`.

                    Why point to two branches?  

                      This is to be able to operate on two heads at the
                      same time, like to copy commits from one head to
                      the other as `git fetch` and `git push` does.


                    We have two types of 'tracking-branches' (both on
                    our local repository):
                    
                      'local  tracking-branches', 
                           with a simple     branch name,  and
                           
                      'remote tracking-branches', 
                           with a path-style branch name.
                           
                      See `git branch -avv`.  For example:

enter image description here

  • The 1st two lines output here, are local tracking-branches. The asterisk (*) prefixing master tells us that master is currently the default branch (i.e. what is checked out into our working area). BTW, the name master is short for refs/heads/master.

  • The 3rd line output is a simple local branch.

  • The 4th line output is NOT a branch at all, but rather a second local HEAD (in addition to our normal local HEAD) which points to the default remote tracking-branch, or one of the following branches in this example. Use git remote set-head <remote-name> <remote tracking-branch name> to set it. (NOTE this is also not the same HEAD as returned by git remote show <remote-name> which is the downloaded value of the remote repository's HEAD.)

  • The last two lines output are remote tracking-branches.

Note that all branches reference a commit ID (hex number). remotes/origin/HEAD is not a branch so it doesn't have this.

Also note that the first two lines and the last two lines also have a symbolic reference to a branch on a remote (in this case the remote named origin).

Here 'master' is our local working branch. And remotes/origin/master is a local copy of the branch named master fetched (by git fetch, git clone or git pull) from the remote we call origin.

(BTW, origin is the default name of the Remote repository that we originally cloned, with a git clone command.)


                    So our 'remote tracking-branches' are not remote 
                    branches, on a remote repository, but rather are 
                    local branches, which have a local head of their
                    own, pointing to a local commit, and also at the 
                    same time symbolically pointing, to a remote 
                    branch.

                    With `git branch -avv`, notice how two branches can
                    point to origin/remote:
                    
                    * the first  being the  'local-tracking-branch' 
                      with the name        'master', and with the
                      '[origin/master]' extra clause,  and 
                      
                    * the second being the 'remote-tracking-branch'
                      with the name 'origin/master'.


                    NOTE: Though they point to the same remote branch, 
                    the local commit head is not always the same!
                    
                    Thus they are actually two different branches.  
                    
                    The 'local-tracking-branch' is our working branch, 
                    and the 'remote-tracking-branch' is a copy of the 
                    remote's branch that we cloned from or fetched to
                    update.

INVESTIGATION

REMOTES

git remote                      # List names of known Remotes  

git remote -v                   # List names of known Remotes and
                                #   show the 2 URL's pointing to them  
                                #
                                #  See '[remote "<names>"]' in
                                #    $ cat .git/config

REMOTE BRANCHES (located on the remote repository)

git remote show <remote-name>   # Download and view 
                                #   a specific Remote's info.

# for example, let's download the information for 
# two remotes named origin and upstream:

enter image description here

  • The leading asterix (*) is a bullet to mark the start of data from a given remote. We requested downloads from two remotes, so we have two bullets.

  • The 1st line output gives the name of the remote, prefaced with the word 'remote'.

  • The 2nd and 3rd lines report our locally configured fetch and push URLs for the remote named origin. View them also with git remote -v.

  • The 4th line reports the HEAD from the remote repository. You can't set this HEAD. Nor is it the same as the local HEAD, nor local read for remotes from git branch -avv

  • Starting on the 6th line is the list of branches that the remote repository owns.

    Remote branches: master tracked updates tracked

  • Then torek says this about the remaining lines:

>All git remote show does is call [the remote] up, using git ls-remote, over the Internet-phone, and compare their references to your references to guess what git fetch and git push would do, based on those results. (If you use git pull, that just means run git fetch, then run git merge. The git remote show command tries to guess what that will do, too.)

LOCAL BRANCHES (located on the local repository)

git branch -avv  # Show ALL  'local branches', verbosely;  (3 types):


git branch -rv   # -- type 1 -------------------------------------
                 # Show ONLY 'local branches' that point to
                 # 'remote branches' (-r = remote; -v = verbose)
                 #
                 #   This lists your 'Remote tracking branches'!
                 #     From:  $ tree .git/refs/remotes/*
                 #
                 #      They allow us to move snapshots between
                 #       repositories, and to keep a copy of
                 #       Remote's branches locally.

git branch -vv   # -- types 2 and 3 ------------------------------
                 # Show ONLY 'local branches', that point to local
                 # things, but his includes two different types of
                 #  branches mixed together, for example:

* master  de430b6 [origin/master] <comment describing this branch>
  updates 3c40299 [origin/updates] <comment describing this branch>
  foo     de430b6  <comment describing this branch>

Notice that the first two branches named master and updates (above), both have an additional field after their commit number. For example, for the branch named 'master', this field is [origin/master].

This tells us that these two branches are not ordinary local branches, but rather are Local tracking-branches. Similar to the 'remote-tracking-branches' above, they also symbolically point to a remote branch. Thus master in this case, not only points to a branch head in the local repository, but it also points to origin/master, in the remote repository.

These extra fields are setup by parameters in .git/config.

By contrast, foo here is a simple, normal branch, i.e. non-tracking.


 cat .git/config                       # '[branch "<names>"]' are local
                                       #    tracking branches

 ls -F .git/refs/heads/*               # 'Local' branch names & heads:
                                       #   both tracking and non-tracking

 ls .git/refs/remotes/<remote-name>/*  # 'Remote' tracking branch names & heads

CONFIGURATION

Create with git branch, git checkout -b, or by cloning a remote repository with git clone, or manage explicitly either by directly edting .git/config or with these:


Remotes

Create with git remote implicitly by cloning a git repository with git clone.

  • git remote add - to explicitly add a new remote name (to .git/config)
  • git remote rename
  • git remote remove - to delete a remote
  • git remote prune - to delete any local remote-tracking branches which have already been removed on the remote

Set properties with:

  • git set-url - set one url, or replace a url for the remote

  • git set-url --add - append a url, to the list of urls for the remote

  • git set-url --delete - remove all url's matching a pattern

  • git set-branches - changes the set of tracked branches

  • git set-branches --add - append, rather than fully replace the list of currently tracked branches

  • git set-head - sets the default remote branch (i.e. the remote's HEAD)

  • git set-head --auto - query remote to set the local HEAD for the remote branch

  • git set-head --delete - deletes the default remote branch (i.e. the remote's HEAD)

Branches

git branch  [--set-upstream | --track | --no-track]  [-l] [-f]               <NewBranchName> [<start-point>]   # create branch         (start point defaults to HEAD)

git branch  (--set-upstream-to=<upstream-branch> | -u <upstream-branch>)       [<BranchName>]                  #   link to upstream branch
git branch --unset-upstream                                                    [<BranchName>]                  # unlink to upstream branch


git branch --edit-description                                                  [<BranchName>]                  # edit   branch description


git branch (-m | -- move | -M)                              [<oldBranchName>] <newBranchName>                  # rename (move) branch; -M = force

git branch (-d |           -D) [-r]                                             <BranchName>...                # delete branch

COLLABORATING

With a default configuration, when you git clone this automatically sets your remotes and tracking-branches. Note however, that there are configuration settings that will disable or change how this works.


TIP Use the --dry-run option on git fetch and git push to see what's going to happen before you do it.


Use git fetch (possibly by calling git pull) to update your local copy of a remote's commits to bring you up to date.

If you don't include a then the default is used. You can see what the default is in .git/config in the fetch= property under [remote "<remote-name>"]. This might look like this:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*

Syntax is [+]?<source>:<destination>. What that means is to get the refs (normally commits and tags) from .git/refs/heads/* which are normal, simple branches in the remote repository, and put them into our local .git/refs/remotes/origin/* branches, which are our tracking-branches. Cool, eh! BTW, the '+' says to update even if this won't be a fast forward.


Use git push <remote> <branch> to send local commits to a remote repository that you have permission to write to.


I hope I've got this all correct.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionededView Question on Stackoverflow
Solution 1 - GitFlimmView Answer on Stackoverflow
Solution 2 - GitSNceView Answer on Stackoverflow
Solution 3 - GitEric MathisonView Answer on Stackoverflow
Solution 4 - GitElliptical viewView Answer on Stackoverflow