Technology git merge explained

Learn with diagrams, code, systems and practical examples.

</>
Git command reference · Reviewed 2026-08-16

git merge: decide which branch receives the history before you combine it

Learn git merge through commit-graph reasoning, fast-forward behavior, merge commits, conflict recovery, and safe collaboration scenarios.

01Inspect

Identify the current branch, the branch being integrated, and whether the histories are linear or divergent.

02Predict

Decide whether Git can fast-forward or must create a two-parent merge commit.

03Run

Merge in the correct direction and choose --ff-only, --no-ff, or normal behavior only for a stated history reason.

04Verify

Inspect the resulting graph and test the combined behavior; a clean merge is not proof the application is correct.

Understand

Start with the mental model

Merge integrates another line of Git history into the branch you currently have checked out. Unlike rebase, it normally preserves the existing commit identities and the fact that independent branch histories existed.

Predict before reading on

Main points to C. feature/login started at C and added D → E. Main has not moved since the branch was created. If you switch to main and run git merge feature/login, must Git create a new merge commit?

Reveal the reasoning

No. Because main is still an ancestor of feature/login, Git can fast-forward main directly to E. There is no divergent history to reconcile, so a two-parent merge commit is unnecessary unless you explicitly request one with --no-ff.

Safety principle

Merge updates the branch you currently have checked out. Before running it, say the direction out loud: “I want branch X to receive branch Y.” Then switch to X and merge Y.

Inspect

Before you run it

  • Run git status and confirm the branch that should receive the other line of work is the current branch.
  • Inspect git log --graph --oneline --decorate --all and decide whether the result should be a fast-forward or a true integration commit.
  • Fetch first when you intend to merge a remote-tracking branch so the target reflects the remote state you actually inspected.
  • Decide whether preserving branch topology has project value; do not use --no-ff or --squash as unexplained style preferences.
Prerequisite knowledge
  • Know that the branch you currently have checked out is the branch Git will move or update during the merge.
  • Understand that commits form a graph through parent links, and two branches can point to different tips in that graph.
  • Be comfortable checking repository state with git status and inspecting history with git log.
Reference

Options and the decision behind them

--ff-only

Allow the merge only when the current branch can move directly to the target without creating a merge commit.

Use it when: Automation or protected workflows where an unexpected divergent history should fail instead of being merged implicitly.
--no-ff

Create a merge commit even when Git could fast-forward.

Use it when: When preserving the existence and integration point of a feature or release branch is intentionally valuable to the project history.
--squash

Apply the combined changes from the other branch to the working tree and index without creating the branch topology as a merge commit.

Use it when: When you deliberately want one new commit containing the net change and do not need the source branch commits connected into the current history.
--abort

Stop a conflicted merge and try to restore the state from before the merge began.

Use it when: When the conflict set is unexpected, the wrong branch was selected, or you need to reconsider the integration plan.
Apply

Worked examples

Example 1Beginner: merge a completed feature into main

Situation: Your feature/login branch is complete and tested. You want to integrate it into local main while preserving the existing feature commits.

git switch main
git merge feature/login

The important first step is switching to the branch that should receive the work. Git then compares the two branch tips. If main has not advanced since the feature branched, Git may fast-forward; if both histories diverged, a normal merge usually creates a new commit with two parents.

Typical output:

Updating <old>..<new>
Fast-forward
… or a merge commit message when histories have diverged.
Example 2Practical: update a shared feature branch from main without rewriting teammates’ commits

Situation: Several developers have already pulled feature/payments. Main has moved forward, and the team wants the feature branch to include those changes without replacing published commit IDs.

git switch feature/payments
git fetch origin
git merge origin/main

Fetching first updates the remote-tracking main reference. Merging origin/main into the shared feature branch preserves the commits everyone already has while recording the point where the newer main history was integrated.

Example 3Advanced: require a true fast-forward in automation

Situation: A deployment branch is expected to be strictly behind main. If the histories diverged, you want the job to fail so a human can inspect why.

git switch deployment
git fetch origin
git merge --ff-only origin/main

With --ff-only, Git refuses to invent an integration commit. Success proves the deployment branch tip was an ancestor of origin/main and could simply move forward. A failure is useful evidence that the branch history no longer matches the workflow assumption.

Typical output:

Fast-forward on success; fatal: Not possible to fast-forward, aborting. when the histories diverged.
Troubleshoot

When merge pauses, protect the integrated behavior—not one side of the conflict

A merge conflict means Git cannot automatically combine the two branch tips. “Ours” and “theirs” describe graph positions, not which business behavior is correct.

  1. Confirm the receiving branch

    Check repository state first so you know which branch is being updated and which paths are unresolved.

    git status
  2. Inspect both sides

    Read the conflict in context and compare each branch’s intent before choosing or combining changes.

    git diff --ours
    git diff --theirs
  3. Build the intended combined result

    Edit the files so both valid behaviors survive where appropriate, then run focused tests rather than merely deleting conflict markers.

  4. Stage and complete

    Stage resolved files and complete the merge only after the integrated behavior is verified.

    git add <resolved-files>
    git commit
  5. Abort when the direction or plan was wrong

    If you merged from the wrong branch or the conflict set reveals a bad integration plan, return to the pre-merge state.

    git merge --abort
Avoid

Common mistakes and why they fail

Merging while checked out on the wrong branch

git merge updates the current branch. If you intended to put feature work into main but are still on the feature branch, the direction of integration is reversed.

Safer response: Before merging, run git status or inspect the prompt and state the goal in words: “I want branch X to receive branch Y.” Switch to X, then merge Y.

Assuming every merge creates a merge commit

When the current tip is an ancestor of the target, Git can fast-forward by moving the branch pointer. No new commit is required because there is no divergent history to reconcile.

Safer response: Inspect git log --graph --oneline --decorate before merging. Use --no-ff only when preserving an explicit integration point is a deliberate project choice.

Resolving a textual conflict by picking one side wholesale

Conflict markers identify overlapping edits, not which side is correct. “Ours” and “theirs” are repository positions, not business-intent labels.

Safer response: Read the surrounding code, understand both changes, create the intended combined result, stage it, run focused tests, then complete the merge.

Using --squash without understanding the history trade-off

A squash merge copies the net changes into the index but does not connect the source branch commits as parents of the resulting commit. The content can be correct while the graph tells a different story.

Safer response: Choose squash because the project wants a single integration commit, not merely because the graph looks shorter. Use normal merge when branch ancestry is useful history.

Practice

Guided practice

A shared feature branch already contains commits your teammates pulled. origin/main has advanced. You want the feature branch to include the new main work without replacing the published feature commit IDs. What sequence fits that collaboration constraint?

Hint

Update the remote-tracking reference first, then integrate the remote main line into the shared feature branch without rewriting existing feature commits.

Tutor answer
git switch feature/payments
git fetch origin
git merge origin/main

The feature branch is the receiver, and a normal merge preserves the commit identities teammates already have. If the histories diverged, Git records the integration point instead of replaying published feature commits.

Independent practice

Create a disposable repository where one branch can fast-forward and another has truly diverged. Predict the graph before each merge, run the operations, compare fast-forward versus merge-commit results, then deliberately create one conflict and practice both resolving it and aborting it.

Working set

Related commands to keep nearby

git statusgit log --graph --oneline --decorategit fetchgit diffgit rebase

Keep the working set small enough that each command has a clear job: inspect state, update remote knowledge, compare changes, integrate history, or recover from mistakes.

Clarify

Frequently asked questions

What is a fast-forward merge?

If the current branch tip is already an ancestor of the branch being merged, Git does not need to combine divergent lines. It can simply move the current branch pointer forward to the newer commit.

When should I use --no-ff?

Use it when the project deliberately wants an explicit merge commit to preserve the fact that a feature, release, or other branch was integrated as a unit. Do not use it automatically if the extra topology provides no value.

Is merge safer than rebase?

For already-shared history, merge is often safer because it normally preserves existing commit IDs. That does not make every merge correct: you still need to choose the right direction, resolve conflicts deliberately, and test the integrated result.

How do I cancel a merge conflict?

If the merge is still in progress and you have not intentionally completed it, git merge --abort is the normal escape route. Inspect git status first so you understand the current state, especially if you had unrelated uncommitted work before merging.

Next step

Practice merge direction, fast-forward prediction, and conflict recovery together.

A reliable merge workflow is less about memorizing flags and more about knowing which branch should move, whether the graph is already linear, what topology you want to preserve, and how you will verify the combined behavior.

Explore command references