Git commands
Why some merges create no merge commit at all
Fast-forward merges: when merging just moves a label
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 a fast-forward merge?
- Watch it happen
- Before and after
- Why some teams disable it
- Is it safe?
- How to undo it
- Try it on your repository
- Common questions
- Summary
- Next steps
- Related commands
Introduction
Sometimes you run git merge and the output says "Fast-forward" instead of "Merge made by the 'ort' strategy", and there's no merge commit anywhere. People occasionally think something went wrong. Nothing did. Git noticed there was nothing to combine and took the shortcut.
In this article, we'll:
- Watch a fast-forward merge on a small repository
- See why Git didn't need to create a commit
- Cover when this happens, why some teams turn it off, and how to force a merge commit
What is a fast-forward merge?
When you merge <branch> into your current branch and your current branch has no commits that <branch> lacks, the tip of <branch> already contains everything. There is nothing to combine, so Git just moves your branch's pointer to that commit. That's a fast-forward. The history stays a straight line and no new commit is made.
It's the same thing that happens on a git pull when you have no local commits: your branch catches up to the remote by moving forward.
Watch it happen
Our sample repo has a release branch two commits behind main with nothing of its own: release sits at 96c4fc2, and main has two commits after that. Here's git merge main with release checked out:
- Before:
releaseandHEADon96c4fc2, two commits behindmainat8c02d5bon the same history. - Git fast-forwards
releasetwo commits to8c02d5b.HEADmoves with it because it's attached torelease. - Git creates no commit. The history has the same commits as before.
Before and after
release and main now point at the same commit. The only thing that changed in .git is the hash inside .git/refs/heads/release. Git's output says so directly:
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 (main) Update dependencies
| * a0b2db3 Add user settings page
|/
* 96c4fc2 (HEAD -> release) Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commitafter
* 1117a34 (feature) Add search tests
* e5869f0 Fix typo in search box
* fc19889 Add search box
| * 8c02d5b (HEAD -> release, main) Update dependencies
| * a0b2db3 Add user settings page
|/
* 96c4fc2 Fix header layout
* ae65976 Add login page
* 3e1ffe4 Add project skeleton
* 4114b2c Initial commitwhat git printed
Updating 96c4fc2..8c02d5b
Fast-forward
requirements.txt | 1 +
settings.html | 1 +
2 files changed, 2 insertions(+)
create mode 100644 requirements.txt
create mode 100644 settings.html"Updating 96c4fc2..8c02d5b" followed by "Fast-forward" is Git telling you it moved the pointer and did nothing else.
Why some teams disable it
A fast-forward leaves no trace that a branch ever existed. If your team likes to see a merge commit for every feature, so git log --first-parent main reads as a list of features, they'll set merge.ff = false or use --no-ff when merging, which has its own page. GitHub's "Create a merge commit" button does the same thing.
The opposite preference exists too: git merge --ff-only refuses to merge unless it can fast-forward, which guarantees a straight-line history and is a common setting for pull (the git merge documentation describes both --ff-only and merge.ff).
--no-ff for feature branches, mostly because reverting a whole feature is one command when it came in as a single merge commit.
Is it safe?
Safe git-sim pre-flight
Brings in 2 commit(s) from main (fast-forward).
The way back
A fast-forward only moves the branch: git reset --hard ORIG_HEAD puts it back on 96c4fc2
A fast-forward changes one ref. No commits are created or rewritten, and your working directory updates to the new tip the same way a checkout would.
How to undo it
git reset --hard 96c4fc2
or git reset --hard ORIG_HEAD, which Git sets to the pre-merge position for exactly this purpose.
Try it on your repository
pip install git-sim
git-sim merge main
git-sim tells you before the merge whether it will fast-forward or create a merge commit, and lists the commits your branch would gain.
Common questions
What does fast-forward mean in Git?
Your branch had no commits the other branch lacked, so Git moved your branch pointer to the other branch's tip instead of creating a merge commit.
Why did git merge not create a merge commit?
Because it fast-forwarded. Use git merge --no-ff if you want a merge commit regardless.
What is git merge --ff-only?
A merge that refuses to run unless it can fast-forward. It's a way to guarantee your branch's history stays linear, and a common choice for git pull.
How do I undo a fast-forward merge?
git reset --hard ORIG_HEAD moves the branch back to where it was before the merge.
Summary
In this article, we watched git merge fast-forward the release branch two commits without creating a merge commit, saw why Git could take that shortcut, and covered how to prevent or require it.
Next steps
git merge --no-ff shows the same merge with a merge commit forced. git merge covers the case where both sides have moved.
Related commands
- git merge, when both branches have changed
- git merge --no-ff, to force a merge commit
- git rebase, another way to get a straight line
- git pull, which often fast-forwards
- git branch, the pointer that moved
- git log, to see the resulting history
