← Back to list

Git rebase / cherry-pick / worktree Advanced Team Collaboration Guide

Many people have been using Git for five years, but their commands still stay at the "add / commit / push / pull" four-piece set, with at…

Chimin · 2026-07-14 23:09 · 2 claps · 9.1 min read paywalled
#git #git-worktree #coding #vibe-coding #programming
Open on Medium ↗
Wiki topics: 💻 · Programming 🔓 · Open Source 📊 · Economic Policy 🥊 · Combat Sports

Git rebase / cherry-pick / worktree Advanced Team Collaboration Guide

Many people have been using Git for five years, but their commands still stay at the "add / commit / push / pull" four-piece set, with at most a "merge" added. Once they encounter tasks like "squash these five commits into one," "cherry-pick a hotfix to two other branches," or "work on both main and hotfix simultaneously without stashing," they start to panic.

Today, I'll go over the most commonly used advanced Git commands—rebase -i / cherry-pick / worktree / stash / bisect—all at once. Each one comes with real commands and real scenarios, so you can use them immediately after reading.

Companion reading: W7 covered reflog as a lifesaver, and this article will reference it heavily. Don't panic if rebase goes wrong; reflog is the regret pill.

rebase Mental Model: Moving Commits

Merge merges two lines into a new merge node; rebase moves a series of commits from the original base to a new base.

Before moving:  
        A---B---C  feature  
       /  
  D---E---F---G  main  

After moving (git checkout feature && git rebase main):  
                  A'--B'--C'  feature  
                 /  
  D---E---F---G  main  

Note the prime marks (A' B' C') — after rebase, commit hashes will always change because the parent has changed. This is the root of all collaboration issues later.

When to use rebase:

  • Want history to be a straight line for a clean log
  • Want to squash and organize multiple WIP commits before pushing for review
  • Want to catch up the feature branch with the latest code on main to avoid a huge merge conflict later

When not to use rebase:

  • On branches that have already been pushed to remote and are being used by others — rebasing and pushing would ruin your colleagues' work
  • On public release branches (main / release) — history must retain real merge nodes

Interactive Rebase: rebase -i

This is the most frequently used one in daily work. For example, you've made 5 messy commits over the past two days:

git --no-pager log --oneline -5  
# a1b2c3d Fix comment pagination bug  
# d4e5f6g typo  
# h7i8j9k temporary console.log  
# k0l1m2n Comment pagination API  
# n3o4p5q Comment pagination UI

You want to squash these 5 into a single "Comment pagination feature" commit and push it to your supervisor for review.

git rebase -i HEAD~5   # Enter interactive mode, operate on the last 5 commits

An editor (vim / VSCode) will pop up showing something like:

pick n3o4p5q Comment pagination UI  
pick k0l1m2n Comment pagination API  
pick h7i8j9k temporary console.log  
pick d4e5f6g typo  
pick a1b2c3d Fix comment pagination bug  

# Commands:  
# p, pick = use commit  
# r, reword = use commit, but edit the commit message  
# e, edit = use commit, but stop for amending  
# s, squash = use commit, but meld into previous commit  
# f, fixup = like "squash", but discard this commit's log message  
# d, drop = remove commit

Note: In the list, commits are ordered from oldest to newest from top to bottom, which is the opposite of git log.

Our goal:

  • Keep the first UI commit
  • Squash the API commit into the UI (keep both commit messages)
  • Drop the console.log
  • Fixup the typo into the previous commit (discard the typo message)
  • Reword the bug fix to a proper description

Change it to:

pick n3o4p5q Comment pagination UI  
s    k0l1m2n Comment pagination API  
d    h7i8j9k temporary console.log  
f    d4e5f6g typo  
r    a1b2c3d Fix comment pagination bug

Save and exit. Git will pause to let you edit the squashed commit message, then let you reword the last one. After organizing, the result is:

Tip: After drop removes that commit, if the next commit is fixup / squash, it will merge into the previous non-dropped commit. In the example, f typo will actually be merged into s Comment pagination API, not the vanished console.log. Keep that in mind when placing drop next to fixup/squash.

git --no-pager log --oneline -2  
# x9y8z7w Comment pagination feature (UI + API)  
# v6u5t4s feat: Fix comment pagination edge cases

Clean.

Remember these frequently used commands:

Rebase Conflict Resolution Toolkit

Conflicts during rebase are common. The flow differs slightly from merge:

git rebase main  
# CONFLICT (content): Merge conflict in src/api.ts  

# Resolve conflict (editor / IDE / git mergetool all work)  
vim src/api.ts  

# Mark as resolved  
git add src/api.ts  

# Continue rebase (note: not git rebase --commit)  
git rebase --continue

If you want to give up midway:

git rebase --abort   # Return to state before rebase

If a commit is no longer valid (e.g., main already did the same thing), you can skip it:

git rebase --skip

During rebase, you may need to resolve conflicts multiple times – because each commit is replayed against the new base. So it's normal to resolve the same file conflict three times in a row; don't think Git is malfunctioning.

This is an age-old debate with no standard answer. Here's a convention our team has used for three years:

Our convention:

  1. Inside a feature branch: free to rebase (your own playground, no one else using it)
  2. Before merging feature into main: first git rebase main to catch up with latest code, then create MR
  3. Main branch merges: use merge (preserves merge point for auditing / rollback)
  4. Already pushed branches: after rebasing, push must use --force-with-lease, not -f:
# Safe: if someone else has pushed new commits to remote, it will reject  
git push --force-with-lease origin feature-x  

# Dangerous: directly overwrites remote, may break colleague's work  
git push -f origin feature-x   # Use with caution

Don't argue "rebase vs merge" in team chat — just write it into CONTRIBUTING.md and everyone follows it.

cherry-pick: Pick Hotfixes to Multiple Branches

Typical scenario: Two versions running online release-1.x and release-2.x, a bug fixed on main needs to be applied to both releases.

# 1. Find that commit on main  
git --no-pager log --oneline -1  
# a1b2c3d fix: Comment pagination NPE  

# 2. Switch to release-1.x, cherry-pick  
git checkout release-1.x  
git cherry-pick a1b2c3d  

# 3. Same for release-2.x  
git checkout release-2.x  
git cherry-pick a1b2c3d

Useful parameters:

# -x: Append "(cherry picked from commit a1b2c3d)" at the end of commit message  
# Helps audit where this commit came from  
git cherry-pick -x a1b2c3d  

# -n: Pick but don't auto-commit, review first then commit  
git cherry-pick -n a1b2c3d  
git diff --cached       # Check what was picked  
git commit -m "fix: ... (backport from main)"  

# Pick a range of consecutive commits (left-exclusive, right-inclusive)  
git cherry-pick a1b2c3d..h7i8j9k  

# Conflict handling (same as rebase)  
git cherry-pick --continue  
git cherry-pick --abort  
git cherry-pick --skip

Gotcha: After cherry-pick, the commit hash will change (since the parent is different), so the same fix has three different hashes across three branches. The -x parameter is a lifesaver for auditing backports.

worktree: Develop Multiple Branches in Parallel in the Same Repository

This command is not widely used, but once you use it, you'll never go back.

Classic scenario: You're working hard on a feature branch when your boss says, "There's an urgent bug on production."

Old way:

git stash                   # Stash current changes  
git checkout main  
git checkout -b hotfix-xxx  
# Fix code, commit, merge  
git checkout feature-x  
git stash pop               # Restore

Switching back and forth, stash might cause conflicts. If the hotfix takes hours, you'll have to deal with stash conflicts later.

worktree solution:

# Create another working directory beside current repo, checkout hotfix branch  
git worktree add ../proj-hotfix -b hotfix-xxx main  

# Now your file system looks like:  
# ~/work/proj/             ← Your feature-x in progress, files untouched  
# ~/work/proj-hotfix/      ← New hotfix workspace, can independently modify, commit, push  

# Open proj-hotfix in another IDE window, finish and push  
cd ../proj-hotfix  
# ... fix code ...  
git push origin hotfix-xxx  

# After done, remove worktree  
cd ../proj  
git worktree remove ../proj-hotfix

Common commands:

git worktree list          # See current worktrees  
git worktree add <path> <branch>    # Add new worktree (branch already exists)  
git worktree add <path> -b <new-branch> [<base>]  # Create new branch and worktree  
git worktree remove <path> # Remove worktree  
git worktree prune         # Clean up metadata of manually deleted directories

Notes:

  • The same branch cannot be checked out in two worktrees at once (will error)
  • Share the same .git directory – all branches/remotes/stash are available
  • Large directories like node_modules need to be installed in each worktree; make sure you have enough disk space

Our frontend team now uses proj/ (main development) + proj-review/ (dedicated to checking out others' branches for review). No more interrupting current work.

stash Advanced

90% of people only know git stash + git stash pop. But stash is much richer:

# Add a message when stashing for easy identification  
git stash push -m "Comment pagination WIP halfway"  

# View stash list  
git stash list  
# stash@{0}: On feature-x: Comment pagination WIP halfway  
# stash@{1}: On main: Debug output  

# See diff of a specific stash  
git stash show -p stash@{0}  

# Apply without deleting (apply) vs apply and delete (pop)  
git stash apply stash@{0}   # stash remains  
git stash pop               # Apply most recent and delete  

# Stash only part of files (interactive)  
git stash push -p  
# Stash this hunk [y,n,q,a,d,e,?]?   

# Restore stash as a branch (useful when base has changed long after stash)  
git stash branch stash-restore stash@{0}  

# Clear all stashes (careful!)  
git stash clear

Practical advice:

  • Always name your stash with -m, otherwise you won't remember what it is after two days
  • For long-term WIP, use branches instead of stash – stash is for "short-term save"
  • Stash does not save untracked files (use git stash -u to include untracked, -a also includes ignored)

bisect: Binary Search for Bugs

Scenario: A feature that worked fine two weeks ago is now reported broken by users. There are 200 intermediate commits; rolling back one by one is impractical.

bisect uses binary search to find which commit introduced the bug.

# Start  
git bisect start  

# Tell Git the current version is bad  
git bisect bad  

# Tell Git a tag from two weeks ago is good  
git bisect good v1.2.0  

# Git will automatically checkout the middle commit  
# Bisecting: 100 revisions left to test after this (roughly 7 steps)  
# [a1b2c3d] feat: xxx  

# Manually test this version  
npm test      # Or run your own reproduction script  

# Tell Git the result  
git bisect good     # This version is good  
# Or  
git bisect bad      # This version is bad  

# Git continues binary search, repeat about 7 times to locate the bug-introducing commit  
# a1b2c3d is the first bad commit  

# When done, end bisect  
git bisect reset

Advanced: Fully automated

If you have a script that can determine good/bad (return 0 for good, non-zero for bad), you can run it in one shot:

git bisect start HEAD v1.2.0  
git bisect run ./scripts/repro-bug.sh   # Auto binary search to the end, find first bad commit  
git bisect reset

With 200 commits, 7-8 binary searches will locate the bug, far more efficient than going through git log one by one.

reflog: The Regret Pill for rebase

Most common rebase disaster:

git rebase -i HEAD~10  
# Accidentally dropped commits you shouldn't have  
# Save and exit  
# ... oh no

Don't panic. All commits altered by rebase are still alive in reflog – to be precise: reachable commits are kept for 90 days by default (gc.reflogExpire), and commits that become unreachable after rebase are kept for 30 days by default (gc.reflogExpireUnreachable). So if you find a mistake, act fast:

git reflog  
# a1b2c3d HEAD@{0}: rebase finished: returning to refs/heads/feature-x  
# d4e5f6g HEAD@{1}: rebase: Comment pagination UI  
# h7i8j9k HEAD@{2}: rebase: Comment pagination API  
# k0l1m2n HEAD@{3}: rebase (start): checkout main  
# n3o4p5q HEAD@{4}: commit: The commit I shouldn't have deleted   ← Here it is!  
# ...  

# Reset the branch to state before rebase  
git reset --hard HEAD@{4}

Remember: As long as you've committed it, there's hope. See W7's article for detailed explanation.

Submodule and Subtree Overview

These are less frequently used, so a quick mention:

  • submodule: Embed another independent repository inside the main repo. The main repo only stores a pointer (commit hash). Suitable for shared internal libraries, but clone/pull may cause "submodule not updated" pitfalls.
  • subtree: Merge the content of another repository directly into a subdirectory of the main repo, no pointer concept. Simple but merge history can be messy.

In practice, more and more teams are moving to monorepo + workspace (npm / pnpm / yarn) or package managers (npm private registry / Maven). Submodule/subtree are not recommended for new projects. If needed, a separate article can be written.

Final Words

Git advanced commands essentially do two things:

  1. Rewrite history (rebase / commit --amend / cherry-pick)
  2. Manage workspaces (stash / worktree)

As long as you remember that rewritten commits change hashes, and be cautious with already pushed branches, plus have reflog as a regret pill, you can't really go wrong.

One final suggestion: Always try these Git advanced commands for the first time on your own local toy repo – don't practice on production branches. Once you get the hang of them, you'll save a lot of time every day.


메타데이터
post_id
35f787fa4c51
slug
git-rebase-cherry-pick-worktree-advanced-team-collaboration-guide-35f787fa4c51
url
https://medium.com/@githubdaily/git-rebase-cherry-pick-worktree-advanced-team-collaboration-guide-35f787fa4c51
canonical_url
https://medium.com/@githubdaily/git-rebase-cherry-pick-worktree-advanced-team-collaboration-guide-35f787fa4c51
author_url
https://medium.com/@githubdaily
status
ok
fetched_at
2026-07-15 14:13:45