How to Merge Two Branches in Git: A Complete Guide

Merging branches is one of the most common — and most misunderstood — operations in Git. Whether you're combining a finished feature into your main codebase or pulling in updates from a teammate's work, understanding how Git handles merges puts you in control of your project history.

What Does "Merging" Actually Mean in Git?

When you merge two branches, Git combines the changes from both into a single branch. Think of branches as parallel timelines of your project. Merging brings those timelines back together.

Git doesn't just paste one branch's changes on top of another. It looks at three points: the common ancestor (where the two branches originally diverged), the tip of the first branch, and the tip of the second. This is called a three-way merge, and it's how Git figures out what changed, what's new, and what might conflict.

The Basic Merge Command

To merge one branch into another, the core process is:

  1. Switch to the branch you want to merge into — typically main or develop
  2. Run the merge command pointing at the branch you want to bring in
git checkout main git merge feature-branch 

That's it for the basic operation. Git will attempt to combine the histories automatically.

Two Types of Merges Git Can Perform

Not every merge works the same way under the hood.

Fast-Forward Merge

If the branch you're merging into hasn't changed since the feature branch was created, Git can simply move the pointer forward. No new commit is created — Git just "fast-forwards" the timeline.

This produces a clean, linear history, which looks tidy but hides the fact that a separate branch ever existed.

Three-Way Merge (Merge Commit)

If both branches have new commits since they diverged, Git creates a merge commit — a special commit with two parent commits. This preserves the full branching history.

You can force a merge commit even when fast-forward is possible using:

git merge --no-ff feature-branch 

Many teams prefer this because it makes the branching structure explicit in the log.

Merge TypeWhen It HappensCreates New CommitPreserves Branch History
Fast-ForwardNo new commits on target branchNoNo
Three-WayBoth branches have divergedYesYes
--no-ffForced, any situationYesYes

What Happens When There's a Conflict 🔀

A merge conflict occurs when both branches changed the same part of the same file in different ways. Git can't decide which version to keep, so it pauses and marks the problem in the file itself.

You'll see something like:

<<<<<<< HEAD This is the version from main ======= This is the version from feature-branch >>>>>>> feature-branch 

To resolve it:

  1. Open the conflicted file(s)
  2. Decide which version to keep — or write a combined version
  3. Remove the conflict markers (<<<<<<<, =======, >>>>>>>)
  4. Stage the resolved files: git add filename
  5. Complete the merge: git commit

Git will pre-populate a merge commit message, or you can write your own.

Alternative: Rebasing Instead of Merging

Rebasing is an alternative to merging that rewrites history rather than creating a merge commit. Instead of combining histories, it replays the commits from one branch on top of another.

git checkout feature-branch git rebase main 

This gives you a linear history without merge commits — but it changes commit hashes, which can cause problems if others are working on the same branch. The general rule: rebase local, unpublished work; merge shared branches.

Before You Merge: A Few Things Worth Checking

Merging isn't inherently risky, but going in without context can create unnecessary headaches.

  • Pull the latest changes on both branches before merging, so you're not working with stale code
  • Review the diff between branches using git diff main..feature-branch to understand what's about to come in
  • Check for open work on the feature branch — unfinished changes or debug code left behind
  • Know your team's branching strategy — whether your project uses Git Flow, trunk-based development, or something else shapes when and how merges should happen

How Workflow Affects the Right Merge Approach

The "correct" way to merge isn't universal — it depends heavily on how your project is organized and who's working on it.

A solo developer on a small project might prefer fast-forward merges for a clean, minimal history. A team using pull requests will usually generate merge commits automatically through their platform (GitHub, GitLab, Bitbucket), sometimes with squash options to compress multiple commits into one. An open source project might have strict conventions about rebasing before merging to maintain a readable log.

Squash merging is a third path some teams use — it takes all the commits from a branch and combines them into a single commit before merging. This produces clean history but loses the granular commit-by-commit record of how a feature was built.

git merge --squash feature-branch git commit 

Each approach makes a different trade-off between history clarity, granularity, and simplicity.

Your History Tells a Story 📖

Every merge decision shapes what your project's Git log looks like months or years from now. A dense tangle of merge commits can be hard to read; an aggressively rebased or squashed history can obscure why decisions were made.

The mechanics of merging are consistent across setups — but how those mechanics interact with your team size, your branching conventions, your deployment process, and your tolerance for history complexity is where the real decisions live. Understanding the tools is the first step; figuring out which approach fits your specific project is where the actual thinking begins.