Skip to content
Tools

Git Rebase vs Merge: Compare the History in a Small Repository

Merge and rebase integrate changes but leave different histories. Observe original IDs, replayed commits and recovery in a disposable repository before choosing a workflow for a shared branch.

By Published

5 min readEditorial analysisUpdated
  • Git
  • Rebase
  • Merge
  • Version control
What to remember

Merge preserves existing commits and records integration when histories diverge. Rebase replays work on a new base and can create new commit IDs. Choose according to branch ownership and team policy.

Decide who relies on the current history

Rebasing your unpublished feature commits onto main can simplify review. For a branch others already use as a base, merging avoids making them reconcile rewritten commits. Check team integration policy before publishing a rewrite.

A merge is not always a merge commit. If the current tip is an ancestor of the incoming tip, Git can fast-forward the branch pointer. --no-ff requests a merge commit where a fast-forward would otherwise be possible. A linear-looking graph therefore does not prove that somebody ran rebase.

Choose by ownership and history requirements
SituationTypical choiceReason
Private feature workRebaseReview on current base
Shared feature branchMergePreserve published commits
Record integration boundaryMerge with --no-ffKeep a merge commit
Protected mainRepository policyFollow allowed workflow

Create the same divergence twice

Run this with Git supporting switch and init -b. It creates a temporary directory, sets repository-local demo identity and contacts no remote. Keep the directory for inspection. Separate files deliberately avoid content conflicts.

A is the base. B adds feature.txt on feature; C adds main.txt on main. Both demo branches start from B, comparing two treatments of identical work. In real projects, test after integration: conflict-free changes can still combine incompatible behavior.

DEMO_DIR=$(mktemp -d)
cd "$DEMO_DIR"
git init -b main
git config user.name "History Demo"
git config user.email "demo@example.invalid"
printf '%s\n' 'base' > base.txt
git add base.txt
git commit -m "A: base"
git switch -c feature
printf '%s\n' 'feature' > feature.txt
git add feature.txt
git commit -m "B: feature"
git switch main
printf '%s\n' 'main update' > main.txt
git add main.txt
git commit -m "C: main update"
git switch -c merge-demo feature
git merge --no-ff main -m "M: merge main into feature"
git log --graph --oneline --all
git switch -c rebase-demo feature
git rebase main
git log --graph --oneline main rebase-demo

Read parents, not just the order of log lines

On merge-demo, M has parents B and C. B's original ID remains reachable. The history records main's integration into the feature line. Both files appear in the working tree.

On rebase-demo, the replayed feature commit follows C. Call it B-prime: its parent is now C rather than A, so its ID changes even though this exercise keeps the same feature-file change. The original feature branch still points to B because rebasing rebase-demo moves only that branch. Compare git show feature with git show rebase-demo and inspect git rev-list --parents -n 1 on each result.

Resolve the actual operation in progress

In a real rebase, Git may stop while replaying each conflicting commit. Read git status, resolve the file, stage it and continue. --skip drops the current commit's replay; it is appropriate only when you intend that change to be omitted. Use --abort to return to the pre-rebase branch state while the operation is still in progress.

The commands below are alternatives, not a sequential script. Replace the placeholders. For merge conflicts, use git merge --continue or git merge --abort. Start with a clean worktree or saved changes; merge abort may not reconstruct unrelated uncommitted edits reliably.

git status
git add path/to/resolved-file
git rebase --continue
# To cancel an unfinished rebase instead:
git rebase --abort
# After a finished operation, inspect before creating a rescue branch:
git reflog show feature
OLD_TIP=replace-with-verified-commit
git branch rescue-feature "$OLD_TIP"

Preserve a lost tip before changing anything else

After completion, --abort no longer applies. Find the relevant branch's earlier tip in reflog, verify its contents, then create a rescue branch there before resetting anything. In this exercise, inspect rebase-demo's reflog rather than feature's.

Reflogs are local reference histories, not a permanent remote backup. Entries and unreachable objects can expire, and another clone may not have your history. A named backup branch before a substantial rewrite is easier to identify later. Avoid copying a reset --hard command from a tutorial before protecting current uncommitted work.

Treat publishing rewritten history as a separate decision

A rebased branch may be rejected by a normal push because the remote tip is not an ancestor of the new tip. That rejection is useful information. Confirm branch ownership and team agreement before replacing published history. Rebasing a private branch does not authorize rewriting main or someone else's branch.

When an agreed rewrite is necessary, an explicit --force-with-lease=<ref>:<expected-commit> checks that the remote still has the verified tip you intend to replace. It does not make the rewrite harmless to collaborators. The shorthand relies on remote-tracking state and can lose protection when background fetches update it. Use your team's reviewed publication procedure and verify the final branch afterward.

Quick answers

Frequently asked questions

Does rebase change the code?

It replays selected changes onto another base. The combined code includes that base, and conflict resolutions can alter the replay. In the simple example the feature diff stays the same, but its parent and commit ID change.

Does merge always create an extra commit?

No. A possible fast-forward moves a branch pointer. A merge commit is created for diverged histories or when the chosen options require one.

Can I undo a completed rebase with --abort?

No. Abort applies to an operation still in progress. After completion, inspect reflog, verify the old tip and create a rescue branch before deciding how to restore history.

Is force-with-lease safe for a shared branch?

It checks a condition before updating a remote ref. It still rewrites published history and requires agreement. An explicit expected tip avoids relying solely on remote-tracking refs that background fetches can update.

Source notes

References and review policy

Information checked on October 4, 2026. Section links identify sources for factual claims and technical explanations. Interpretations, practice scenarios and preparation recommendations are RecallDeck’s editorial work.

From reading to recall

Practice the full interview loop.

RecallDeck schedules the concepts you miss and keeps coding, design, and behavioral fundamentals available when the interviewer changes direction.

Start studying

Keep going