Every stacked-diff tool sits on top of plain git. There is nothing magic happening — gt restack is literally a series of git rebase --onto commands, just orchestrated by a DAG instead of by you. So the honest comparison is: what does stkd actually save you, versus running git directly?
This article is that comparison, in concrete steps.
The plain-git stacked workflow
Here’s how you stack three branches without any tool:
# Branch 1
git checkout -b feature/auth-base main
# … work, commit …
git push -u origin feature/auth-base
gh pr create --base main --head feature/auth-base
# Branch 2 — stacked on branch 1
git checkout -b feature/auth-oauth feature/auth-base
# … work, commit …
git push -u origin feature/auth-oauth
gh pr create --base feature/auth-base --head feature/auth-oauth
# Branch 3 — stacked on branch 2
git checkout -b feature/auth-2fa feature/auth-oauth
# … work, commit …
git push -u origin feature/auth-2fa
gh pr create --base feature/auth-oauth --head feature/auth-2fa
Three branches, three PRs. Doable. Mildly tedious. With stkd this is one command per branch (gt create) and one to push them all (gt submit --stack), but it’s not the typing that gets you — it’s what happens next.
Now a reviewer asks for a fix on branch 1
# Switch to branch 1, fix it, commit, push
git checkout feature/auth-base
# … fix …
git commit -am "address review feedback"
git push origin feature/auth-base # PR #1 updated
# Now the trouble starts.
# Branch 2 is now based on the *old* tip of feature/auth-base.
# You have to rebase it onto the new tip.
git checkout feature/auth-oauth
git rebase --onto feature/auth-base @{u} feature/auth-oauth
# (or some variation — getting the three arguments right is famously confusing)
git push --force-with-lease origin feature/auth-oauth
# Same for branch 3.
git checkout feature/auth-2fa
git rebase --onto feature/auth-oauth @{u} feature/auth-2fa
git push --force-with-lease origin feature/auth-2fa
That’s three context-switches, two git rebase --onto invocations (with three arguments each that you’ll consult man git-rebase to get right), and two force-pushes. Multiply by N branches in the stack and you understand why this workflow doesn’t scale.
With stkd, that whole sequence is:
gt down # navigate to feature/auth-base
# … fix …
git commit -am "address review feedback"
gt restack
gt submit --stack
Same outcome. Two commands instead of seven. No mental tracking of which branch was based on which.
A reviewer asks for a fix on branch 2
The plain-git version:
git checkout feature/auth-oauth
# … fix …
git commit -am "fix oauth review feedback"
git push --force-with-lease origin feature/auth-oauth
# Branch 3 is now based on old auth-oauth. Restack:
git checkout feature/auth-2fa
git rebase --onto feature/auth-oauth @{u} feature/auth-2fa
git push --force-with-lease origin feature/auth-2fa
stkd version:
gt up # or gt up 2 to skip past auth-oauth
# (we're on feature/auth-oauth now)
# … fix …
git commit -am "fix oauth review feedback"
gt restack
gt submit --stack
You can see the pattern. The interesting work — making the fix, committing it — is the same. The tedium of propagating it through the stack is what stkd takes off your plate.
Branch 1 merges
# Plain git
git checkout main
git pull
git branch -d feature/auth-base # delete merged branch locally
# Now branch 2 is based on the *old* feature/auth-base which is gone.
# We need to rebase it onto main.
git checkout feature/auth-oauth
git rebase --onto main feature/auth-base@{1} feature/auth-oauth
# (the reflog trick — fragile if you've done other git operations in the meantime)
git push --force-with-lease origin feature/auth-oauth
# And the same for branch 3.
git checkout feature/auth-2fa
git rebase --onto feature/auth-oauth feature/auth-base@{1} feature/auth-2fa
git push --force-with-lease origin feature/auth-2fa
# You also need to update the PR's base from feature/auth-base to main.
gh pr edit 42 --base main
That last step — updating the PR’s base branch on GitHub — is something plain git absolutely cannot do for you. GitLab now does it automatically when the source branch merges; GitHub still requires a manual update. With stkd, it’s handled.
stkd version:
gt sync
# fetches origin, detects feature/auth-base merged, deletes it locally,
# restacks feature/auth-oauth and feature/auth-2fa onto main,
# retargets the PRs (#42, #43) to point at main.
One command.
The conflict scenario
Where the plain-git workflow gets really hairy is when restacking hits a conflict.
git rebase --onto feature/auth-base @{u} feature/auth-oauth
# Auto-merging src/auth/middleware.rs
# CONFLICT (content): Merge conflict in src/auth/middleware.rs
# error: could not apply abc1234... oauth provider wiring
You resolve middleware.rs, then:
git add src/auth/middleware.rs
git rebase --continue
# More potential conflicts on subsequent commits...
# Eventually:
git push --force-with-lease origin feature/auth-oauth
# Now restack feature/auth-2fa, which is also conflicted...
Each branch in the stack potentially has its own conflicts. You manage them by hand and remember which branches still need restacking.
stkd version of the same situation:
gt restack
# Restacking feature/auth-oauth: conflict in src/auth/middleware.rs
# Resolve the conflict, then run: gt continue
# (resolve the conflict, save the file)
gt continue
# ✓ feature/auth-oauth restacked
# Restacking feature/auth-2fa: clean
# ✓ All branches restacked.
The state of the in-progress restack is kept by stkd in .git/stkd/restack-state.json. If you gt continue and forget what branch you were on, stkd remembers. If you abort, gt undo rolls everything back to where you started.
The real cost of plain git
A rough mental model:
- Single-branch development with plain git: zero overhead. This is exactly what git was designed for.
- Occasional 2-branch stacks with plain git: tolerable, ~3 minutes of overhead per restack.
- Frequent 3-4 branch stacks with plain git: painful. You’ll either give up on stacking or build your own tooling.
- 5+ branch stacks with plain git: don’t. Even Linus Torvalds doesn’t do this by hand.
The break-even is around the second time you stack. By the third time, the time savings cover learning the tool.
What stkd doesn’t replace
Importantly:
- stkd is not a
gitreplacement. You still usegitfor commits, day-to-day work, repository administration. stkd handles the stacking layer specifically. - You can mix workflows. Some branches are part of stacks (
gt created); others are normal feature branches (git checkout -b). stkd only touches branches it knows about. - You don’t lose any git skills. Everything you know about git still applies.
gt restackis just a series ofgit rebase --ontoinvocations; if you understand those, you understand stkd.
Verdict
If you stack occasionally, plain git is fine — and the discipline of doing it by hand teaches you the underlying mechanics. If you stack frequently, the time savings from stkd’s automation are real, and the mental load saved (no more drawing out the DAG on paper) is bigger.
The honest framing: stkd doesn’t do anything you couldn’t do in git. It just does the tedious bookkeeping that the human shouldn’t have to think about.