Rebasing, Cherry-Pick & Worktrees
Rebase, cherry-pick, and worktrees help Go teams keep linear history, port fixes across release lines, and work on two module versions at once.
Used carefully, they reduce go.sum conflict pain and speed hotfixes without dirty stashes.
Summary
Rebase replays your commits onto a newer base, rewriting SHAs.
Cherry-pick copies individual commits to another branch, common for backports.
Worktrees add a second checkout directory sharing one .git store, ideal for parallel go test runs on different branches.
All three interact with Go module pseudo-versions because those strings embed commit metadata.
Recipe
Quick-reference recipe card - copy-paste ready.
# Rebase feature branch onto latest main
git fetch origin
git switch feat/my-change
git rebase origin/main
go test ./...
go mod tidy && git diff --exit-code go.mod go.sum
git push --force-with-lease
# Cherry-pick hotfix to release branch
git switch release/v1
git cherry-pick abc1234
go test ./...
# Parallel checkout with worktree
git worktree add ../repo-hotfix release/v1When to reach for this:
- Updating a PR branch before merge without merge commits.
- Backporting a security fix from
maintorelease/v1. - Reviewing a release tag while continuing feature work in another directory.
- Cleaning up commit history before tagging a module release.
Working Example
Fix a nil panic on main, backport to v1 release line, keep feature work running:
# On main - fix landed as commit fa1c0ff
git switch main
git pull --ff-only
go test ./...
# Backport to release/v1
git switch release/v1
git pull --ff-only
git cherry-pick fa1c0ff
go test ./...
git tag -a v1.9.4 -m "v1.9.4: fix nil panic in parser"
git push origin release/v1 v1.9.4
# Continue feature branch in a worktree
git worktree add ../widget-feat feat/new-api
cd ../widget-feat
go test ./...What this demonstrates:
- Cherry-pick isolates the fix commit without merging all of
maininto the release branch. - Tests run on each line before tagging module consumers rely on.
- Worktree avoids stashing WIP on the feature branch during the hotfix.
Deep Dive
How It Works
Rebase temporarily removes your commits, fast-forwards to the new base, then reapplies commits one by one.
Conflicts may appear in Go sources and go.sum; resolve, git add, git rebase --continue.
Cherry-pick applies the patch of a chosen commit as a new commit on the current branch.
If the original commit touched go.mod, verify tidy state after pick.
Worktree creates a linked working directory with its own HEAD but shared objects and refs.
Each tree can run go build / go test independently; the module cache is global on the machine.
Rebase Safety Rules
| Situation | Guidance |
|---|---|
| Personal feature branch before merge | Rebase freely; push with --force-with-lease |
| Branch others pushed to | Coordinate; prefer merge |
| After tag consumers use | Do not rewrite tagged commits |
| Open PR with many reviewers | Rebase early and often, not only at end |
Cherry-Pick vs Merge for Backports
Cherry-pick brings one commit.
Merge brings entire branch history.
For Go patch lines, cherry-pick keeps release branches minimal and changelog-friendly.
Worktree Layout Example
~/src/widget/ # main work on feat/new-api
~/src/widget-hotfix/ # worktree on release/v1
List worktrees: git worktree list.
Remove: git worktree remove ../widget-hotfix after branch is done.
Go Notes
# After any history rewrite on a branch you depend on locally
go clean -testcache
go test ./...
# Pseudo-version preview for current HEAD (unpinned)
go list -m -json example.com/widget@masterRewriting SHAs changes pseudo-version strings for untagged commits.
Tagged releases are unaffected once pushed.
Gotchas
- Force-push without lease - Overwrites teammates' work silently. Fix: always
git push --force-with-lease. - Cherry-pick without re-running tests - Transitive
go.modcontext differs on release branch. Fix:go test ./...and tidy after every pick. - Rebase across
go.sumconflicts - Hand-merging checksum lines is error-prone. Fix: take one side, rungo mod tidy, continue rebase. - Too many worktrees - Disk and mental overhead. Fix: remove trees when PR merges; avoid one per experiment.
- Rebasing public fork default branch - Breaks contributor clones. Fix: rebase only feature branches targeting upstream.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
Merge main into feature | Shared branch, low rewrite tolerance | You want linear trunk history |
git merge backport | Large divergent release line | Single-commit security fix |
| Stash | Quick context switch, minutes | Parallel long builds on two branches |
| Separate clone | Completely isolated experiments | Wasted disk and fetch time |
FAQs
Does rebase change module versions consumers see?
Tagged semver releases do not change after rebase unless you move or delete tags.
Untagged commits accessed via pseudo-versions will show new version strings after SHA changes.
When should I prefer merge over rebase?
When multiple people commit to the same branch or when preserving exact merge context matters for audits.
Can cherry-pick fail on Go generated files?
Yes, if protobuf or stringer outputs differ between branches.
Regenerate with the branch's toolchain, then continue the cherry-pick.
How many worktrees are practical?
Two or three per repo is typical: trunk, feature, hotfix.
More than that usually signals branch policy problems.
Should CI run after force-push?
Yes.
Treat force-pushed branches like new pushes; module graphs must re-validate.
What is interactive rebase for?
Squash WIP commits, reword messages, drop debug commits before a clean PR.
Run before review, not after merge to trunk.
Do worktrees share go.work?
Each worktree is a separate directory.
A go.work file in one tree does not apply to another unless you copy or symlink intentionally.
How remove a bad cherry-pick?
git cherry-pick --abort during conflict, or git revert on the bad commit if already committed.
Does bisect interact with rebase?
Rebasing old commits changes SHAs and can confuse manual bisect notes.
Use tags and merge commits as stable bisect anchors.
Can I worktree a detached tag?
Yes: git worktree add ../widget-v1 v1.9.3.
Useful to reproduce a consumer bug at an exact module version.
Should bots rebase PRs automatically?
Helpful if checks rerun reliably.
Ensure go mod tidy and tests run after bot rebase, not just conflict resolution.
What about rebase in monorepos?
Same rules, but conflicts may span multiple go.mod files.
Tidy each affected module root after resolution.
Related
- Branching Strategies & Trunk-Based Flow - When to rebase feature branches
- Git Basics for Go Projects - Stash and worktree intro example
- Signed Tags & Go Module Releases - Tagging after cherry-picked fixes
- Monorepo Git Patterns with go work - Parallel module work across trees
- Code Review with GitHub PRs - Force-push etiquette in review
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).