git merge Command
git merge is the command that combines the changes from another branch into the current branch. It produces either a fast-forward update or a true merge commit, depending on whether the branches have diverged. It can also abort halfway through if conflicts arise.
The basic invocation
Merge another branch into the current one
# Switch to the destination git switch main # Merge the source branch in git merge feature-x
Important: git merge feature-x reads as “merge feature-x into the current branch.” The current branch is the destination; the named branch is the source.
What Git does internally
Finds the common ancestor of the two branches.
If the current branch is an ancestor of the target → fast-forward.
Otherwise → three-way merge: compute the changes each branch made since the ancestor, combine them.
If both sides changed the same lines → conflict.
Common flags
--no-ff— always create a merge commit, even if fast-forward would work. Many teams use this for clean history.--ff-only— refuse to merge unless fast-forward is possible. Useful forgit pull --ff-onlyin linear-history teams.--squash— squash all the source commits into a single commit on the destination (no merge commit, no history of the branch).-m "message"— supply the merge-commit message inline.--no-commit— perform the merge but stop before committing, so you can inspect/tweak.--abort— abandon a merge in progress, restoring the pre-merge state.--continue— finish a merge after you resolved conflicts.
Fast-forward merge
When the target has not moved
git merge feature-x # Updating c204c1d..1f9ab2c # Fast-forward # src/login.js | 5 +++-- # 1 file changed, 3 insertions(+), 2 deletions(-)
No merge commit was created — main simply moved forward to match feature-x. The graph is linear.
Three-way merge (with merge commit)
When both branches have new commits
git merge feature-x # Merge made by the 'recursive' strategy. # src/login.js | 5 +++-- # src/header.js | 2 ++ # 2 files changed, 5 insertions(+), 2 deletions(-)
Git opens your editor with a default merge commit message (“Merge branch 'feature-x' into main”). You can accept it or edit it.
Force a merge commit (--no-ff)
git merge --no-ff feature-x # Always creates a merge commit, even if FF would have worked
Useful when you want history to clearly show that there was a feature branch — e.g., in Gitflow.
Refuse non-fast-forward (--ff-only)
git merge --ff-only feature-x # fatal: Not possible to fast-forward, aborting.
Useful for keeping a strictly linear history. If FF isn’t possible, you’re forced to rebase first.
Squash merge
git merge --squash feature-x # Squash all of feature-x's commits into one staged blob git commit -m "Add feature-x" # Now main has one new commit; feature-x's individual history is gone
Note: squash does not record the source branch in history. See the “Squash Merge” page.
Merging multiple branches at once
Octopus merge
git merge branch-a branch-b branch-c # An "octopus" merge — creates one commit with multiple parents # Works only if there are no conflicts
Octopus merges are rare and only useful when the branches truly don’t touch each other.
Inspecting before committing
Stop just short of committing
git merge --no-commit --no-ff feature-x # Merge in progress; review with: git diff --cached # Then either: git commit # finalise git merge --abort # undo
Aborting a merge
Bail out if things go wrong
git merge --abort # Restores your working tree to the state before the merge began
Reading the result
git log --oneline --graph --all -10 # * c1d2e3f (HEAD -> main) Merge branch 'feature-x' # |\ # | * b1a2c3d (feature-x) Wire search to API # | * 9f8e7d6 Add search component # * | 8d7c6b5 Update README # |/ # * 7e6d5c4 Earlier work
Merge branch 'feature-x' into main. That is fine, but a richer message that explains *what* the feature does is more useful in the long run.git log main..feature-x --oneline to preview which commits are about to be merged in. Surprise commits are the cause of most merge headaches.