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:
- 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:
- it directly points to a local head, (i.e. to a specific commit; the growing tip), and
- 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 its 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:

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:

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.
RELATED FILES
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.