DevOpsInterviewPrep logo
← 🚀 Delivery & GitOps
Foundational

Git merge vs rebase: commit identity and shared history

Understand how merge preserves ancestry and rebase creates new commits. Follow a small Git graph, resolve a conflict safely and explain the risk of rewriting a shared branch.

TL;DR: A merge combines histories while retaining existing commits. A rebase replays changes onto a different base and usually creates new commits with new IDs. Rebase a private review branch when that improves review; coordinate before rewriting anything other people may have based work on.

A commit includes its ancestry

Suppose main advances from commit A to B while your feature adds X and Y from A. The branch names are pointers. The commits form a graph, and each ordinary commit records its parent along with its tree and metadata. Changing the parent changes the commit's identity.

A merge of main into the feature can create M with parents Y and B. X and Y retain their identities. A rebase onto B instead creates X-prime and Y-prime: new commits whose changes are replayed on B. The resulting files may be identical to a merge result, while the history remains different. The Git rebase manual explains the replay operation and how to continue or abort it.

rendering diagram…

The diagram shows two alternative outcomes from the same starting history. You would choose one outcome for the branch, rather than maintain both as a normal workflow.

What reviewers and collaborators experience

OperationGraph effectOperational consequence
Fast-forward mergeMoves a branch pointer to an existing descendantNo new merge commit is needed
Three-way mergeCan create a commit with two parentsExisting branch commits remain identifiable
RebaseReplays commits on a new basePreviously published commit IDs may be replaced
Squash mergeRecords the combined changes as a new commitIndividual source commits are absent from the destination's ancestry

Squash and rebase are different operations. A squash can make the main branch easier to scan, but a later merge from the original long-lived source branch may be confusing because its original commits were never recorded as ancestors. Short-lived branches avoid much of that problem by ending after integration.

A safe local rehearsal

Run this only in a new disposable directory. It creates a tiny repository with unrelated files so the rebase succeeds without conflict. The local identity is illustrative and applies only to this repository.

mkdir git-history-lab
cd git-history-lab
git init -b main
git config user.name 'History Lab'
git config user.email '[email protected]'
printf 'base\n' > app.txt
git add app.txt
git commit -m 'Create base'
git switch -c feature
printf 'feature\n' > feature.txt
git add feature.txt
git commit -m 'Add feature'
git rev-parse HEAD
git switch main
printf 'main change\n' > main.txt
git add main.txt
git commit -m 'Advance main'
git switch feature
git rebase main
git rev-parse HEAD
git log --oneline --graph --all

The two printed feature IDs differ because the replayed feature commit now has the new main commit as its parent. The file added by the feature still exists. This is why “same code” and “same commit” are different claims when investigating a build.

Resolve conflicts as a semantic decision

When both lines alter overlapping content, Git may stop for a conflict. Inspect git status, read both intended changes, edit the file to the required combined behavior and stage the result. Use git rebase --continue to resume. git rebase --abort restores the branch to its pre-rebase position.

A conflict-free replay can still be incorrect. One commit may rename a configuration option in a different file from the feature's new use of the old name. Run the relevant tests after integration. Treat automatic text merging as a mechanical aid, with behavior established separately.

During rebase, “ours” and “theirs” can be surprising because the operation applies your commits onto the upstream history. Inspect the actual versions before using a blanket conflict-resolution option. The merge documentation also distinguishes abort behavior and merge strategies; these command names are not interchangeable recovery instructions.

Why shared history changes the decision

If a teammate has built Z on Y, replacing Y with Y-prime leaves their branch based on the old history. They must now reconcile their work with the rewrite. That is the coordination cost behind the rule against casually rebasing shared branches.

If a published review branch must be rewritten, coordinate with its collaborators and check repository policy. A force push with an explicitly expected old remote commit can protect against overwriting an unexpected branch update. A generic --force removes that protection. Even --force-with-lease needs care when background fetches update tracking refs; it does not establish that every collaborator agreed to the rewrite.

Prefer a merge for a shared integration branch whose commits others already consume. Prefer a local rebase for a private short-lived branch when a linear review improves understanding. Neither choice makes the tests optional.

Check your explanation

A colleague says rebase is safer because it creates no merge conflicts. What would you correct?

Rebase can encounter conflicts as it replays each commit. It can also produce a clean textual result with incorrect behavior. Its useful property is the resulting history shape, paid for by new commit identities and potential coordination. For a shared branch, first determine who depends on the published commits.

Apply that reasoning to rebasing a shared branch, then connect the chosen commit to the artifact that moves through environments.

RELATED CONCEPTS
PRACTICE THIS IN REAL QUESTIONS