A merge commit in Git is a special commit that joins two or more branches by combining their histories, created automatically when you run git merge and a fast-forward isn’t possible. It records the merged result and preserves the exact parent commits, so you can trace exactly which changes came from which branch. This article explains how merge commits work, when to use them, common problems, and how they compare to other integration methods.
What Exactly Is a Merge Commit?
A merge commit is a commit with two or more parents (usually two). Normal commits have one parent, pointing to the previous commit. A merge commit has multiple parents, each pointing to the tip of a branch that was merged. This structure is what makes Git’s history a directed acyclic graph (DAG) rather than a simple line.
When you run git merge <branch>, Git looks at the current branch and the branch you’re merging. If the current branch has not diverged from the target (i.e., the target is ahead of your current branch), Git performs a fast-forward: it simply moves your branch pointer forward, and no merge commit is created. But if the branches have diverged (each has commits the other doesn’t), Git creates a merge commit that combines the two histories.
How a Merge Commit Is Created
The merge process works like this:
- Git finds the common ancestor (the merge base) of the two branches.
- It compares the changes from that base to each branch tip.
- It combines the changes. If changes don’t conflict, it automatically stages the result.
- It creates a new commit with two parents: the current branch tip and the merged branch tip.
If there are conflicting changes (e.g., both branches edited the same line differently), Git pauses the merge and marks the files as conflicted. You then manually resolve the conflicts, stage the resolved files, and run git commit to complete the merge commit.
Example: Suppose you have a main branch and a feature branch. Both have new commits since they diverged. Running git checkout main then git merge feature will create a merge commit with parents main and feature. The commit message defaults to “Merge branch ‘feature'” but you can edit it.
Why Use Merge Commits?
Merge commits are valuable because they preserve the true history of what happened. They show exactly when a branch was integrated, and the branch’s individual commits remain intact. This is useful for:
- Keeping a record of feature branches – you can see which commits were part of a feature and when it was merged.
- Collaborative workflows – multiple developers can work on long-lived branches and merge them periodically without rewriting history.
- Auditing – the merge commit provides a clear point to revert if the merge needs to be undone.
However, merge commits can clutter the history with many “Merge branch” entries, especially in busy repositories. That’s why some teams prefer rebasing or squashing (see below).
Merge Commit vs. Fast-Forward vs. Rebase
When you merge, you can choose between a merge commit and a fast-forward. By default, git merge will fast-forward if possible. To force a merge commit even when a fast-forward is possible, use git merge --no-ff. This is common when you want to keep a record of the feature branch, even if it could have been a simple fast-forward.
Rebasing is an alternative: git rebase <branch> takes the commits from your current branch and replays them on top of the target branch, creating a linear history with no merge commits. The downside is that it rewrites commit hashes, which can cause problems if the commits have been shared with others.
Squashing (e.g., git merge --squash) combines all the changes from a branch into a single commit on the target branch, discarding the individual commit history. This is useful for cleaning up messy feature branches, but it loses the granular history.
Common Problems and How to Solve Them
Merge commits can cause confusion, especially for beginners. Here are common issues:
- Merge conflicts – When both branches modify the same lines, Git can’t auto-merge. You must manually edit the conflicted files, remove the conflict markers (
<<<<<<<,=======,>>>>>>>), then stage and commit. - Merge commit with no changes – If you merge a branch that has no new commits, Git will say “Already up to date.” No merge commit is created.
- Accidental merge commits – If you pull with default settings and your local branch has diverged, Git may create a merge commit automatically. To avoid this, use
git pull --rebaseto replay your local commits on top of the remote branch instead. - Reverting a merge commit – To undo a merge, use
git revert -m 1 <merge-commit-hash>. The-m 1tells Git to revert to the first parent (the branch you were on when you merged). A simplegit revertwithout-mwill fail because Git doesn’t know which parent to keep.
How to Choose: Merge Commit vs. Rebase vs. Squash
The choice depends on your team’s workflow and the importance of history clarity.
- Use merge commits when you want a complete, accurate history of how branches were integrated, and when you’re working on long-lived feature branches that others may also be using.
- Use rebase when you want a clean, linear history and you haven’t shared your branch with others. It’s great for keeping a feature branch up to date with
mainbefore merging. - Use squash when you want to condense a messy branch into one commit, often for a pull request that should be merged as a single unit.
Many teams adopt a policy: rebase to update your feature branch, then merge with --no-ff to create a merge commit that marks the feature’s integration. This gives a linear-looking history with clear merge points.
Frequently Asked Questions
Does every merge create a merge commit?
No. If Git can fast-forward (i.e., the current branch is behind the target and has no unique commits), it simply moves the branch pointer forward without creating a merge commit. To force a merge commit, use git merge --no-ff.
How do I see the parents of a merge commit?
Use git show --pretty=raw <commit-hash> to see the parent hashes. Alternatively, git log --graph shows the branching structure visually.
Can I undo a merge commit?
Yes, but with caution. Use git revert -m 1 <merge-commit> to create a new commit that undoes the merge, keeping the history intact. If you haven’t pushed, you could also reset with git reset --hard HEAD~1, but that discards the merge and its changes.
Why does my pull create a merge commit?
Because your local branch has diverged from the remote branch. Git pulls the remote changes and merges them with your local commits, creating a merge commit. To avoid this, use git pull --rebase to replay your local commits on top of the remote changes.
What is the difference between a merge commit and a regular commit?
A regular commit has one parent, representing a linear progression. A merge commit has two or more parents, representing the joining of two or more lines of development. That’s the only structural difference; merge commits also typically have a default message like “Merge branch ‘feature'” but you can change it.
Is a merge commit the same as a pull request merge?
Not necessarily. A pull request (PR) merge on platforms like GitHub can be configured to create a merge commit, squash, or rebase. The PR itself is a request to merge, but the actual merge can be done in different ways depending on the repository settings.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Jenkins vs GitHub Actions: Which CI/CD Fits Your Team?
- Turn Off Backup Encryption in iTunes?
- Campus Tech Innovation Hubs: What They Are
- Poco C51 Airtel Prepaid Locked Variant India?
- Shared VPS Hosting: Is It Better?
- Disk Defrag Pro: What It Does and Whether You Need It