A tracking branch (also called an "upstream branch") is a pointer
inside a local branch to "its" remote. Stored in .git/config:
[branch "main"]
remote = origin
merge = refs/heads/main
This means: "local main is tied to origin/main." What that gives you:
git pullwith no arguments knows where to pull from.git pushwith no arguments knows where to push to.git statuscompares against that remote: "Your branch is ahead by 3 commits."git branch -vvshows each branch's upstream next to it.
How tracking is set
Three ways:
# 1. On first push
git push -u origin feature
# equivalent: git push --set-upstream origin feature
# 2. After the fact for an existing branch
git branch --set-upstream-to=origin/feature feature
# 3. When creating a branch from a remote
git switch -c feature origin/feature
After any of these, the branch is "linked," and subsequent
git pull / git push work without arguments.
Remote-tracking branch: a different thing
Do not confuse the two:
- Tracking branch is a local branch that remembers its remote (described above).
- Remote-tracking branch is
origin/main,origin/feature/x. These are local refs that mirror the state of the remote (see fetch).
Their relationship:
local main ─ tracks ─→ origin/main (remote-tracking branch)
↑
fetch updates this
What git status shows
On branch feature
Your branch is ahead of 'origin/feature' by 2 commits.
Meaning:
- You have 2 commits that are not in
origin/feature. - You need to push.
Your branch is behind 'origin/feature' by 3 commits.
- The remote has 3 commits you do not have.
- You need to pull or fetch.
Your branch and 'origin/feature' have diverged,
and have 2 and 3 different commits each, respectively.
- Both you and the remote have commits since the common ancestor.
- Resolve with merge, rebase, or fetch and rewrite your commits.
Without tracking
If a local branch has no upstream:
git push
# fatal: The current branch feature has no upstream branch.
# To push the current branch and set the remote as upstream, use
# git push --set-upstream origin feature
This is intentional: Git does not guess where to push a new branch.
You need to say -u origin feature explicitly.
Pitfalls
- Tracking breaks on remote rename. If you run
git remote rename origin foo, local branches withbranch.X.remote = originwill have broken pull/push.git remote renameusually fixes this, but verify afterward. - Ghost tracking after a remote branch is deleted. If the remote
branch was deleted, the local tracking still points to something that
no longer exists.
git fetch --pruneremoves dead refs. - Config and state are separate.
.git/configstores who to push to. The actual SHA lives inrefs/remotes/origin/<branch>. If refs are stale, rungit fetch.