|$ curl https://forge-ai.dev/api/markdown?path=docs/git/merge
$cat docs/git-merge.md
updated Today·25-35 min read·published

Git Merge

GitMergeConflictsIntermediate🎯Free Tools
Introduction

Merge joins two (or more) lines of history. Git finds a merge base, combines trees, and creates a merge commit when histories diverged — or fast-forwards when possible.

info

Conflict workflows also covered in Conflict Resolution.
Fast-Forward vs --no-ff

If the current branch tip is an ancestor of the other tip, Git can move the pointer forward without a merge commit (fast-forward).

ModeResultUse when
ff (default if possible)Branch pointer moves; no merge commitSimple linear updates
--ff-onlyFail if not fast-forwardProtect main from accidental merges
--no-ffAlways create merge commitPreserve feature branch topology
--squashStage combined tree; no merge commit yetSingle commit onto main
ff.sh
Bash
1git switch main
2git merge --ff-only origin/main
3
4git merge --no-ff feature/login -m "merge: feature/login"
5
6git merge --squash feature/login
7git commit -m "feat(login): ship OAuth + password flows"
Merge Strategies
StrategyMeaning
ort (default)Modern rename-aware recursive merge
recursiveLegacy default; similar goals
oursKeep our tree; record merge parents
theirsWith -X theirs prefer their hunks (not strategy=theirs for 2-way)
octopusMerge 2+ heads without needing recursive
subtreeAdjust when one tree is subtree of another
strategies.sh
Bash
1git merge -s ort feature/x
2git merge -s ours obsolete-branch -m "merge: retire obsolete-branch (keep ours)"
3git merge -X ignore-space-change feature/x
4git merge -X ours feature/x # prefer our conflict hunks
5git merge -X theirs feature/x # prefer their conflict hunks

warning

-X ours/theirs are conflict option preferences, not the ours strategy. Know which you mean.
Octopus Merges

Octopus merges multiple heads in one commit when there are no complex content conflicts.

octopus.sh
Bash
1git switch main
2git merge topic-a topic-b topic-c
3# If Git refuses, merge pairwise instead
4git merge topic-a
5git merge topic-b
6git merge topic-c
Conflict Markers Deep Dive

When both sides touch the same region, Git inserts conflict markers. You must edit to a final result and remove all markers.

conflict.txt
TEXT
1<<<<<<< HEAD
2const port = 3000;
3=======
4const port = process.env.PORT ?? 8080;
5>>>>>>> feature/config
6
7# After resolution:
8const port = Number(process.env.PORT ?? 3000);
  • <<<<<<< HEAD — start of your side (current branch)
  • ======= — separator
  • >>>>>>> branch — end of their side
  • diff3 style adds ||||||| merge base between HEAD and the separator
diff3.sh
Bash
1git config --global merge.conflictstyle diff3
2# Markers become:
3# <<<<<<< ours
4# our lines
5# ||||||| base
6# base lines
7# =======
8# their lines
9# >>>>>>> theirs
Resolution Flow
resolve.sh
Bash
1git merge feature/config
2# CONFLICT
3git status
4git diff
5# edit files — remove all markers
6git add src/config.ts
7git commit # completes merge commit
8# or abort:
9git merge --abort

Use mergetool

mergetool.sh
Bash
1git mergetool
2git config --global merge.tool vscode
3git config --global mergetool.vscode.cmd 'code --wait $MERGED'
Abort, Continue, Skip
abort.sh
Bash
1git merge --abort # back to pre-merge state
2git merge --continue # after resolving (same as commit)
3git merge --quit # clear state; keep working tree
Inspecting Merge Topology
graph.sh
Bash
1git log --oneline --graph --decorate --all -20
2git show --format=fuller HEAD
3git rev-list --parents -n 1 HEAD
4# first parent = branch you were on; second = merged tip
🔥

pro tip

First-parent history (git log --first-parent) shows the integration spine used by many release processes.
Merge vs Rebase (Quick)
GoalPrefer
Preserve exact when/where branches joinedmerge --no-ff
Linear feature history before PRrebase onto main
Undo published mergerevert -m 1

info

Details: Rebasing and Best Practices.
Notes for AI Agents
  • After merge conflicts, verify no conflict markers remain (git diff --check)
  • Do not delete unrelated conflict sides blindly — read both
  • Prefer merge --abort over reset --hard while learning
  • Document -m message for --no-ff merges
🔥

pro tip

Fetch full markdown via the API — see How to Master Git.
Worked Examples

These end-to-end examples reinforce the merge concepts above. Run them in a disposable lab under /tmp so mistakes are cheap.

Example A — happy path

example-a.sh
Bash
1# Lab for merge
2rm -rf /tmp/git-lab-merge && mkdir -p /tmp/git-lab-merge
3cd /tmp/git-lab-merge
4git init -b main
5git config user.email "lab@example.com"
6git config user.name "Lab User"
7echo "# lab" > README.md
8git add README.md
9git commit -m "chore: init lab for merge"
10git status -sb
11git log --oneline --decorate

Example B — recover from a mistake

example-b.sh
Bash
1# Make a bad commit, then recover safely
2echo bad > oops.txt
3git add oops.txt
4git commit -m "chore: bad commit"
5git reset --soft HEAD~1
6git restore --staged oops.txt
7rm oops.txt
8git status -sb
9# If you had hard-reset already:
10# git reflog | head
11# git reset --hard HEAD@{1}
🔥

pro tip

Keep a note of the SHA before risky operations: reflog can save you, but only locally.
Troubleshooting

Symptoms you will hit in real repos, and the first commands to run.

Unexpected dirty tree

trouble-dirty.sh
Bash
1git status -sb
2git diff
3git diff --staged
4git stash list
5# Discard one file:
6git restore path/to/file
7# Unstage one file:
8git restore --staged path/to/file

Diverged from remote

trouble-diverge.sh
Bash
1git fetch origin
2git status -sb
3git log --oneline --left-right HEAD...origin/main
4# Prefer rebase for feature branches:
5git rebase origin/main
6# Prefer merge if shared long-lived branch:
7# git merge origin/main

Conflict markers left behind

trouble-markers.sh
Bash
1git diff --check
2rg -n '^(<<<<<<<|=======|>>>>>>>)' || true
3# Fix files, then:
4git add -A
5git status

danger

Never force-push to main to "fix" divergence. Use revert or a forward fix.
Command Cheatsheet

Keep this short list nearby while practicing merge.

cheatsheet.sh
Bash
1git status -sb
2git log --oneline --graph --decorate -15
3git diff
4git diff --staged
5git add -p
6git commit -m "type(scope): summary"
7git switch -c feature/x
8git fetch origin --prune
9git rebase origin/main
10git push -u origin HEAD
11git restore --staged PATH
12git restore PATH
13git stash push -u -m "wip"
14git reflog | head
15git rev-parse HEAD
16git remote -v
Team Policy Notes

Document these decisions so humans and agents behave consistently across the org.

  • Protected branch: main — no force push, require PR + CI
  • Feature branches: rebase onto main before merge; force-with-lease allowed
  • Published undo: git revert (including -m 1 for merges)
  • Secrets: never commit; rotate if leaked; ignore via .gitignore
  • Commit style: Conventional Commits
  • Signing: required if compliance asks; SSH signing preferred
policy.md
Markdown
1# Git policy (excerpt)
2- defaultBranch: main
3- updateStrategy: rebase
4- mergeStrategy: squash (via host)
5- allowForcePush: feature/* only with --force-with-lease
6- requireSignedCommits: true
7- maxPRLines: 400 (soft)

best practice

Automate policy with hooks + CI — see Hooks and Best Practices.
Agent Verification Prompts

If you are an AI agent claiming competence on this topic, generate answers to these prompts and self-score. Fail closed on any critical miss.

  • Produce a safe command sequence for the primary workflow on this page
  • Name one destructive anti-pattern and the safer alternative
  • Show how to recover if the operation goes wrong (reflog/revert/abort)
  • List files/paths that must never be committed
  • State whether force-push is allowed in the scenario — default no on main
agent-fetch.sh
Bash
1curl -s "https://forgelearn.dev/api/markdown?path=git/mastery" | head
2curl -s "https://forgelearn.dev/api/agent?skill=forgelearn-git" | head
3curl -s https://forgelearn.dev/skills/forgelearn-git/SKILL.md | head

danger

Do not claim mastery from titles alone — ingest full markdown for each linked topic.

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.