git merge takes commits from another branch and attaches them to the
current one. It is the fundamental operation for collaborative work.
Two scenarios
Fast-forward
If the current branch has no new commits that are absent from the branch being merged, Git simply advances the current branch's pointer to the tip of the other branch. No new commit is created; history stays linear.
before: main: A → B
feat: A → B → C → D
after: main: A → B → C → D (main caught up with feat)
feat: A → B → C → D
This happens when you run git merge feat from main and main has
received no new commits since the branch point.
Three-way merge
When both branches have their own commits since the fork, Git creates a merge commit, a special commit with two parents.
before: main: A → B → E
feat: A → B → C → D
after: main: A → B → E → M (M is the merge commit)
\ /
C → D
feat: A → B → C → D
The content of the merge commit is the combination of the trees at E and D against their common ancestor B. If changed lines do not overlap, Git handles it automatically. If they do, there is a conflict.
Commands
git switch main
git merge feature # merge feature into main
git merge --no-ff feature # create a merge commit even if fast-forward is possible
git merge --ff-only feature # refuse if fast-forward is not possible
git merge --squash feature # collapse all feature commits into one staged change
git merge --abort # cancel a merge in progress
The --no-ff flag is a common team strategy for preserving topology:
"there was a feature branch here." Without --no-ff, feature commits
blend into the main line and the fact of branching disappears visually.
Conflicts
When a conflict occurs, Git marks the file with special markers:
<<<<<<< HEAD
print("from main")=======
print("from feature")>>>>>>> feature
What to do:
- Open the file in an editor or mergetool.
- Remove the markers and leave the version you want (or a combination).
git add <file>to mark it resolved.git committo finish the merge (Git suggests a ready-made message).
Useful commands during a conflict:
git status # shows which files are in conflict
git diff # view three versions in the conflict hunks
git checkout --ours file # accept the current branch's version entirely
git checkout --theirs file # accept the incoming branch's version entirely
Pitfalls
--squashcreates a commit without recording the source branch as a parent. This means the merged branch is still considered unmerged and cannot be deleted withbranch -d. You must usebranch -D. This often surprises people.- If you change your mind during a merge,
git merge --abortrestores everything to the state before the merge started. git mergewith unstaged changes in the working tree may refuse to proceed if those changes overlap with the merge. Commit or stash first.