Cherry-Picking and Rebasing Basics

8 min read

Two commands that shape Git history more directly than the ones in earlier lessons: git cherry-pick lifts a single commit from one branch and applies it to another, and git rebase replays a sequence of commits onto a different base. Both are powerful, both rewrite history, and both have a "do not use on shared branches" warning attached. This lesson covers the safe, useful applications you'll actually need as a QA engineer — and the lines you should not cross until you have more Git mileage.

git cherry-pick — grab one specific commit

The mental model: walk up to a tree, pick one fruit, take it back to your tree. Cherry-pick takes the changes from one commit and applies them as a new commit on your current branch.

The basic form:

git cherry-pick abc1234
[main 7a92f1e] Fix flaky search test by waiting for network idle
 Date: Tue May 5 14:22:08 2026 +0530
 1 file changed, 3 insertions(+), 1 deletion(-)

Note the new commit hash (7a92f1e) is different from the original (abc1234). Cherry-pick doesn't move a commit — it copies its changes and creates a fresh commit with a new hash. The original stays put on its own branch.

When QA engineers reach for cherry-pick

  • Wrong-branch fix. You wrote a flake fix on main instead of on your feature branch. Cherry-pick the commit onto the feature branch, then git revert (or reset, if local) it on main.
  • Backporting one fix into a release branch. A bug fix lives on main, but the team also maintains release/v2.6 for an old customer. Cherry-pick just the fix onto the release branch — you don't want to merge all of main.
  • Hotfixing without merging the rest of a branch. Your feature/checkout-tests has 12 commits, only one of which is a flake fix everyone needs urgently. Cherry-pick that one onto main; the other 11 stay on the branch until the feature is ready.

Cherry-picking multiple commits

git cherry-pick abc1234 def5678 fed4321

Or a range (commits A through B inclusive, exclusive of A's predecessor):

git cherry-pick abc1234^..fed4321

If a cherry-pick hits a conflict, Git pauses just like a merge:

error: could not apply abc1234... Fix flaky search test
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run "git cherry-pick --continue".

Resolve the file the way you would a merge conflict (Chapter 2, Lesson 3), then:

git add <resolved-file>
git cherry-pick --continue

Or bail out:

git cherry-pick --abort

git rebase — replay your branch on top of another

Rebase answers a different question: "I've been working on a feature branch for two days, but main has moved on. How do I update my branch with the latest main, without a noisy merge commit?"

The rebase flow:

git switch feature/checkout-tests
git rebase main
First, rewinding head to replay your work on top of it...
Applying: Scaffold checkout test file
Applying: Add discount-code edge cases
Applying: Fix flaky timing on cart-update test

What happened internally:

  1. Git temporarily set your branch aside.
  2. It moved your branch's starting point to wherever main is now (the new "base").
  3. It replayed your commits one by one on top of that new base.

Each commit is re-created with a new hash — the original commits are gone, replaced by their rebased copies. Your branch now looks as if you'd started it from today's main, not yesterday's.

Rebase vs merge — same goal, different shape

Both bring the latest main into your feature branch. The difference is the resulting history:

  • Merge (git merge main) creates a merge commit combining both branches. History keeps a forked-and-rejoined shape. Honest but noisy.
  • Rebase (git rebase main) replays your commits on top of main. History is linear — your commits look as if they happened after main's. Cleaner, but rewritten.

Pick rebase when your team prefers a clean, linear history (most modern teams do, especially with squash-and-merge PRs). Pick merge when you'd rather not rewrite local commits, or when the team's workflow doesn't care about linearity.

merge vs rebase at a glance

Bringing main into your feature branch — two shapes of history

git merge main

  • Creates a merge commit

    Two parents — one from main, one from your branch

  • Original commits unchanged

    Same hashes, same authors, same timestamps

  • Forked-and-rejoined history shape

    Honest — shows that two lines existed in parallel

  • Safe on pushed branches

    No history rewrite; teammates' clones stay consistent

  • Pick when in doubt

    Especially if commits have already been pushed and reviewed

git rebase main

  • Replays your commits onto main

    Each commit is re-created with a NEW hash

  • Linear history

    As if your branch started from today's main, not yesterday's

  • No merge commit

    Cleaner log, especially in squash-and-merge teams

  • Rewrites history — DON'T rebase pushed/shared commits

    Force-push is needed; teammates' clones diverge

  • Pick when keeping history tidy matters

    And only on your own unshared branch

The golden rule of rebasing

Borrowed verbatim from the Git docs and never wrong:

Do not rebase commits that exist outside your repository and that people may have based work on.

Translated: if you've pushed commits to a branch and a teammate has pulled them, do not rebase. Rebasing rewrites those commits' hashes; their copies on your teammate's machine no longer match yours; your next push is rejected, their next pull creates duplicates, everyone loses time.

Safe rebase scenarios:

  • Your local feature branch, never pushed, you're polishing it before opening a PR.
  • A branch only you push to, with team agreement that you can rebase as part of your workflow.
  • After PR feedback, before merge, on a branch only you work on.

Unsafe scenarios:

  • A long-running branch shared with multiple developers.
  • main, develop, or any release branch.
  • Anything you've pushed and someone else has pulled.

Interactive rebase — a quick taste

git rebase -i HEAD~3 opens an editor with your last 3 commits and lets you squash, reorder, edit, or drop each one. The most common QA use: tidying up a feature branch before opening a PR.

git rebase -i HEAD~3
pick a8f2c91 WIP: scaffold search tests
pick 3a7b2c1 fix typo
pick 9b3d2f1 Add 5 search regression tests

Change pick to squash (or s) on commits 2 and 3 to fold them into commit 1:

pick a8f2c91 WIP: scaffold search tests
squash 3a7b2c1 fix typo
squash 9b3d2f1 Add 5 search regression tests

Save and close. Git asks you to write a unified commit message. Result: one clean commit, "Add 5 search regression tests," instead of three messy ones.

Don't go deep into interactive rebase yet. The takeaway: it exists, it's the tool when you want to clean up before a PR, and it falls under the same "local-only, never on shared branches" rule.

Day-to-day advice

For most QA engineers, the practical position is:

  • Cherry-pick is the more useful of the two — keep it in your toolkit for the wrong-branch and backport scenarios.
  • Rebase is powerful but easy to misuse. Until you're confident, use merge (git merge main from your feature branch) to bring main's changes in. The history is slightly less tidy; nothing is broken.
  • Once you've worked on a few teams and seen the workflows, you'll know when to introduce rebase — and you'll do it on your own branch, before a PR.

A real QA scenario — cherry-picking a flake fix

You're three days into feature/payment-gateway-tests. Yesterday you committed a one-line fix to a flaky search test — it has nothing to do with the feature work, but you happened to be on that branch. Your team needs the search-test fix on main today. The branch isn't ready to merge.

Find the commit:

git log --oneline -10
9b3d2f1 Add tests for declined-card flow
3a7b2c1 Scaffold payment-gateway tests
7a92f1e Fix flaky search test by waiting for network idle      ← the one you want
4c48901 Add cart fixture for discount-code edge cases

Switch to main, pull, cherry-pick:

git switch main
git pull
git cherry-pick 7a92f1e
git push

The fix is now on main. Your feature branch is unchanged. CI's flake rate just dropped — and your feature work is still in flight.

⚠️ Common mistakes

  • Rebasing a shared branch and force-pushing. The single most-cited cause of "we lost a day" stories on engineering teams. If others have pulled the branch, the rebase makes their commits orphans on their machines. Use merge instead, or rebase only branches you alone work on.
  • Cherry-picking the same commit twice without realising. If you cherry-pick a commit, then later merge the source branch, the same change can appear as two different commits in your history. Git is usually smart enough to detect this and skip the duplicate, but not always — review with git log --oneline after cross-cutting operations.
  • Resolving rebase conflicts by aborting and re-trying. Beginners who hit a rebase conflict sometimes panic---abort, edit the source file, and try again. The conflict will keep happening because the underlying changes still overlap. Resolve in place: edit the file, git add, git rebase --continue. The friction is the rebase doing its job.

🎯 Practice task

Practice both commands in a safe sandbox. 25-30 minutes.

  1. In your qa-sandbox repo, make sure you're on main with at least 3 commits. Create a branch: git switch -c feature/sample.
  2. On feature/sample, make 3 commits — one per file, simple content. Confirm with git log --oneline -5.
  3. Cherry-pick: switch back to main. Pick the middle commit's hash from your branch. Run git cherry-pick <hash>. Confirm with git log --oneline -5 that the change is on main with a new hash.
  4. Rebase: switch back to feature/sample. Make a new commit on main (git switch main && echo x > marker && git add marker && git commit -m "main moved"). Switch back to your branch and run git rebase main. Read the output; confirm with git log --oneline --graph --all that your branch's commits now sit on top of main's new commit.
  5. Interactive rebase: stay on feature/sample. Run git rebase -i HEAD~3. Change two picks to squash. Save. Write a combined commit message. Confirm git log --oneline shows fewer commits.
  6. Stretch: create a deliberate cherry-pick conflict (cherry-pick a commit that touches the same line as a commit on the destination branch). Resolve it: edit the file, git add <file>, git cherry-pick --continue.

That closes Chapter 4. You can now save in-progress work, read history, undo mistakes safely, and shape history with cherry-pick and rebase. Chapter 5 turns the focus to test automation projects specifically — .gitignore, test data, and Git hooks that run your suite before code leaves your machine.

// tip to track lessons you complete and pick up where you left off across devices.