Push sends your commits to the remote. Pull is the other
direction: it brings the remote's commits down to your machine.
git pull is what you run when you sit down to work in the
morning and want to make sure you have whatever your teammates
pushed overnight.
Pull is really two operations
Under the hood, git pull is two commands chained together:
git fetch: downloads new commits from the remote into your local repo. Updates the remote-tracking branches (likeorigin/main). Doesn't touch your local branches.git merge(orgit rebase): takes those newly-fetched commits and integrates them into your current local branch.
So git pull origin main is roughly equivalent to:
git fetch origin
git merge origin/main
Splitting them apart is useful sometimes. git fetch is
completely safe. It just downloads. You can then inspect what the
remote has before deciding whether to merge:
git fetch origin
git log HEAD..origin/main --oneline # what's new upstream?
git merge origin/main # merge if you like it
Most of the time you don't bother; you just git pull and get on
with your day.
Fast-forward pulls
If your local branch hasn't moved since you last synced, the pull
is a fast-forward. Git slides your local main pointer forward to
match origin/main, no merge commit needed:
Fast-forward
remote.txt | 1 +
1 file changed, 1 insertion(+)
Simple case, most common case.
Diverged pulls
If your local branch has its own new commits AND the remote has new commits, pull has to do a real merge. It creates a merge commit, and your history now has the diamond shape from the Diverged module:
Merge made by the 'ort' strategy.
This is fine, but a lot of teams prefer their local branches to stay linear so the log is easier to read. For those teams, the pattern is:
git pull --rebase origin main
Instead of a merge, Git rebases your local commits on top of the remote's. Same commits (with the same content), just replayed at a different position, giving you a straight-line history.
If you want that behaviour by default forever:
git config --global pull.rebase true
What if there are conflicts?
If your local and remote versions of a file conflict on the same
line, pull pauses with a merge conflict. You resolve it exactly
like the merge-conflict lesson: edit the file, remove the markers,
git add, then git commit to finish the merge (or git rebase --continue if you were pulling with --rebase).
Conflicts during pull feel worse than they are because they're usually a surprise. Nothing about the resolution is different from a normal merge conflict.
Pulling with uncommitted changes
If you have uncommitted changes and Git thinks the pull would overwrite them, it refuses. Your options are the same as the switch-branch case:
- Commit them.
- Stash them (
git stash), pull, thengit stash pop. - Discard them, if they don't matter.
Git will never quietly overwrite work you've done. Read the error message; the fix is always one of those three.