Back to Git: Branching, Merge, Rebase
Q6Question 6 of 6

The difference between git merge, git rebase, and git cherry-pick, and when to use each

Key Concepts
  • `git merge` creates a merge commit with two parents, preserving the true history of parallel development.
  • `git rebase` replays commits onto another branch tip as new commits, producing a clean linear history but rewriting commit hashes.
  • `git cherry-pick` copies one or more specific commits by hash to the current branch without bringing the rest of the source branch.
  • Never rebase commits that have been pushed to a shared branch and pulled by others, because it rewrites shared history and causes divergence.
  • Use merge on shared branches for safety, rebase on private branches for cleanliness, and cherry-pick for targeted hotfix transplants or backports.
  • Interactive rebase (`git rebase -i`) lets you squash, reorder, edit, or drop commits before replaying, which is ideal for cleaning up a feature branch before review.
  • A common team policy is to rebase locally for clean history and then merge to shared branches with `--no-ff` so shared history is never rewritten.

Definition

Merge joins branches with a merge commit preserving true history, rebase replays commits for a linear history but rewrites them, and cherry-pick copies specific individual commits – use merge on shared branches, rebase on private ones, cherry-pick to transplant a single fix.
  • git merge – Combines two branches by creating a merge commit that has both branch tips as parents, preserving the honest record of parallel development.
  • git rebase – Replays the commits of one branch onto the tip of another, creating new commits with new hashes to produce a straight, linear history as if the work was done sequentially.
  • git cherry-pick – Copies one or more specific commits by their hash from any branch and applies them as new commits on the current branch, without bringing the rest of the source branch.
  • Safety rule – Merge is non-destructive and safe on shared branches; rebase rewrites history and must only be used on local or private branches; cherry-pick is additive on the target but creates duplicate commits.
  • Team policy – Many teams adopt "rebase locally, merge to shared branches" to get linear readability with shared-branch safety.

At the National Bank of India, merge is like stapling two teams' separate logbooks together with a cover note saying "these two streams of work joined here" – the true, honest record of parallel effort is preserved. Rebase is like one team rewriting their logbook so it reads as if their work was done neatly after the other team's, producing one clean straight story – tidier to read, but it is a rewritten record, so you only do it before anyone else has copied it. Cherry-pick is like taking one single important page out of one logbook – say the fix that corrected Rajesh's fee calculation – and copying just that page into another logbook, without bringing the whole book.

Understanding the Concepts

What is git merge?

git merge integrates one branch into another by creating a new merge commit whose parents point to both branch tips. This records the fact that development happened in parallel and then came together. Merge never changes existing commits; it only adds the merge commit. A special case is a fast-forward merge: if the target branch has not moved since the feature branched, Git simply moves the pointer forward without a merge commit. Teams often force a merge commit with --no-ff to keep a visible record of each feature.

BASH
# Rajesh merges his fee-fix branch into main at National Bank of India
git checkout main
git pull origin main
git merge --no-ff feature/fee-fix-rajesh
# Creates a merge commit: "Merge branch 'feature/fee-fix-rajesh' into main"
git push origin main
TEXT
# History after merge (non-linear, true record)
*   M  Merge branch 'feature/fee-fix-rajesh' into main
|\\
| * C3 Fix fee rounding for Priya's account
| * C2 Add BigDecimal for fee calculation
* | C1 Update transfer limit
|/
* C0 Initial commit

What is git rebase?

git rebase takes the commits unique to your branch and replays them one by one onto the tip of another branch, creating new commits with new hashes but the same changes. The result is a straight, linear history with no merge commits. Interactive rebase (git rebase -i) additionally lets you reorder, squash, edit, or drop commits, which is excellent for cleaning up a messy feature branch into logical commits before review.

BASH
# Rajesh rebases his private branch onto the latest main
git checkout feature/loan-calculator
git rebase main
# Commits C2 and C3 are replayed as C2' and C3' on top of main's tip
# If conflicts occur, resolve each one, then:
git add .
git rebase --continue
TEXT
# History after rebase (linear, clean)
* C3' Add EMI edge case handling
* C2' Implement loan calculator service
* C1  Update transfer limit (from main)
* C0  Initial commit

What is git cherry-pick?

git cherry-pick copies one or more specific commits by their hash and applies their changes as brand-new commits on your current branch. It does not bring along the rest of the source branch's history. This is surgical: you reach into one branch, take exactly the commit you want, and apply it elsewhere.

BASH
# A fee-rounding hotfix was made on the release branch
# Rajesh needs just that one fix on main, not the whole release branch
git checkout main
git cherry-pick abc1234
# Applies commit abc1234 as a new commit on main
git push origin main
TEXT
# The commit abc1234 becomes a new commit def5678 on main
# Same changes, different hash, no connection to the release branch

How does each command work internally?

Merge performs a three-way merge between the common ancestor, the current branch tip, and the target branch tip, then creates a merge commit with two parents. If there are no conflicting changes, Git completes automatically; if there are conflicts, it pauses and marks the conflicting files for manual resolution.

Rebase identifies the commits unique to your branch (those after the fork point), temporarily saves them as patches, resets your branch to the target tip, and then applies each patch sequentially as a new commit. Each new commit gets a new hash because its parent has changed. If a patch conflicts, rebase pauses at that commit for resolution before continuing.

Cherry-pick takes the diff introduced by the specified commit and applies it to the current HEAD as a new commit. It does not consider the commit's ancestry or the rest of its branch. If the diff conflicts with the current state, Git pauses for resolution.

BASH
# Viewing the internal difference
# Merge: two parents visible in the commit
git log --graph --oneline main
# Shows merge commits with two parent lines

# Rebase: linear history, no merge commits
git log --graph --oneline feature/loan-calculator
# Shows a straight line of commits

# Cherry-pick: new commit with different hash
git log --oneline main
# Shows the cherry-picked commit with a new hash

How is merge different from rebase? (comparison table)

| Aspect | git merge | git rebase |
|---|---|---|
| History shape | Non-linear, branches and merge commits visible | Linear, as if work was sequential |
| Existing commits | Never changed; only adds a merge commit | Rewrites commits with new hashes |
| Shared branches | Safe to use on any branch | Must not use on shared branches |
| Conflict resolution | All conflicts resolved in one merge commit | Conflicts resolved commit by commit |
| Rollback | Revert the merge commit | Harder; must find the original branch point |
| Readability | Can be noisy with many branches | Clean, easy to follow |
| Information preserved | Full parallel development record | Parallel work hidden; looks sequential |

BASH
# MERGE: safe on shared branches
git checkout main
git merge --no-ff feature/transfer-service
# Result: merge commit preserving both histories

# REBASE: only on private branches
git checkout feature/transfer-service
git rebase main
# Result: linear history, commits rewritten
# Then merge to main (fast-forward possible)
git checkout main
git merge feature/transfer-service

When should you use each?

Use merge to integrate a completed feature into a shared branch while preserving the honest record. Merge is the default safe choice for anything others depend on. It is also the right choice when you want to see exactly when and where work converged.

Use rebase to keep a private feature branch up to date with main and to tidy its commits into a clean, linear story before merging. Rebase is a tool for your own local branches. A common workflow is: rebase your feature onto the latest main, resolve conflicts incrementally, then merge to main with --no-ff.

Use cherry-pick when you need a specific change somewhere without the rest of its branch. The classic case is a hotfix made on a release branch that you also need on main, or backporting a single bug fix to an older supported version.

BASH
# Workflow at National Bank of India
# Step 1: Rajesh keeps his feature branch current with rebase
git checkout feature/emi-calculator
git fetch origin
git rebase origin/main

# Step 2: Clean up commits with interactive rebase
git rebase -i HEAD~3
# Squash WIP commits into logical units

# Step 3: Merge to main with a merge commit
git checkout main
git merge --no-ff feature/emi-calculator
git push origin main

# Step 4: Cherry-pick a hotfix from release to main
git checkout main
git cherry-pick release/v2.1~2  # specific hotfix commit

What are common mistakes? (WRONG then CORRECT)

The most dangerous mistake is rebasing a branch that others have already pulled.

BASH
# WRONG: Rebasing a shared branch that others have pulled
git checkout main
git rebase feature/transfer-service
# This rewrites main's commits! Everyone else's main diverges.
# Result: chaos, merge conflicts for the entire team.
BASH
# CORRECT: Only rebase your own private branch onto main
git checkout feature/transfer-service   # your private branch
git rebase main                          # replay your commits onto main's tip
# Only your private commits are rewritten. main is untouched.

Another common mistake is using cherry-pick as a routine integration mechanism instead of merging.

BASH
# WRONG: Cherry-picking every commit instead of merging
git cherry-pick abc1234
git cherry-pick def5678
git cherry-pick ghi9012
# Creates duplicate commits. When branches merge later,
# Git sees the same changes twice and may produce conflicts.
BASH
# CORRECT: Use merge for integration, cherry-pick only for targeted fixes
git merge feature/transfer-service       # integrates all commits properly
# Cherry-pick only for isolated hotfixes or backports
git cherry-pick abc1234                  # just the one fee-fix commit

What happens with conflicts in each?

With merge, all conflicts are gathered into a single resolution step. You resolve all conflicting files, stage them, and complete the merge commit. This is simpler when there are many conflicts because you handle them all at once.

With rebase, conflicts may occur at each replayed commit, so you resolve them one commit at a time. This is more granular but can be tedious if multiple commits touch the same files. You can always abort with git rebase --abort to return to the state before rebasing.

With cherry-pick, conflicts are resolved for the single commit being applied. If the cherry-picked commit depends on prior commits that are not present on the target branch, the conflict may be complex.

BASH
# Resolving a rebase conflict step by step
git checkout feature/emi-calculator
git rebase main
# CONFLICT in src/main/java/com/bank/service/EMICalculator.java
# Resolve the file manually, then:
git add src/main/java/com/bank/service/EMICalculator.java
git rebase --continue
# If another commit conflicts, repeat. To abort entirely:
git rebase --abort

What about interactive rebase for cleaning up history?

Interactive rebase (git rebase -i) is the most powerful commit-editing tool in Git. It opens a list of commits and lets you reorder, squash (combine), fixup (combine without keeping the message), edit (pause to amend), or drop commits.

BASH
# Clean up the last 4 commits on Rajesh's feature branch
git rebase -i HEAD~4
TEXT
# The editor shows:
pick a1b2c3 Add EMI calculator skeleton
pick d4e5f6 WIP: fix tests
pick g7h8i9 WIP: more test fixes
pick j0k1l2 Add edge case for zero-interest loans

# Change to:
pick a1b2c3 Add EMI calculator skeleton
fixup d4e5f6 WIP: fix tests
fixup g7h8i9 WIP: more test fixes
pick j0k1l2 Add edge case for zero-interest loans

# Result: two clean, logical commits instead of four messy ones

This is essential before creating a pull request, because reviewers at National Bank of India want to see logical, meaningful commits, not a trail of WIP saves.

What are common interview follow-up questions?

  • "Can you rebase after a merge?" – Technically yes, but it rewrites the merge commit and can cause confusion. Avoid it on shared branches.
  • "What is git pull --rebase?" – It fetches and rebases your local commits on top of the remote instead of merging, keeping a linear local history.
  • "How do you undo a rebase?" – Use git reflog to find the commit before the rebase and git reset --hard to that point. Reflog is your safety net.
  • "What is git rerere?" – "Reuse Recorded Resolution" remembers how you resolved a conflict so Git can auto-resolve it if the same conflict appears again during rebase.
BASH
# Undo a rebase using reflog
git reflog
# Find the entry before the rebase, e.g., HEAD@{3}
git reset --hard HEAD@{3}
# Branch is back to its pre-rebase state

# Pull with rebase instead of merge
git pull --rebase origin main
# Equivalent to: git fetch origin && git rebase origin/main

Visual Overview

TEXT
Git Merge (non-linear, preserves parallel history)
==================================================

  main:    C0 --- C1 ----------- M (merge commit)
                   \             /
  feature:          C2 --- C3 --

  M has two parents: C1 and C3
  All original commits (C0, C1, C2, C3) keep their hashes.


Git Rebase (linear, rewrites commits)
=====================================

  Before rebase:
  main:    C0 --- C1
                   \
  feature:          C2 --- C3

  After rebase (feature onto main):
  main:    C0 --- C1
                    \
  feature:           C2' --- C3'  (new hashes!)

  C2 and C3 are abandoned; C2' and C3' are new commits.


Git Cherry-Pick (surgical, one commit copied)
=============================================

  release:  C0 --- C1 --- C2 (hotfix) --- C3

  main:     C0 --- C4 --- C5 --- C2' (cherry-picked)

  Only C2's changes are copied as C2' (new hash).
  C1 and C3 are NOT brought to main.

Key Takeaway

The three operations differ in how they reshape history. Git merge combines two branches by creating a merge commit with two parents, honestly recording that development happened in parallel and then came together. It never changes existing commits, making it non-destructive and safe on shared branches. The trade-off is a history graph with branches and merge commits that some find noisier to read.

Git rebase takes the commits unique to your branch and replays them onto another branch's tip as new commits with new hashes, producing a straight, linear history as though you started from the latest base. Interactive rebase lets you squash, reorder, and clean up commits before review. The crucial caveat is that rebase rewrites history, so you must never rebase commits that have been pushed to a shared branch and pulled by others, because everyone else's copy would diverge. Rebase is a tool for private branches only.

Git cherry-pick copies specific commits by their hash and applies them as new commits on the current branch, without bringing the rest of the source branch. It is surgical: you reach into one branch, take exactly the commit you want, and apply it elsewhere. The classic use case is transplanting a hotfix from a release branch to main, or backporting a single fix to an older version. In the banking system at National Bank of India, Rajesh would rebase his private EMI-calculator feature onto the latest main for a clean linear history, merge it into shared main with --no-ff so shared history is never rewritten, and cherry-pick just one fee-rounding hotfix from the release branch onto main rather than dragging the whole branch.

Remember one sentence: rebase private branches for clean history, merge to shared branches for safety, and cherry-pick only for targeted hotfixes or backports.

---

Share
Use ← → arrow keys to navigate