git pull is two operations, not one
git pull is shorthand for git fetch followed by an integration step — by default a merge, optionally a rebase. That second step is where confusion lives. Without thinking about it, git pull will create merge commits in your local branch when there is divergence, which is rarely what most developers actually want for short-lived feature work.
Two integration choices, both legitimate. Merge joins your branch with the upstream changes by creating a merge commit if needed. Preserves divergence in history. Good when the divergence is meaningful (long-lived integration branches, releases). Rebase replays your local commits on top of the upstream tip. Result: linear history. Good for short-lived feature work where the divergence is "I worked while someone else also worked" rather than a structural fork.
The recommended modern default is to set pull.rebase = true globally and use plain git pull for daily work. Linear history is easier to read, bisect is cleaner, and reviewers see one chain instead of "merge of main into feature" noise. When the situation calls for a true merge (release branch integration, big-feature handoff), use git merge explicitly. git pull is for the routine case.
Two failure modes to recognize. Pull with uncommitted changes: Git refuses if integration would touch the same files. The fix is commit (or stash) first, pull second. Pull rebase mid-conflict: rebase pauses on each conflicting commit, asks you to resolve and git rebase --continue. If a rebase pull goes sideways, git rebase --abort rewinds you to before the pull, fully reversible.