Git commands
What a merge commit is, and why it has two parents
git merge: how two branches become one
How to use this page
- slider / ▶Drag the slider, or press play, to watch the command happen. Before and After jump to either end.
- ← → · spaceStep through a multi-step command; space toggles Before / After.
- APlay or pause the loop (the page opens playing). Any manual input takes over.
- hoverA commit shows its message, author, date and parents, with its history highlighted.
- clickCopies the commit sha.
- ctrl + wheelZoom around the cursor (pinch on a trackpad). Double-click resets the view.
- EscStop playback, reset the view, close this menu.
- shareThe Share button copies a link to this graph, copies it as an image, downloads PNG/SVG/page, or posts it. #before, #after or #step=N in the link pins the state.
git-sim visually simulates any Git command in your own repos - from your terminal, IDE, or AI.
Table of Contents
- Introduction
- What is git merge?
- Watch it happen
- Before and after
- What a merge commit contains
- When two sides change the same lines
- Is it safe?
- How to undo it
- Try it on your repository
- Common questions
- Summary
- Next steps
- Related commands
Introduction
A merge is how work done on a branch gets back to where everyone else can see it. Most of the time it's uneventful: Git combines the two histories, makes one commit, and you carry on. The interesting part is that one commit, because it's the only kind of commit in Git with more than one parent, and that shape is what lets Git remember that two lines of work were ever separate.
In this article, we'll:
- Watch
git merge featurecreate a merge commit on a small repository - Look at what a merge commit contains and why it has two parents
- Cover what a conflict is, how to undo a merge, and when a merge doesn't make a merge commit at all
What is git merge?
git merge <branch> takes the commits on <branch> that your current branch doesn't have and combines them with your current branch. When both branches have moved since they split, Git finds the last commit they share (the merge base), works out what each side changed since then, applies both sets of changes to one tree, and records the result as a merge commit with two parents: your previous tip and the tip of <branch>.
If only one side has moved, there's nothing to combine and Git just moves your branch forward. That's a fast-forward, and it has its own page.
Watch it happen
Our sample repo has two commits on main and three on feature since the branches split. Here's git merge feature with main checked out:
- Before:
mainandHEADon8c02d5b, andfeatureon1117a34at the end of its own three commits. The two branches have diverged. - Git creates a merge commit, "Merge branch 'feature'", with two parents:
8c02d5bonmainand1117a34onfeature. mainandHEADmove to the merge commit.featurestays where it was. Merging intomaindoesn't move the branch you merged from.
Before and after
Before, the two branches share 96c4fc2 and then go their own ways. After, they're joined by a commit that reaches both. Git's own report of the merge lists the files it brought in:
The raw git output, if you want to read along in text
git log --oneline --graph --all
before
* 1117a34 (feature) Add search tests
* e5869f0 Fix typo in search box
* fc19889 Add search box
| * 8c02d5b (HEAD -> main) Update dependencies
| * a0b2db3 Add user settings page
|/
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commitafter
* ee672dd (HEAD -> main) Merge branch 'feature'
|\
| * 1117a34 (feature) Add search tests
| * e5869f0 Fix typo in search box
| * fc19889 Add search box
* | 8c02d5b Update dependencies
* | a0b2db3 Add user settings page
|/
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commitwhat git printed
Merge made by the 'ort' strategy.
search.html | 1 +
test_search.py | 2 ++
2 files changed, 3 insertions(+)
create mode 100644 search.html
create mode 100644 test_search.pyWhat a merge commit contains
Run git cat-file -p HEAD after the merge and you'll see two parent lines:
tree ...
parent 8c02d5b...
parent 1117a34...
The first parent is the branch you were on. The second is the one you merged. Everything else, git log --first-parent, git revert -m 1, the shape of --graph output, hangs off that ordering. The tree is the combined result, so checking out the merge commit gives you both sets of changes.
When two sides change the same lines
Git can combine changes to different parts of a file, or different files, on its own. When both branches changed the same lines of the same file, it stops with a conflict, writes both versions into the file between <<<<<<< and >>>>>>> markers (the git merge documentation shows the other marker styles), and waits. You edit the file to what it should be, git add it, and git commit to finish the merge. git merge --abort puts everything back to before you started.
Our sample merge had no conflicts, and git-sim checked that ahead of time with git merge-tree, which is what the "No conflicts detected" line in the report below comes from.
Is it safe?
Safe git-sim pre-flight
Brings in 3 commit(s) from feature (merge commit).
The way back
Undo the merge commit with: git reset --hard ORIG_HEAD (back to 8c02d5b)
A merge adds a commit and moves your branch forward. Nothing existing is rewritten. The only thing to know in advance is whether it will conflict, which git-sim tells you.
How to undo it
If you haven't pushed:
git reset --hard HEAD~1
main goes back to 8c02d5b, and since feature still points at its commits, nothing is lost. If the merge has been pushed, git revert -m 1 <merge-sha> adds a commit that undoes the merged changes while keeping history intact.
Try it on your repository
pip install git-sim
git-sim merge feature
git-sim shows the merge commit and both parents on your own graph, and runs Git's conflict check first, so you know whether the merge will go through cleanly before you start it.
Common questions
What is a merge commit?
A commit with two parents: the tip of the branch you were on and the tip of the branch you merged. Its tree contains the combined changes from both.
What is a merge base?
The most recent commit that both branches have in their history. Git compares each side against it to work out what changed.
How do I undo a git merge?
Before pushing, git reset --hard HEAD~1 moves your branch back to the commit before the merge. After pushing, git revert -m 1 <merge-commit> adds a new commit that reverses the merge.
What is the difference between git merge and git rebase?
Merge joins two histories with a merge commit and keeps both intact. Rebase reapplies your commits onto the other branch as new commits, producing a straight line and rewriting your branch's history.
Summary
In this article, we watched git merge create a two-parent commit joining main and feature, looked at what that commit contains, and covered conflicts and how to undo a merge.
Next steps
Fast-forward merges are the case where no merge commit is needed, and git rebase is the alternative that avoids one on purpose.
Related commands
- Fast-forward merge, when only one side moved
- git merge --no-ff, to insist on a merge commit
- git rebase, the other way to combine branches
- git revert, to undo a pushed merge
- git reset --hard, to undo an unpushed one
- git pull, which merges for you
- git merge --squash, to bring in a branch's changes as one commit of your own
- git merge --continue, to finish a merge after resolving a conflict
- git merge --abort, to back out of a merge that stopped on a conflict
