git pull
fetch + merge (or fetch + rebase) — why this trips people up.
git pull is not a primitive — it is a macro that runs git fetchfollowed by an integration step. The surprise is that integration step: on a diverged branch it silently creates a merge commit, which many developers don't expect from a simple "sync" command.
Pull in Action
Choose the fast-forward scenario (remote is strictly ahead) or the diverged scenario (both sides have new commits). On diverged, toggle between merge and rebase strategies.
What pull actually does
Step 1: git fetch origin — contacts the remote, downloads new objects, advances origin/mainto reflect the remote's current state. Your local branch and working directory are untouched.
Step 2: integration — by default, git merge origin/main. If your local branch is strictly behind (fast-forward), the branch pointer just slides forward — no new commit. If both sides diverged, a merge commit is created.
With --rebase, step 2 becomes git rebase origin/main instead. Your local commits are replayed on top of the fetched commits, producing linear history without a merge commit.
Configuring the default strategy
You can set the integration strategy globally so you never have to pass a flag:
The pull.ff only option is the safest: it refuses to create merge commits silently, forcing you to consciously decide how to integrate diverged work.