Git Merge

Merging is how Git brings the independent work from one branch into another, either by fast-forwarding a pointer or by weaving histories together with a dedicated merge commit.

What Merging Does

`git merge <branch>` integrates the commits from <branch> into your current branch. Git finds the best common ancestor of the two branches and combines everything that happened on each side since that point. The result depends entirely on how far the two branches have diverged from one another.

Fast-Forward Merges

If your current branch hasn't moved since the other branch was created, meaning your branch's tip is a direct ancestor of the branch you're merging, Git doesn't need to create a new commit at all. It just slides your branch pointer forward to match. This is called a fast-forward merge, and it's why merging a fresh feature branch back into main often produces no merge commit.

Fast-forward merge

$ git switch main
$ git merge feature/footer-links

Three-Way Merges and Conflicts

If both branches have new commits since they diverged, Git can't simply move a pointer. It performs a three-way merge, comparing the common ancestor against each branch's tip and combining the changes into a new merge commit with two parents. This is the normal case once main has kept moving while you worked on a feature branch.

Three-way merge producing a merge commit

$ git merge feature/checkout-redesign

A conflict happens when both branches changed the same lines of the same file in incompatible ways. Git pauses the merge, marks the file, and inserts conflict markers so you decide the outcome yourself. It never guesses on your behalf.

A conflicting merge and its resolution

$ git merge feature/pricing-update
$ git status
$ git add src/data/pricing.json
$ git commit
  • <<<<<<< HEAD - start of your current branch's version
  • ======= - divider between the two conflicting versions
  • >>>>>>> branch-name - end of the incoming branch's version
  • After editing the file, stage it with git add to mark the conflict resolved
  • git merge --abort backs out entirely and restores the pre-merge state
OptionEffect
--no-ffAlways create a merge commit, even if a fast-forward is possible
--squashCombine incoming commits into one set of staged changes, no merge commit
--abortCancel a conflicted merge and return to the pre-merge state
-X ours / -X theirsAuto-resolve whole-file conflicts by favoring one side
Note: Many teams pass --no-ff on purpose when merging feature branches into main, since the resulting merge commit preserves a clear marker of where a feature started and ended in the log.
Note: A merge conflict is not a sign you did something wrong. It's Git being honest that it found two edits to the same lines and is refusing to silently pick a winner for you.

Exercise: Git Merge

What does `git merge <branch>` do?