Fetch, Pull, and Upstream Tracking
The previous lesson introduced git fetch, git push, and remote-tracking branches. Here we connect them into a reliable daily workflow. The key distinction is whether you want to learn about remote changes or integrate them into your current branch.
Fetch: inspect before integrating
Section titled “Fetch: inspect before integrating”git fetch origingit statusgit log --oneline main..origin/maingit diff main..origin/mainFetch downloads objects and updates matching remote-tracking references according to the fetch configuration. It does not merge or rebase into your checked-out branch, and it does not rewrite your working files. Your local main can therefore remain behind origin/main after a fetch.
git fetch origin main requests the named remote branch. With the normal cloned refspec it also updates origin/main; custom refspecs can behave differently. A plain git fetch origin does not promise to fetch every possible server-side ref.
Git may refresh metadata and objects, so “fetch touches nothing” is inaccurate. Its valuable guarantee is narrower: it does not integrate the fetched commits into your current branch.
Pull: fetch and integrate
Section titled “Pull: fetch and integrate”git switch maingit pull origin mainPull first fetches, then integrates the selected remote history into the currently checked-out branch. Depending on Git version and repository configuration, integration may fast-forward, merge, rebase, or refuse divergence until you choose a policy. Do not memorize “pull always means fetch plus merge.”
For a predictable update that refuses diverged histories:
git switch maingit pull --ff-only origin mainIf your branch contains local commits that are absent remotely, a fast-forward may be impossible. Inspect the graph before choosing merge or rebase:
git fetch origingit log --oneline --graph --decorate --all -12git pull --rebase origin main fetches and then replays your local commits on top of the fetched branch. That rewrites their commit IDs, so use it only when those commits are yours to rewrite. A separate rebase lesson covers the full process.
Uncommitted changes may block pull or complicate conflict resolution. Commit or stash relevant work before integrating. A conflict is possible when Git cannot combine both sides automatically.
| Question | git fetch origin |
git pull origin main |
|---|---|---|
| Download remote history? | Yes | Yes |
| Update remote-tracking refs? | Normally yes, per refspec | Normally yes, per refspec |
| Integrate into current branch? | No | Yes, or refuse |
| Change working files? | No | Possibly |
| Can integration conflict? | No integration occurs | Yes, if merge/rebase is attempted |
Choose fetch when you want to review the incoming commits first. Choose pull when you are ready to integrate into the branch you are standing on and know the intended integration policy.
Push and upstream tracking
Section titled “Push and upstream tracking”The preceding lesson showed that a named push affects a selected branch:
git push origin maingit push origin feature/loginIf both local branches have new commits, the first command does not publish the second branch. Staged or unstaged edits are not pushed either. After a branch push succeeds, another teammate must fetch or pull to learn about it.
For the first publication of a feature branch:
git switch feature/paymentgit push -u origin feature/paymentThe push sends commits, creates or updates the destination branch if allowed, and stores an upstream relationship for the local branch. The local remote-tracking name origin/feature/payment represents your last known remote position; the actual hosted branch is separate. -u does not create a magic live synchronization.
After tracking is configured, short commands usually work under the repository’s push and pull settings:
git pushgit pullgit branch -vvCheck git branch -vv and git status rather than assuming a branch has the intended upstream. A branch with no upstream may require an explicit remote and branch on first push. Some configurations can set the upstream automatically, so a particular error message is not universal.
An end-to-end .NET example
Section titled “An end-to-end .NET example”Assume the hosted inventory-service already contains a default branch. Clone it, inspect the connection, and update safely:
git clone https://github.com/acme-learning/inventory-service.gitcd inventory-servicegit remote -vgit branch -vvgit fetch origingit log --oneline main..origin/maingit switch maingit pull --ff-only origin mainNow implement one focused change and publish it:
dotnet testgit statusgit add Models/InventoryItem.csgit diff --cachedgit commit -m "feat: add inventory model"git pushFor a second change, the sequence still needs a new commit before another push:
git add Services/InventoryService.csgit diff --cachedgit commit -m "feat: add inventory rules"git pushOne lecture slide showed git add . && git push for a second change. That would not publish the newly staged edits: push transfers commits, not the index. It might report everything up to date while the edit remains local.
When working on a feature branch, publish that branch separately if you need a Pull Request or a teammate to review unfinished work:
git switch -c feature/discount-rulesgit add Services/DiscountService.csgit commit -m "feat: add discount rules"git push -u origin feature/discount-rulesYou do not have to push every private draft branch. Push it when it needs backup or collaboration, while respecting the team’s policy about unfinished work.
Common mistakes
Section titled “Common mistakes”- Treating fetch as a merge into the current branch.
- Treating pull as always equivalent to a merge, regardless of configuration.
- Pulling while checked out on the wrong branch.
- Assuming
git statuscompares against the live server without a recent fetch. - Pushing staged edits that have not been committed.
- Assuming one branch push publishes all other branches.
- Assuming
-uupdates branches automatically after the initial push.
Summary
Section titled “Summary”Fetch gives your local repository newer information about remote history. Pull fetches and attempts to integrate into the current branch. Push transfers selected committed history outward. An upstream records the default relationship between a local branch and a remote branch; it does not synchronize them automatically.
Knowledge check
Section titled “Knowledge check”- After fetching, can local
mainstill be behindorigin/main? - Why can pull change working files while fetch does not?
- What happens if you stage a second edit and run push without committing it?
- Does pushing
mainpublish new commits onfeature/login? - What information does
git push -usave for later commands?