Tracking Branches
A tracking branch is a local branch that has a known relationship to a branch on a remote. Tracking lets Git figure out automatically which remote branch to fetch from, push to, and compare with — so git pull and git push can be typed with no arguments. It is one of those “invisible until it breaks” pieces of Git that makes everyday work smooth.
Tracking vs remote-tracking branches
Remote-tracking branch (e.g.,
origin/main) — a local pointer that records where the remote branch was at the last fetch. Read-only — you never commit to it.Tracking branch (e.g., your local
maintrackingorigin/main) — a local branch with an upstream relationship to a remote branch. Editable as normal; Git knows where to push and pull.
How tracking gets set up automatically
git clone <url>— every local branch automatically tracks the corresponding remote branch.git switch feature-xwhenorigin/feature-xexists — creates a localfeature-xtracking the remote.git push -u origin feature-x— setsfeature-xto trackorigin/feature-xgoing forward.
Setting tracking explicitly
# When creating a branch git switch -c feature-x --track origin/feature-x # Set tracking on an existing local branch git branch --set-upstream-to=origin/main main # Short flag git branch -u origin/main
Inspecting tracking info
# Each branch with its upstream and ahead/behind state git branch -vv # * main 1f9ab2c [origin/main] Add login form # feature-x d4b1e0c [origin/feature-x: ahead 1, behind 2] WIP # Or just the current branch git status # On branch main # Your branch is up to date with 'origin/main'.
Reading the brackets
[origin/main]— tracks origin/main, in sync.[origin/main: ahead 2]— local has 2 commits the remote does not.[origin/main: behind 3]— remote has 3 commits the local does not.[origin/main: ahead 2, behind 3]— diverged.[gone]— the tracked remote branch was deleted; safe to clean up locally.
Disconnecting a tracking branch
git branch --unset-upstream # Or by branch name git branch --unset-upstream feature-x
The push.default setting
Tracking interacts with push.default, which decides what git push (no arguments) actually pushes:
simple(default since Git 2.0) — pushes only the current branch to its upstream, AND only if the names match. Safest.current— pushes the current branch to a branch of the same name on the remote, regardless of upstream.upstream(formerlytracking) — pushes to the upstream.matching— pushes EVERY local branch that has a matching remote branch. Dangerous; rarely used.nothing— refuses to push without explicit args.
git config --global push.default current
Why tracking matters
Without tracking,
git pullandgit pushneed explicit remote and branch arguments.git statuscannot tell you “ahead 2, behind 3” without an upstream.git fetchupdates remote-tracking refs butgit pullneeds the upstream to know what to merge.
Common errors
The classic
git push # fatal: The current branch feature-x has no upstream branch. # To push the current branch and set the remote as upstream, use: # git push --set-upstream origin feature-x # Fix it with: git push -u origin feature-x
Reset tracking after a rename
If the remote branch was renamed
git fetch git branch --unset-upstream git branch -u origin/new-name
git config --global push.autoSetupRemote true once. Now git push on a new branch automatically sets tracking — you stop seeing the “no upstream” error forever.