What is a merge?

Joining two lines of work: a merge commit with two parents, or a fast-forward when there is nothing to join.

A merge brings the commits of one branch into another. Git finds the last commit the two branches share, works out what each side has changed since then, and combines the two sets of changes into one new commit. That commit has two parents, one on each branch, which is how the graph shows the join. The branch you merged into moves to it; the other branch stays where it was.

Sometimes there is nothing to combine. If the branch you are on has not moved since the two parted, every commit on the other branch already builds on yours, and Git simply moves your branch forward to the other branch’s commit. That is a fast-forward: no new commit, and afterwards the two names point at the same place.

  1. Two branches at the same commit, C. Nothing has diverged yet.

  2. Work on both. feature has D and E; main has F. C is the last commit they share.

  3. Merge feature into main. M combines F's changes with D's and E's, and has both F and E as parents. main moves to M; feature stays at E.

  4. Now merge main into feature. M already has E behind it, so there is nothing to combine: feature moves to M. That is a fast-forward.

When the two sides disagree

Git combines changes line by line, and it only knows how when the two sides touched different lines. Where both changed the same lines it stops before making the merge commit, marks the file, and asks you to choose. That is a conflict, and it is a normal outcome of a merge rather than a failure of one: resolving it means editing the file to what it should be, then finishing the merge.

A squash merge is the same combination without the second parent. The other branch’s changes arrive as one ordinary commit on yours, and its own commits are not part of your history.

On the command line

git switch main
git merge feature            # a merge commit, or a fast-forward
git merge --no-ff feature    # always a merge commit
git merge --squash feature   # the changes, staged, as one commit to make

Git’s own reference: git-merge. The Pro Git book walks through the same two cases.

In Innesta

The three kinds Innesta offers, and what each does to the history, are on merging. A merge that stops is a conflict, settled in the three-pane editor; one you would rather not finish can be abandoned. The commit graph is where a merge commit shows its two parents.

The Playground is a repository made for trying this on.