Merging
By the end of this lesson
Bring a branch back and understand what a merge commit records.
Merging combines the work on one branch into another. You move onto the branch that should receive the work, then name the branch whose work you want.
How Git does it depends on one question: has the receiving branch moved on since your branch started? The answer produces two noticeably different outcomes, and knowing which you are looking at removes most of the mystery from merging.
Case 1 — main has not moved since the branch started
before main -> C
feature -> E (chain: A - B - C - D - E)
after main -> E Git moves the pointer forward.
feature -> E No new commit is created.
Case 2 — main has moved on
before main -> F (chain: A - B - C - F)
feature -> E (chain: A - B - C - D - E)
after main -> M M is a new merge commit.
M's parents are F and E.- Case 1 is a fast-forward. Every commit on main is already in feature's chain, so there is nothing to reconcile and Git only has to slide the pointer.
- Case 2 needs a real merge. The two branches genuinely diverged at C, so Git combines the two sets of changes and records the result as a new commit.
The two outcomes side by side:
| Fast-forward | Merge commit | |
|---|---|---|
| When it happens | The receiving branch has no commits your branch does not have | Both branches have commits the other does not |
| New commit created? | No | Yes, with two parents |
| Resulting history | A single straight line | Two lines that meet at the merge commit |
| Can conflicts occur? | No — there is nothing to reconcile | Yes, if both sides changed the same lines |
| Record of the branch | None — you cannot tell a branch existed | Preserved — the shape shows where work split and rejoined |
# Get onto the branch that should receive the work
git switch main
# Make sure it is current before merging into it
git pull
# Bring the branch in
git merge add-expense-export
# See the shape of the history you produced
git log --graph --oneline --all
# The branch pointer has served its purpose
git branch -d add-expense-export- The order matters: you merge into the branch you are standing on. Running git merge main while on your feature branch does the opposite of what is described here, and is a genuinely useful thing to do for a different reason.
- git pull first means you merge into an up-to-date main, so you find out about conflicts now rather than when you try to push.
- git log --graph --oneline --all draws the branch structure as text. It is the fastest way to confirm whether you produced a fast-forward or a merge commit.
- Deleting the branch afterwards removes the pointer, not the commits. The work is in main's history and stays there.
A merge commit is the one kind of commit with two parents, and that is exactly what it records: this commit is the point where those two lines of work became one. Its first parent is where the receiving branch was, and its second is the tip of the branch you merged.
This is more than trivia. Two parents are how Git can later work out what came from which line of development, and how tools show you a feature as a single unit rather than seven scattered commits.
Summary
- You merge into the branch you are currently on
- A fast-forward moves the pointer forward and creates no commit, because the branches never truly diverged
- A real merge creates a commit with two parents, recording where two lines of work joined
- Update the receiving branch before merging so conflicts surface early
- A conflict-free merge can still break behaviour — build and test afterwards
Practice
Attempt each one before opening the solution. Getting it wrong first is how the idea sticks.
Try it yourself
Produce one of each
Create a branch, make one commit, switch back to main and merge. Look at git log --graph --oneline.
Now do it again, but before merging, make a commit directly on main. Merge and compare the two graphs.
Show solution
The first merge is a fast-forward: the graph is a straight line and no merge commit appears. Nothing in the history shows that a branch was involved.
The second produces a merge commit with two parents, and the graph shows the split and the rejoin. The only difference between the two runs is whether main moved, which is precisely the condition that decides.
git switch -c tidy-report-header
git commit -am "Align the report header with the invoice layout"
git switch main
git merge tidy-report-header
git log --graph --onelineThink about it
Think about it
A merge commit has two parents. What could you work out from that which you could not work out from a straight line of commits?
Show solution
You can tell which commits belonged to the feature and which to the receiving branch, and you can see the point at which the two lines diverged.
That allows things a linear history cannot offer: reverting a whole feature as one unit, and seeing a feature as a group rather than as commits interleaved with everyone else's by timestamp.
It is also the honest record. The work genuinely happened in parallel, and the merge commit is the only thing that says so.
Knowledge check
Nothing is recorded and there is no score. The explanation appears either way.
Saved in this browser only.