When you work with remotes, Git maintains a parallel set of references on your local machine that mirror the state of branches on the remote. Understanding these remote-tracking branches — what they are, how they move, and how to use them — is essential for collaborating without confusion.
Remote-Tracking Branches
A remote-tracking branch is a local, read-only reference that records the state of a branch on a remote repository the last time you communicated with it.
You cannot move remote-tracking branches yourself. Git moves them automatically whenever you fetch, push, or pull — updating them to reflect the current state of the remote. Think of them as bookmarks: they tell you where a remote branch was the last time you connected to it.
Remote-tracking branch names follow the pattern <remote>/<branch>:
origin/main
origin/feature-login
upstream/develop
When you clone a repository, Git creates origin/main (or origin/master) pointing to the same commit as the remote's default branch, and creates a local main branch starting from the same point for you to work on.
After cloning:
origin/main ──→ C3 (remote-tracking — read-only)
main ──→ C3 (local — you work here)
How Remote-Tracking Branches Move
Remote-tracking branches only update when Git communicates with the remote. If your teammate pushes two new commits while you are working offline, your origin/main stays where it was — it does not know about those commits yet.
Remote server: C1 -- C2 -- C3 -- C4 -- C5 (main)
Your machine: C1 -- C2 -- C3 (origin/main — stale)
\
D -- E (your local main — ahead)
Running git fetch origin downloads the new commits and moves origin/main forward:
After fetch:
Remote server: C1 -- C2 -- C3 -- C4 -- C5
Your machine: C1 -- C2 -- C3 -- C4 -- C5 (origin/main — updated)
\
D -- E (your local main — unchanged)
Your working branch is not touched. Only the remote-tracking reference is updated. You then decide what to do with those changes — merge, rebase, or inspect.
Pushing a Branch to a Remote
Local branches are not automatically shared. To publish a branch:
git push origin feature-login
This creates a feature-login branch on the remote and sets up origin/feature-login as its remote-tracking reference on your machine.
To push a local branch under a different name on the remote:
git push origin feature-login:new-name-on-remote
Credential caching
If you use HTTPS and are prompted for a password on every push, configure credential caching to avoid typing it repeatedly:
git config --global credential.helper cache
Tracking Branches
A tracking branch (also called an upstream branch) is a local branch that has a direct relationship with a remote-tracking branch. When you are on a tracking branch, git pull automatically knows which server to fetch from and which branch to merge into yours.
How tracking branches are created
When you clone a repository, Git automatically creates a local main branch that tracks origin/main. This is why git pull works immediately after cloning without specifying any arguments.
When you check out a local branch from a remote-tracking branch, Git sets up tracking automatically:
git checkout -b feature-login origin/feature-login
Branch 'feature-login' set up to track remote branch 'feature-login' from 'origin'.
A shorter equivalent using --track:
git checkout --track origin/feature-login
An even shorter shortcut — if the branch name doesn't exist locally and exactly matches one name on a remote, Git creates it with tracking set up automatically:
git checkout feature-login
# Branch 'feature-login' set up to track remote branch 'feature-login' from 'origin'.
Setting or changing the upstream for an existing branch
If you already have a local branch and want to set or change which remote branch it tracks:
git branch -u origin/feature-login
# or
git branch --set-upstream-to origin/feature-login
Upstream shorthand
Once tracking is set up, you can refer to the upstream branch with @{upstream} or @{u}:
git merge @{u} # Same as: git merge origin/main
git diff @{u} # Diff your branch against its upstream
Checking Tracking Status — git branch -vv
To see all local branches alongside what they track and how far ahead or behind they are:
git branch -vv
feature-login 93b412c [origin/feature-login: ahead 2] Add form validation
* main 7a98805 [origin/main] Merge branch 'feature-login'
experiment 5ea463a (no upstream set)
Reading the output:
| Column | Meaning |
|---|---|
* | The currently checked-out branch |
| Hash | The abbreviated SHA-1 of the last commit on that branch |
[origin/branch] | The remote-tracking branch it follows |
ahead N | N local commits not yet pushed to the remote |
behind N | N remote commits not yet pulled into the local branch |
| No brackets | No upstream tracking branch configured |
Important:
git branch -vvshows cached data from the last fetch. For current numbers, rungit fetch --allfirst:git fetch --all && git branch -vv
Deleting Remote Branches
Once a branch is merged and no longer needed on the remote:
git push origin --delete feature-login
This removes the branch pointer from the remote server. The commits themselves are not immediately deleted — they remain in the database until garbage collection runs, which means an accidental deletion can often be recovered.
Cleaning up stale remote-tracking references
After remote branches are deleted, their local remote-tracking references may linger. Clean them up with:
git fetch --prune
Or configure Git to prune automatically on every fetch:
git config --global fetch.prune true
How Everything Fits Together
Here is the relationship between the three types of references involved in remote collaboration:
| Reference type | Example | Who controls it | Purpose |
|---|---|---|---|
| Local branch | main | You — moves with your commits | Where you do your work |
| Remote-tracking branch | origin/main | Git — updates on fetch/push/pull | Bookmark of the remote's last known state |
| Remote branch | main on origin | The remote server | The actual shared branch |
When you git fetch, the remote-tracking branch moves to match the remote branch. When you git push, the remote branch moves to match your local branch. The two never automatically synchronise — you are always in control of when synchronisation happens.
Summary
| Command | What It Does |
|---|---|
git fetch origin | Updates all remote-tracking branches from origin |
git fetch --all | Updates remote-tracking branches from all remotes |
git fetch --prune | Updates and removes stale remote-tracking references |
git push origin <branch> | Publishes a local branch to the remote |
git push -u origin <branch> | Publishes and sets up tracking |
git push origin --delete <branch> | Deletes a remote branch |
git checkout --track origin/<branch> | Creates a local tracking branch |
git branch -u origin/<branch> | Sets the upstream for the current branch |
git branch -vv | Shows tracking info and ahead/behind counts |