git merge Explained: Fast-Forward, Three-Way, –no-ff and Squash Merges

Merging brings finished work back into main. In this lesson you will learn how Git decides between fast-forward and three-way merges, use the most important merge options, check what will be merged, and clean up afterwards.

Advertisement

๐Ÿ“– What You’ll Learn: how merging works, fast-forward merges, three-way merges and merge commits, –no-ff, –ff-only, –squash and –abort, –no-ff vs squash and GitHub’s merge buttons, checking branches before and after a merge, and cleaning up merged branches.


๐Ÿ”€ What Does Merging Do?

When the work on a branch is finished, you merge it into another branch, usually main. Git combines the histories and the changes. You always merge into the branch you are currently on:

git switch main                 # 1. go to the branch that should receive the changes
git pull                        # 2. make sure it is up to date
git merge feature/login-tests   # 3. bring the feature in

Depending on the history, Git performs one of two kinds of merge.


โฉ Fast-Forward Merge

If main has no new commits since the branch was created, Git simply moves the main pointer forward. No merge commit is created.

Before:                              After git merge feature:
C1 โ”€โ”€ C2 โ† main                      C1 โ”€โ”€ C2 โ”€โ”€ C3 โ”€โ”€ C4 โ† main, feature
        \
         C3 โ”€โ”€ C4 โ† feature
Updating 8b1d4e2..7e2f1a9
Fast-forward
 tests/login.spec.ts | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

๐Ÿ”บ Three-Way Merge

If both branches have new commits, Git looks at three snapshots (the common ancestor and the two branch tips) and creates a new merge commit with two parents.

Before:                                After git merge feature:
C1 โ”€โ”€ C2 โ”€โ”€ C5 โ† main                  C1 โ”€โ”€ C2 โ”€โ”€ C5 โ”€โ”€โ”€โ”€ M โ† main
        \                                      \          /
         C3 โ”€โ”€ C4 โ† feature                     C3 โ”€โ”€ C4 โ† feature

Git opens your editor with a default message like “Merge branch ‘feature/login-tests'”; save and close to finish. If both branches changed the same lines, Git stops with a conflict instead; see Resolve Merge Conflicts.


๐ŸŽ›๏ธ Merge Options

CommandResult
git merge featureFast-forward if possible, otherwise a merge commit
git merge --no-ff featureAlways create a merge commit, keeping the branch visible in history
git merge --ff-only featureMerge only if a fast-forward is possible; otherwise stop
git merge --squash featureCombine all branch changes into staged changes; you then make one normal commit
git merge --abortCancel a merge that stopped with conflicts and go back to the state before

–no-ff vs –squash

--no-ff--squash
Commits from the branch kept in main’s historyโœ… All of themโŒ Replaced by one new commit
Merge commitโœ…โŒ
Readable history of mainDetailedCompact, one commit per feature
GitHub equivalent“Create a merge commit”“Squash and merge”

GitHub’s three pull-request merge buttons (merge commit, squash and merge, rebase and merge) map to these strategies; see Pull Requests Step by Step.


๐Ÿ” Check Before and After Merging

git log --oneline main..feature/login-tests   # commits that will come in
git diff main...feature/login-tests           # changes on the branch since it split from main
git branch --merged                           # branches already merged into the current branch
git branch --no-merged                        # branches with unmerged work
git log --oneline --graph --all               # see the result

๐Ÿงน After Merging

git push                              # publish the merged main
git branch -d feature/login-tests     # delete the merged branch locally
git push origin --delete feature/login-tests

๐Ÿงญ Merge vs Rebase (Preview)

Merging preserves history exactly as it happened and is always safe for shared branches. Rebasing rewrites a branch so it looks as if it started from the latest main, giving a linear history. The full comparison is in git rebase and rebase vs merge.


๐Ÿ“ Assignment

  1. Create feature/a from main, make two commits, switch to main and merge. Confirm it was a fast-forward.
  2. Create feature/b, commit on it, then commit something different on main. Merge feature/b and inspect the merge commit with git log --oneline --graph.
  3. Repeat with --no-ff on a branch that could fast-forward and compare the graphs.
  4. Merge a branch with three commits using --squash and commit the result with one message.
  5. Use git branch --merged to find branches you can safely delete, and delete them.

โ“ FAQ

๐Ÿค” How do I merge a branch into main?

Switch to main (git switch main), update it (git pull), then run git merge branch-name and push.

๐Ÿค” What is a fast-forward merge?

A merge where the target branch has no new commits, so Git just moves its pointer forward to the branch tip without creating a merge commit.

๐Ÿค” What does git merge –no-ff do?

It always creates a merge commit, even when a fast-forward is possible, so the feature branch remains visible in history.

๐Ÿค” How do I cancel a merge?

If the merge stopped with conflicts, run git merge --abort. If it already completed and was not pushed, git reset --hard HEAD~1 removes it; if pushed, use git revert -m 1 <merge-commit>.

๐Ÿค” What is the difference between merge and squash merge?

A normal merge keeps every commit from the branch. A squash merge combines them into a single new commit on the target branch.


๐ŸŽฏ Next Steps

๐ŸŽฌ Learn Git and GitHub step by step: watch the series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

1 thought on “git merge Explained: Fast-Forward, Three-Way, –no-ff and Squash Merges”

Leave a Comment