Two merge shapes, one mental model
Every git merge ends in one of two shapes. Fast-forward: the target branch has not advanced since the source branched off, so Git just slides the target pointer forward to the source's tip. No new commit. Three-way (true) merge: both branches advanced, so Git creates a new commit with two parents — yours and theirs — joining the histories at a Y. The graph itself tells you which happened: a straight line versus a diamond.
The fast-forward case is what you usually get when you finish a small feature on a branch that nobody else touched. git merge feature with main unchanged just moves main's pointer. The downside is that the branch's existence is invisible afterward — there is no signal in history that this was a feature branch, just a longer linear chain. Some teams force a merge commit even when fast-forward would work, using --no-ff, to preserve the "this was a unit of work" record.
The three-way merge is what you get when both sides moved. Git uses the most recent common ancestor as a base, computes diffs from base to each side, and combines them. If the diffs touch different lines, the merge is automatic. If they touch the same lines, you get a conflict — that is the next lesson. The merge commit's message defaults to "Merge branch 'feature' into main" — replace that with something meaningful when the merge is significant.
Two flags worth knowing. git merge --ff-only refuses to merge if a fast-forward is impossible, useful in scripts that should fail loudly rather than create a merge commit. git merge --squash takes all the changes from the source branch and stages them as a single commit on top of the target — useful when the branch's individual commits are noisy and you want one clean commit on main.