You've branched off, built an amazing feature, committed your work, and now you're ready to share it with the world. But there's a gap between your feature branch and the main codebase. How do you bridge it?
Merging is the moment of convergence. It's when the parallel universes of your branches come back together, combining different streams of work into a single, unified history. Done right, it's seamless. Done wrong... well, that's when conflicts happen (we'll cover those next).
The fundamental rule of merging
Before we look at the command, let's understand the mental model. Merging always happens into the branch you're currently on. Think of it as "pulling in" work from another branch.
# You're on main, pulling in feature-navbar
git checkout main
git merge feature-navbarThis says: "Take everything from feature-navbar and add it to main." The branch you specify (feature-navbar) stays exactly as it is. The branch you're on (main) gets updated.
This is the most common mistake beginners make, they try to merge from the wrong branch. Remember: checkout the destination, merge the source.
git merge feature-branch" without mentioning git pull origin main. If your teammate pushed changes to main while you were working, you're merging into an outdated version. Always pull before you merge: git checkout main && git pull origin main && git merge feature-branch.Two ways to merge: fast-forward vs merge commitWhat is commit?A permanent snapshot of your staged changes saved in Git's history, identified by a unique hash and accompanied by a message describing what changed.
Git has two different strategies for merging, and which one it chooses depends on the state of your branches.
Fast-forward mergeWhat is fast-forward merge?A Git merge where the branch pointer simply moves forward because there is no divergent history, resulting in no merge commit.: the simple path
Imagine you created feature-login from main, made two commits on your feature branch, and main hasn't changed at all in the meantime:
Before merge:
main: A---B
\
feature: C---DThere's a straight line from main to feature. Git can simply move the main pointer forward to catch up:
After fast-forward merge:
main: A---B---C---D
↑
feature: (same as main now)No new commit is created. Git just slides the main pointer forward. This is clean, simple, and preserves linear history.
Run this:
git checkout main
git merge feature-login
# Output: Updating a1b2c3d..e4f5g6h
# Fast-forwardThe "Fast-forward" message tells you exactly what happened.
Merge commit: when histories diverge
Now imagine a more realistic scenario. While you were working on feature-login, your teammate pushed changes to main:
Before merge:
main: A---B---E ← your teammate added commit E
\
feature: C---D ← you added commits C and DThe histories have diverged. Git can't simply move main forward because there's new work on main that isn't in your feature branch. Instead, Git creates a merge commit: a special commit that has two parents:
After merge commit:
main: A---B---E---F
\ / ← commit F has two parents (E and D)
feature: C---DCommit F is the merge commit. It combines the changes from both branches.
| Merge type | When it happens | New commit? | History shape |
|---|---|---|---|
| Fast-forward | Main hasn't changed | No | Linear |
| Merge commit | Both branches have new commits | Yes | Diamond/fork |
--no-ff merge | Forced by you | Yes | Always shows branch |
The complete merge workflow
In professional development, merging isn't just running git merge. It's a careful process designed to prevent disasters. Here's the full workflow:
Step 1: Verify your feature branch is ready
Before merging, make sure your feature branch is clean and complete:
git checkout feature-navbar
git status # Should show "nothing to commit, working tree clean"Step 2: Switch to main and update it
This is critical. You want to merge into the latest version of main, not an outdated one:
git checkout main
git pull origin main # Get any changes from remoteStep 3: Merge your feature branch
Now you're ready:
git merge feature-navbarStep 4: Verify and push
Check that the merge worked:
git log --oneline --graph
git push origin mainStep 5: Clean up
Your feature branch has served its purpose. Delete it:
git branch -d feature-navbar
git push origin --delete feature-navbarWhen to force a merge commitWhat is commit?A permanent snapshot of your staged changes saved in Git's history, identified by a unique hash and accompanied by a message describing what changed.
Sometimes you want a merge commit even when Git could do a fast-forward. Why? Documentation. A merge commit clearly shows in your history where a feature branch started and ended.
git merge --no-ff feature-navbarThe --no-ff flag means "no fast-forward." Even if Git could fast-forward, it creates a merge commit instead.
Fast-forward (hard to see what was a feature):
main: A---B---C---D---E---F
No fast-forward (clear feature boundaries):
main: A---B---E-------F
\ /
C---D---Many teams prefer --no-ff because it preserves the story of their development.
Checking what's been merged
Over time, you'll accumulate branches. Some are merged, some aren't. Git helps you figure out which is which:
# See branches that are already merged into your current branch
git branch --merged
# See branches that are NOT merged (don't delete these!)
git branch --no-merged| Command | Shows | Safe to delete? |
|---|---|---|
git branch --merged | Branches already merged | Yes, work is preserved |
git branch --no-merged | Branches with unmerged work | No, you'll lose work |
Aborting a merge
Sometimes you start a merge and realize you're not ready. Git lets you abort:
git merge --abortThis returns you to the state before the merge started. Use this when the merge conflicts are more complex than expected, or you forgot to pull main first.
Quick reference
| Command | What it does | When to use it |
|---|---|---|
git merge branch | Merge branch into current | Integrate finished work |
git merge --no-ff branch | Force merge commit | Preserve branch history |
git merge --abort | Cancel in-progress merge | Something went wrong |
git branch --merged | List merged branches | Find safe deletions |
git branch -d branch | Delete merged branch | Post-merge cleanup |
# Switch to main branch
git checkout main
# Merge feature branch into main
git merge feature-login
# Create a merge commit even if fast-forward is possible
git merge --no-ff feature-navbar
# See merged branches
git branch --merged