skip to content

Rebase and History Rewriting

You will learn to rewrite history deliberately: squash, reorder and edit commits with interactive rebase, move work with rebase --onto and cherry-pick, and scrub secrets with git-filter-repo. Interviewers pair it with the consequences — force-push etiquette on shared branches and reflog as the way back.

part ofGitoverview, primer and where to startread it →
on this pageshow

questions

page 1 of 2

In Git, what does git cherry-pick do to the commit you name?

level: juniorimportance: must knowfreq 70%

answer

  1. it copies a change, it does not move it
  2. the source branch is untouched
  3. the result is a brand new object
  4. parent and committer differ from the original
  5. think targeted backport, not merge

basics

~20 s

It applies that commit's change on top of your current branch and creates a new commit for it. The original commit stays where it is; the copy has a different SHA because its parent, committer and timestamp differ.

solid answer

~40 s

`git cherry-pick <commit>` takes the **diff** that commit introduced relative to its parent, applies it to your current `HEAD`, and commits the result — reusing the original message and author, but recording you as committer with a new timestamp and a new parent. That gives a **new commit with a different SHA**; nothing moves, and the source branch is untouched. It can conflict like any other application of a patch, and then you resolve, `git add`, and run `git cherry-pick --continue` (or `--abort` / `--skip`). You can pick several commits at once by listing them or by giving a range such as `A..B`, which picks everything after `A` up to `B`. The typical use is a targeted backport: one bug fix from the main branch onto a release branch, without dragging along everything else.

code

console · 5 lines
console
$ git switch release-1.4
$ git cherry-pick 9f2a1c3
[release-1.4 7c31af0] fix null deref in session lookup
 Date: Mon Aug 10 09:12:44 2026 +0200
 1 file changed, 3 insertions(+), 1 deletion(-)

go deeper

for a junior

Be able to say cherry-pick copies one commit's change onto your current branch as a new commit, and that the original branch is unchanged.

for a middle

Explain which metadata carries over and which does not, why the SHA changes, and how ranges, -n and the conflict flow work.

for a senior

Show judgment about backports: when a fix should be picked versus merged, what a conflicting pick tells you about divergence, and how duplicates play out later.

for a principal

Own the maintenance-branch policy — what is eligible for backport, who decides, and how the team avoids a web of hand-copied fixes across release lines.

## What it does A commit records a full snapshot, but Git can compute the **change** it introduced by diffing it against its parent. `git cherry-pick <commit>` computes that change and applies it to your current branch, then commits. The copy is a genuinely new commit object. It keeps the original **author** and author date and reuses the message, but its parent is your current `HEAD`, its committer is you, and its committer date is now. Since a commit's SHA hashes all of that, the SHA is different. Two commits with the same message and the same diff sitting on different branches is exactly what a cherry-pick looks like in the log. The source branch is not modified at all — nothing is moved or deleted. Cherry-pick copies. ## Everyday form git switch release-1.4 git cherry-pick 9f2a1c3 Useful variations: - **Several commits**: `git cherry-pick A B C` applies them in the order given. - **A range**: `git cherry-pick A..B` applies every commit after `A` through `B`. The left end is exclusive; `A^..B` includes `A`. - **`-n` / `--no-commit`**: apply the change to the working tree and index but do **not** commit, so you can adjust it or combine several picks into one commit. You commit yourself afterwards. - **`-e` / `--edit`**: open the message for editing. - **`-s` / `--signoff`**: add a `Signed-off-by` trailer. - **`-x`**: record the source commit id in the message of the copy. ## Conflicts A cherry-pick is an application of a change onto a different base, so it can conflict — especially when the surrounding code has diverged. Git stops with conflict markers in the tree, records `CHERRY_PICK_HEAD`, and waits. You resolve, `git add` the files, and run `git cherry-pick --continue`. `--abort` restores the branch to where it was; `--skip` drops the current commit and moves on to the next in a multi-commit pick; `--quit` leaves the tree as-is but clears the in-progress state. During a multi-commit pick the remaining plan lives in `.git/sequencer`. A conflict is also a signal worth reading: if a fix does not apply cleanly to a release branch, the code it fixes may have changed enough that the fix is not the right one there. ## When to reach for it - **Backporting** a bug fix from the main line to a maintenance or release branch. - **Rescuing** a commit made on the wrong branch: pick it onto the right branch, then remove it from the wrong one. - **Extracting** one useful commit from an abandoned branch. ## When not to Cherry-pick is a scalpel. Picking dozens of commits one at a time is a sign you actually wanted to merge or rebase the branch: those tools track what has already been integrated, while repeated cherry-picks leave you managing duplicates by hand. The long-term consequence of copying is **duplicate commits**: the same change exists twice, with two SHAs. If the source branch is later merged into the target, Git's three-way merge usually copes because both sides made the same textual change, but the history now contains two commits for one logical fix, and a partially cherry-picked branch can produce confusing conflicts. Git does have tooling for spotting such duplicates by comparing patch identity rather than SHA. ## Common misconceptions - "It moves the commit" — no, the original stays put. - "The SHA is the same" — it cannot be, because the parent changed. - "It brings the whole branch" — it brings exactly the changes of the commits you name. - "A merge commit can be picked like any other" — a merge has two parents, so Git cannot tell which diff you mean unless you say, with `-m`.

  • Why does the cherry-picked commit have a different SHA from the original?
    A commit's SHA hashes its tree, message, author and committer identity and timestamps, and its parent. The copy has a different parent — your branch tip — and a fresh committer line, so the hash differs even when the diff and message are identical. Cherry-pick copies changes; it never relocates a commit object.
  • What does git cherry-pick -n do, and when is it useful?
    `-n` (`--no-commit`) applies the change to the working tree and index but stops short of committing. It lets you adjust the change before recording it, or apply several picks and commit them once as a single logical change. You commit yourself afterwards, which also means you write the message.
  • How do you cherry-pick a range of commits rather than one?
    Give a range: `git cherry-pick A..B` applies every commit after `A` up to and including `B`, in order. Use `A^..B` when you want `A` itself included. Each one becomes its own new commit, and a conflict pauses the sequence so you can resolve, then `--continue`, `--skip` or `--abort`.

It is photocopying one page from one binder into another: the original page stays in place, and the copy is a distinct sheet with its own page number.

saying these in an interview costs you the question

  • Saying cherry-pick moves the commit off the source branch
  • Claiming the copied commit keeps the original SHA
  • Thinking cherry-pick brings the whole branch's history
  • Assuming a cherry-pick can never conflict
  • Reaching for dozens of picks where a merge or rebase was meant

context

open as a page

In Git, why is force-pushing to a shared branch dangerous?

level: juniorimportance: must knowfreq 70%

basics

~20 s

A forced push overwrites the remote branch pointer even when the new tip is not a descendant of the old one, so commits other people pushed can stop being reachable and everyone who already fetched the branch now has a history that diverges from it.

open as a page

In Git, what happens when you run git rebase -i HEAD~3?

level: juniorimportance: must knowfreq 78%

basics

~20 s

Git opens an editor holding a todo list of the three commits after HEAD~3, oldest first, each on a pick line. You edit the verbs and the order, save, and Git replays the commits as scripted, creating new commit IDs.

open as a page

In Git, what is the difference between merging main into your branch and rebasing onto it?

level: juniorimportance: must knowfreq 85%

basics

~20 s

Merging adds a new commit that joins both histories and leaves your existing commits untouched. Rebasing re-creates your commits on top of main's tip as new commits with new hashes, producing a straight line with no merge commit.

open as a page

In Git, why does deleting a file and committing not remove it from history?

level: juniorimportance: must knowfreq 55%

basics

~20 s

A Git commit only adds a new snapshot. Every earlier commit still references the blob holding that file, so the content stays reachable and clonable until history itself is rewritten and the old objects are pruned.

open as a page

How does git bisect run automate the search, and what do its exit codes mean?

level: middleimportance: must knowfreq 45%

basics

~20 s

git bisect run <cmd> runs your test at each step and answers for you: exit 0 means good, 1 to 127 except 125 means bad, 125 means untestable so the commit is skipped, and 128 or above aborts the bisect.

open as a page

In Git, how does git revert undo a change differently from git reset --hard?

level: middleimportance: must knowfreq 72%

basics

~20 s

git revert adds a new commit whose diff is the inverse of the target commit, leaving history intact and forward-only. git reset --hard moves the branch pointer backwards so the commits are no longer on the branch, rewriting what the branch contains.

open as a page

What does git push --force-with-lease do that git push --force does not?

level: middleimportance: must knowfreq 65%

basics

~20 s

It makes the forced update conditional: the push succeeds only if the remote branch still points where your remote-tracking ref says it does. If someone else pushed in between, the update is rejected instead of silently discarding their commits.

open as a page

In a Git interactive rebase todo list, how do squash and fixup differ?

level: middleimportance: must knowfreq 70%

basics

~20 s

Both fold a commit into the one on the line above it. Squash opens an editor with both commit messages so you can write a combined one; fixup keeps the earlier commit's message and throws the folded commit's message away, with no editor prompt.

open as a page

A git rebase stops on a conflict — what do --continue, --skip, and --abort each do?

level: middleimportance: must knowfreq 58%

basics

~20 s

After you stage a resolution, git rebase --continue records that commit and resumes the replay. git rebase --skip discards the commit being replayed entirely and moves on. git rebase --abort ends the whole operation and returns the branch to its pre-rebase tip.

open as a page

Why does git rebase give every replayed commit a new SHA even when the content is identical?

level: middleimportance: must knowfreq 65%

basics

~20 s

A commit's hash is computed over its whole content, which includes its parent, its message, and both author and committer identity and timestamp. Rebase re-creates each commit with a different parent and a fresh committer timestamp, so the hash must differ.

open as a page

How do you use git filter-repo to strip a path from every commit in a repo?

level: middleimportance: must knowfreq 50%

basics

~20 s

Run git filter-repo on a fresh clone with a path filter: git filter-repo --path secrets/ --invert-paths keeps everything except that path. It rewrites every commit, so all downstream SHAs change and the result must be force-pushed.

open as a page

Why does git revert require the -m option when reverting a merge commit?

level: seniorimportance: must knowfreq 45%

basics

~20 s

A merge commit has two parents, so "the change it introduced" is ambiguous — it differs depending on which parent you compare against. -m <parent-number> names the mainline parent to treat as the branch you kept, and Git undoes the change relative to that one.

open as a page

A teammate force-pushed the branch you were on — how do you recover your commits?

level: seniorimportance: must knowfreq 48%

basics

~20 s

Fetch, then find the branch's old upstream tip in your reflog and replay only your own commits onto the new tip with git rebase --onto. Never merge or pull, because that reconciles two parallel histories and drags the discarded commits back.

open as a page

A credential was committed to your Git repository months ago — what do you do?

level: seniorimportance: must knowfreq 55%

basics

~20 s

Treat the credential as compromised and invalidate it first — a history rewrite cannot un-leak it. Then purge it with git filter-repo --replace-text on a fresh clone, force-push every rewritten ref, and have everyone re-clone.

open as a page

In Git, how do you use git bisect to find the commit that introduced a bug?

level: juniorimportance: should knowfreq 50%

basics

~10 s

git bisect binary-searches history. Run git bisect start, mark a broken commit bad and an older working one good, test each commit Git checks out and answer good or bad, then git bisect reset.

open as a page

Why do small, individually buildable commits make git bisect far more useful?

level: middleimportance: should knowfreq 25%

basics

~20 s

Bisect's answer resolution is one commit. Small commits mean the first bad commit is a diff you can read; a huge squashed commit only tells you the bug is somewhere in a week of work, and unbuildable commits force skips.

open as a page

What does the -x option add when you run git cherry-pick?

level: middleimportance: should knowfreq 35%

basics

~20 s

git cherry-pick -x appends a line to the copied commit's message recording the id of the commit it came from, in the form (cherry picked from commit <sha>). It documents provenance; it changes nothing about the content applied.

open as a page

What does Git's rebase --autosquash option do to the todo list?

level: middleimportance: should knowfreq 42%

basics

~20 s

With --autosquash, git rebase -i scans commit subjects for the fixup! and squash! prefixes, moves each such commit directly below the commit it names, and pre-sets its todo verb to fixup or squash — so the plan arrives already arranged.

open as a page

How do you split one commit into two using Git interactive rebase?

level: middleimportance: should knowfreq 45%

basics

~20 s

Mark the commit edit in the git rebase -i todo list. When the rebase stops there, run git reset HEAD^ to undo the commit but keep its changes in the working tree, commit the pieces separately with git add -p, then run git rebase --continue.

open as a page

What does git rebase --onto main feature-a feature-b do, and when do you need it?

level: middleimportance: should knowfreq 45%

basics

~20 s

It replays the commits reachable from feature-b but not from feature-a onto main, then moves feature-b to the result. You need it when the commits you want to move and the base you want to cut them from are different things.

open as a page

Why is git filter-branch discouraged, and what does git filter-repo do better?

level: middleimportance: should knowfreq 38%

basics

~20 s

git filter-branch forks a shell per commit, so it is extremely slow, and its defaults are unsafe: it leaves refs/original backups, keeps empty commits, and ignores tags and other refs unless told otherwise. Git's own docs now point at git filter-repo.

open as a page

In Git, when should you use git bisect skip, and how does it change the result?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Use git bisect skip when a candidate commit cannot be judged, typically because it does not build. Git then tests a neighbour, and if only skipped commits remain it reports a set of possible first bad commits instead of one.

open as a page

After reverting a merge in Git, why does re-merging that branch restore nothing?

level: seniorimportance: should knowfreq 35%

basics

~20 s

The revert removed the content but left the merge commit in place, so the branch's commits are still ancestors. A second merge finds nothing new to bring in — Git decides what to merge from ancestry, not from what the files currently contain.

open as a page

How can git push --force-with-lease still overwrite a teammate's commits?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Its lease is checked against your remote-tracking ref, which any background fetch updates. If something fetched a teammate's push without you looking at it, the lease matches and the forced update discards their work. --force-if-includes closes that gap.

open as a page

In a Git interactive rebase, how do you run the test suite on every commit?

level: seniorimportance: should knowfreq 32%

basics

~20 s

Use git rebase -i --exec "make test" <base>. Git inserts an exec line after every commit in the todo list and runs that command as each commit is created; a non-zero exit stops the rebase at that commit so you can fix it and continue.

open as a page

What problem does git rebase --update-refs solve when you stack dependent branches?

level: seniorimportance: should knowfreq 25%

basics

~20 s

When branches point at intermediate commits in a stack, rebasing the top branch normally leaves those refs on the old, pre-rebase copies. The --update-refs option moves them to the corresponding replayed commits so the whole stack stays consistent.

open as a page

How do you find and purge large blobs bloating a Git repository's clone size?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Measure with git count-objects -vH, then list the biggest objects by piping git rev-list --objects --all through git cat-file --batch-check. Purge them with git filter-repo --strip-blobs-bigger-than or a path filter, then re-measure; every downstream SHA changes.

open as a page

How would you decide and enforce, in Git itself, which branches may be force-pushed?

level: principalimportance: should knowfreq 26%

basics

~20 s

Allow rewriting on short-lived branches with a single owner, forbid it on anything others build on or that is deployed from. Enforce it at the receiving repository — receive.denyNonFastForwards and a pre-receive hook — because client-side flags are only courtesy.

open as a page

In a Git repo, what are the real costs of requiring every branch to be rebased before landing?

level: principalimportance: should knowfreq 32%

basics

~20 s

A linear history buys readable logs and simpler bisecting, but every rebase copies commits: conflicts are re-resolved per commit and per rebase, shared branches need coordinated force-pushes, intermediate commits are combinations that were never tested, and old hashes recorded elsewhere stop resolving.

open as a page

showing 1–30 of 32