Skip to content

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.

Terminal window
git fetch origin
git status
git log --oneline main..origin/main
git diff main..origin/main

Fetch 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.

Terminal window
git switch main
git pull origin main

Pull 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:

Terminal window
git switch main
git pull --ff-only origin main

If your branch contains local commits that are absent remotely, a fast-forward may be impossible. Inspect the graph before choosing merge or rebase:

Terminal window
git fetch origin
git log --oneline --graph --decorate --all -12

git 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.

The preceding lesson showed that a named push affects a selected branch:

Terminal window
git push origin main
git push origin feature/login

If 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:

Terminal window
git switch feature/payment
git push -u origin feature/payment

The 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:

Terminal window
git push
git pull
git branch -vv

Check 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.

Assume the hosted inventory-service already contains a default branch. Clone it, inspect the connection, and update safely:

Terminal window
git clone https://github.com/acme-learning/inventory-service.git
cd inventory-service
git remote -v
git branch -vv
git fetch origin
git log --oneline main..origin/main
git switch main
git pull --ff-only origin main

Now implement one focused change and publish it:

Terminal window
dotnet test
git status
git add Models/InventoryItem.cs
git diff --cached
git commit -m "feat: add inventory model"
git push

For a second change, the sequence still needs a new commit before another push:

Terminal window
git add Services/InventoryService.cs
git diff --cached
git commit -m "feat: add inventory rules"
git push

One 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:

Terminal window
git switch -c feature/discount-rules
git add Services/DiscountService.cs
git commit -m "feat: add discount rules"
git push -u origin feature/discount-rules

You 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.

  • 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 status compares 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 -u updates branches automatically after the initial push.

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.

  1. After fetching, can local main still be behind origin/main?
  2. Why can pull change working files while fetch does not?
  3. What happens if you stage a second edit and run push without committing it?
  4. Does pushing main publish new commits on feature/login?
  5. What information does git push -u save for later commands?