git merge takes the commits from one branch and puts them into the branch you have checked out. Git either slides the branch pointer forward or records a new commit with two parents.
Only the target branch changes. The source keeps its tip, its commits and its name.
Most people reach for it to bring a feature branch back into main. Git picks the outcome on its own. If the branches haven’t diverged, it fast-forwards, and if both have new commits, it does a three-way merge.
One version note. Since Git 2.33.0 (August 2021), the manual lists ort as the default strategy for merging a single branch, replacing recursive.
What Does git merge Do?

The Git manual (version 2.54, April 2026) describes the command as joining two or more development histories together. Git looks at what the named branch changed since the histories split and applies those changes to the current one.
The syntax is git merge <branch>, run after you check out the branch that should receive the changes.
- The checked-out branch gets the new commits and its tip moves.
- The branch you name is left alone.
- HEAD, the index and the working tree update to the merged result.
- ORIG\_HEAD stores the old tip of the target branch before the merge starts, which matters later if you need to undo things.
Both sides are ordinary branches. A branch in Git is a movable pointer to a commit, so a merge can change the target without ever touching the source.
The manual’s own example makes this easy to picture. master holds D, E, F and G, and topic adds A, B and C on top of E.
Running git merge topic on master replays A, B and C onto G and records commit H, whose parents are G and C.
If every named commit is already an ancestor of HEAD, Git exits early with “Already up to date.” Nothing moves.
git pull runs the same operation under the hood to fold remote changes into a local branch. The command never deletes the source branch, so cleanup is a separate job.
Fast-Forward or Merge Commit: How Git Decides

Git fast-forwards when the current branch tip is a direct ancestor of the branch being merged. Anything else gets a merge commit.
What decides it is divergence. If the target hasn’t picked up commits of its own since the source split off, there’s nothing to reconcile, so Git just moves the pointer.
| Outcome | Trigger | History result |
|---|---|---|
| Fast-forward (default) | Target tip is an ancestor of the source tip | Pointer moves, no new commit |
| Merge commit (default) | Both branches have unique commits | New commit with two parents |
| –no-ff | Fast-forward possible, record wanted | Merge commit created anyway |
| –ff-only | Fast-forward possible | Pointer moves, otherwise Git refuses and exits non-zero |
| –squash | Any merge | Working tree and index updated, no commit, HEAD stays put |
Can a fast-forward merge cause a conflict?
No. Conflicts only show up in three-way merges, since a fast-forward has nothing to reconcile (Atlassian Git tutorial).
One side effect trips people up. --no-commit can’t stop a fast-forward, because there’s no merge commit to hold back.
If you want to inspect a merge without letting the branch move, pass --no-ff together with --no-commit. The Git manual recommends exactly that.
Why use –no-ff to keep a feature visible?
A fast-forward leaves a straight line, so the history no longer shows that a feature branch ever existed. --no-ff forces a merge commit, and that commit marks the integration point in the graph that git log can draw.
Setting merge.ff to false behaves like always passing –no-ff, and setting it to only behaves like –ff-only. Merging an annotated tag always creates a merge commit, even when a fast-forward would have worked.
To skip that merge commit when syncing to a release tag, pass --ff-only or unwrap the tag with v1.2.3^0, per the Git manual.
How the Three-Way Merge Builds the Result
A three-way merge compares the tips of both branches against their merge base, which is the latest common ancestor.
Pro Git describes it the same way, as two branch snapshots plus the common ancestor. Git writes the outcome as a new snapshot and creates a merge commit that points to it.
The merge base is the reference point both sides get measured against. HEAD is whatever the current branch holds right now, and MERGE\_HEAD is the named branch’s tip while a merge is paused.
Where only one side changed a region relative to the base, Git takes that side. Where both sides changed the same region, the merge stops with a conflict.
The merge commit lists both tips as parents. That’s how Git records that two lines of work joined, and it’s why the graph shows a diamond.
Only the two tips and the base are compared, never individual commits. A change made on both branches and later reverted on one of them still appears in the result, because the algorithm reads the revert as no change at all (Git merge-strategies documentation).
Which merge strategy does Git pick?

Without a -s option, Git uses ort when merging one branch and octopus when merging more than one.
- ort has been the default since Git 2.33.0 (released 2021-08-16). It handles renames, and the name stands for Ostensibly Recursive’s Twin.
- recursive was the default from v0.99.9k until 2.33.0 and is now a synonym for ort (redirected in v2.50.0).
- octopus handles more than two heads, and it refuses any merge that needs manual resolution.
- ours accepts any number of heads but keeps the current branch’s tree and throws away every change from the others. That’s different from the -Xours option.
- resolve takes two heads only and uses the three-way algorithm, with no rename handling.
The manual says ort’s approach has been reported to produce fewer conflicts without mismerges in tests on real merge commits from Linux 2.6 kernel history.
Speed is a separate gain. After GitHub moved its merge commits to merge-ort in 2022, complex merges that took 5 or more seconds finished in under 200 milliseconds (GitHub Changelog, 2022).
How to Run git merge Step by Step

Check out the branch that should receive the changes, then run git merge with the name of the branch to bring in. For a normal local or remote merge, the sequence is short.
- Commit or stash pending work, then run
git status. A merge stops when uncommitted changes overlap files it must update. - Switch to the target branch, for example
git switch main. - For a remote branch, run
git fetch originso the latest commits exist locally. - Run
git merge feature-branch(orgit merge origin/feature-branch). Git opens an editor for the merge message unless you pass--no-edit. - Check the result with
git log --oneline --graph. A fast-forward shows a straight line, a merge commit shows two lines joining.
Step two causes most of the mistakes, because the command merges into whatever happens to be checked out. Make a habit of switching to the target branch and confirming with git status before typing the merge.
The fetch in step three matters for a similar reason. Without a fresh git fetch, origin/feature-branch points at whatever you last downloaded.
To preview before committing, run git merge --no-commit --no-ff feature-branch. Git performs the merge and stops before creating the commit, and git merge --abort restores the pre-merge state.
Commit or stash first, though. The manual warns that --abort can’t always rebuild uncommitted changes. --autostash exists for dirty worktrees, but it can produce its own conflicts when the stash is reapplied.
Sources: Git manual (git-scm.com, version 2.54), Git merge-strategies documentation (git-scm.com), Pro Git book (git-scm.com), Atlassian Git tutorials, GitHub Changelog (2022-09-12).
What Happens When a Merge Conflict Stops git merge?

Both branches changed the same area of a file, so Git pauses the merge, writes conflict markers into the working tree, and waits for you to finish the job.
While the merge waits, HEAD stays put and MERGE\_HEAD points at the source branch tip. Paths that merged cleanly are already updated in the index and the working tree.
For each conflicting path, the index keeps up to three versions. Stage 1 holds the merge base version. Stage 2 is the HEAD version, and stage 3 comes from MERGE\_HEAD.
git ls-files -u lists those stages, and git show :1:filename prints one of them.
The file itself holds the three-way result between <<<<<<<, ======= and >>>>>>>. Text above the middle line is typically your side, text below is theirs.
The default style hides the original text. Setting merge.conflictStyle to diff3 or zdiff3 adds a ||||||| section with the base version, though diff3 produces larger conflict regions than the default (Git manual).
Finishing the merge goes like this.
- Run
git statusto list the unmerged paths. - Edit each file into its final shape and delete the marker lines.
- Stage each fixed file with
git add. - Run
git merge --continue(orgit commit) to create the merge commit. The first form checks that a merge is actually in progress.
To see what’s going on, use git diff, which shows a three-way diff against HEAD and MERGE\_HEAD. git diff AUTO_MERGE shows what you have changed so far, and the AUTO\_MERGE ref only exists under the ort strategy.
To see each side’s commits for one path, run git log --merge -p <path>. If you’d rather use a visual editor, git mergetool launches one, and the built-in merge.tool values include vscode, meld, kdiff3 and p4merge.
When the hunks pile up, a longer walkthrough on resolving merge conflicts in Git is worth keeping open in another tab.
How to Undo or Abort a git merge
While the merge is unfinished, use git merge --abort. After a local merge commit, use git reset, and once the merge is pushed, use git revert -m 1. Which one fits depends on whether anyone else can see the merge commit.
| Method | Stage | History effect | Safe on shared branch |
|---|---|---|---|
| git merge –abort | Merge paused | None, merge discarded | Yes, nothing published |
| git reset –hard ORIG\_HEAD | Local merge commit, unpushed | Branch pointer moves back | No |
| git revert -m 1 <hash> | After push | New commit reverses the merge | Yes |
When MERGE\_HEAD exists, git merge --abort equals git reset --merge. They only differ when an autostash entry is involved. Abort reapplies it to the worktree, while reset –merge saves it to the stash list (Git manual).
Need to walk away from a paused merge without touching any files? git merge --quit forgets the merge and leaves the index and working tree as they are.
git reset moves the branch pointer back, and since ORIG\_HEAD holds the pre-merge tip, git reset --hard ORIG_HEAD undoes a local merge.
Run it right away. Other commands that change ORIG\_HEAD, git reset among them, overwrite it, and –hard discards uncommitted changes.
On a pushed branch, rewriting history hurts everyone who already pulled. git revert adds a new commit instead. A merge needs -m 1 because Git can’t tell which side is the mainline, and parent 1 is normally the branch you merged into.
Reverting a merge declares that you never want the tree changes it brought in. A later merge of the same branch then only brings commits that aren’t ancestors of the reverted merge (git-revert manual).
To bring the branch back after fixing it, rebase it with --no-ff so it carries fresh commits, instead of reverting the reversion. The git-rebase manual describes this approach.
git merge Compared With git rebase and git pull

Merge suits shared or long-running branches, and rebase suits private branches before they get integrated. The split comes down to one question. Has anyone else built on these commits?
git merge or git rebase: which fits the branch?
Both bring one branch’s work into another. What differs is what happens to the commits along the way.
Merge rewrites nothing, so it stays safe once others have pulled the branch. Conflicts get resolved once, inside a single merge commit, and the real branch topology stays visible in the graph. The cost is an extra merge commit on every integration, and a busy branch produces a non-linear log that’s harder to scan.
Rebase gives you a straight series of commits on top of the latest base, and you can reorder, edit or squash commits interactively before sharing them. The downsides are bigger.
- Commits A, B and C become A’, B’ and C’ with new IDs (git-rebase manual).
- Conflicts stop the rebase commit by commit, and ours and theirs swap sides.
- Merge commits are dropped unless –rebase-merges is passed.
- Rewriting a branch that others built on forces everyone downstream to repair their history.
- Anyone who already pulled the old commits ends up with duplicates unless they clean up.
Before rebasing anything shared, read up on what git rebase does to a branch.
My own rule is simple. A shared or published branch gets merged. A private branch where you want a straight line gets rebased and then fast-forward merged. A long-running feature that should stay visible gets a merge with –no-ff.
GitHub wraps the same outcomes. Its default Merge pull request option uses –no-ff, while Rebase and merge always creates new commit SHAs and updates committer information (GitHub Docs).
What does git pull have to do with git merge?
Sources disagree on the default. Many tutorials describe git pull as a fetch followed by a merge, but the git-pull manual (version 2.55, 29 June 2026) says it only fast-forwards when no reconciliation method is configured, and fails if the local branch has diverged.
Because git pull bundles a fetch with the integration step, divergence is where that default matters most.
Merge enters through --no-rebase or pull.rebase set to false, and --squash runs git merge --squash. List two remote refs on the command line and pull creates an octopus merge.
The manual’s own equivalence: git pull origin next gives the same result as git fetch origin followed by git merge origin/next.
Where git merge Falls Short
It’s a poor fit when you need a linear history, when a branch lives for weeks, or when the files can’t be merged line by line. It also reports success on merges that are textually clean but wrong.
Rename detection has a ceiling. Git examines up to 7000 files in the exhaustive rename pass when neither merge.renameLimit nor diff.renameLimit is set (Git manual), and a large refactor can blow past that.
Binary files get no line merge at all. The -X ours option takes the whole file from the target side, and custom merge drivers are declared per path pattern in .gitattributes. Branches with different end-of-line rules or clean filters need the renormalize option or merge.renormalize.
A clean merge is not proof of a correct one. The manual lists diff-algorithm values (histogram, patience, minimal, myers) as a way to avoid mismerges caused by unimportant matching lines such as braces, and ort defaults to histogram.
Run the test suite after every non-trivial merge, not only after conflicts.
Squash merges add their own trap. GitHub Docs recommends against squash and merge when you plan to keep working on the same head branch, since a squash commit records no merge relationship and the next integration starts from the old base.
Long-lived branches magnify every limit above, because each week of divergence adds changes that both sides touched. Teams that practice trunk-based development avoid most of this by merging small, short-lived branches back into one main line.
Sources: Git manual pages for git-merge, git-pull, git-rebase and git-revert (git-scm.com, versions 2.54 and 2.55), GitHub Docs (pull request merges and merge methods).
git merge FAQ
Does git merge delete the source branch?
No. The source branch stays exactly where it was. Remove it afterwards with git branch -d, which refuses to delete a branch that isn’t fully merged, or use git branch -D to force the deletion.
Can you merge just one commit instead of a whole branch?
Not with a branch merge. git merge accepts a commit hash, but it brings that commit plus every ancestor your branch lacks.
To take a single commit, run git cherry-pick with the hash. Git replays it on your branch as a new commit.
Why does git merge say “refusing to merge unrelated histories”?
The two histories share no common ancestor, so Git has no merge base to compare against. The --allow-unrelated-histories option overrides the check.
The manual calls this a rare case, such as joining two projects that started independently, and provides no config setting to enable it by default.
Should you merge main into a feature branch?
Yes, when the feature branch is shared or already pushed. Check out the feature branch and run git merge main, so any conflicts get settled there instead of at the final integration.
On a private branch, rebasing onto main is the alternative.
Is it safe to run git merge on a shared branch?
Yes. A merge adds commits and rewrites none, so teammates’ clones stay valid.
The catch comes at push time. If the remote branch moved in the meantime, Git rejects the push until you integrate the new commits.
Choosing a Merge Setup for Your Main Branch

On a main branch, –no-ff for feature branches and –ff-only for pulls works best. Each feature lands as one merge commit, and each pull either fast-forwards or stops.
That setup has a payoff the individual options don’t show. A –no-ff merge commit can be reversed with git revert -m 1 in a single step, while a fast-forward leaves no merge commit to revert.
The price is a busier log, since every feature adds one merge commit.
In practice that means setting pull.ff to only, merging features with –no-ff, and reverting failed features with -m 1.
A written Git workflow records these rules for the whole team. Position verified against the git-pull manual (version 2.55, June 2026, unchanged in 2.56); recheck the pull defaults after each major release.
- VS Code Extensions That Are Actually Worth Installing - October 13, 2026
- Google Play App Signing Explained - October 11, 2026
- 5 Best NinjaOne Alternatives for Focused Endpoint Management - October 10, 2026



