Commits & syncing
This is the loop you run all day. Stage a change, commit it into a review, push the branch, and sync when the base branch moves under you. GitStack keeps the whole stack on one branch, so a commit lands inside a review and a push updates the branch and its manifest together. When gs rewrites history it tells you which reviews changed and how.
Every command here also takes the global flags (--plain, --json,
--verbose); see CLI conventions. Review ids and
thread ids follow the forms in reference syntax.
gs add#
Stage files. This is a passthrough to git add.
gs commit does not stage for you. Run gs add first, or pass -a to commit
to stage tracked modifications.
gs add <pathspec>...
gs add takes the same pathspecs as git add and has no flags of its own.
gs add internal/billing/model.go internal/api/billing.go
gs commit#
Create a commit. It extends the topmost review, or inserts into a lower review when HEAD sits there.
gs commit -m "message"
gs commit -m "message" --review -t "title"
| Flag | Description |
|---|---|
--message, -m |
commit message |
--all, -a |
stage tracked modifications before committing |
--review |
after committing, carve a new single-commit review |
--title, -t |
title for the new review (with --review) |
--fixes N |
issue this stack fixes, repeatable, requires --review |
--automerge |
land the whole stack once every review is approved and CI is green, requires --review |
--resolves <id> |
thread id or prefix to mark resolved on the next push, repeatable |
--amend |
alias for gs amend |
--no-edit |
reuse the prior message (with --amend) |
--continue |
resume after a rebase conflict |
--abort |
discard the in-flight commit |
--allow-dirty |
with --review, push even when the tree has other uncommitted or untracked changes |
--squash |
land this review as one commit (the default) |
--rebase |
land this review's commits as they are, on top of the base |
--message, -m--all, -a--review--title, -t--review)--fixes N--review--automerge--review--resolves <id>--amendgs amend--no-edit--amend)--continue--abort--allow-dirty--review, push even when the tree has other uncommitted or untracked changes--squash--rebaseAt the top of the stack, the commit extends the topmost review and prints a short hint naming the review it joined. Mid-stack (HEAD checked out at a lower review), the commit inserts into that review. That review classifies as extended, and every review above it rebases automatically. Extending a review resets its LGTMs, because the reviewer has new code to look at. Reviews that only rebase keep their approvals. See reviews for how approvals work.
--review -t carves in one step. It commits, carves the new commit into a
fresh single-commit review at the top of the stack, and pushes so the server
allocates patchset 1. It only works at the top. If the tree still carries other
uncommitted changes, the carve keeps the review but skips that final push
(partial staging is supported) and leaves a next: gs push hint. Pass
--allow-dirty to push anyway and leave those changes local.
--resolves takes a thread id or a unique prefix and is repeatable. The threads
are marked resolved when the commit reaches the server on the next push.
The --squash and --rebase flags declare how the carved review lands later.
See landing and cleanup.
gs add internal/billing/webhook.go
gs commit -m "billing: handle Stripe webhook" --review -t "billing: webhook handler"
A mid-stack insert can hit a conflict while the reviews above rebase. The commit
pauses. Resolve the files, gs add them, then gs commit --continue. Use
gs commit --abort to discard the in-flight commit and restore the stack.
gs commit --review carves the top commit into a new review, so it only works
at the top of the stack. For mid-stack reshaping use gs review create or
gs review split. See reviews.
gs amend#
Amend HEAD's commit. It stays put at the top of the stack and rebases downstream when mid-stack.
gs amend
gs amend --no-edit
| Flag | Description |
|---|---|
--message, -m |
new commit message |
--no-edit |
reuse the prior commit message |
--resolves <id> |
thread id or prefix to mark resolved on the next push, repeatable |
--continue |
resume after a rebase conflict |
--abort |
discard the in-flight amend |
--message, -m--no-edit--resolves <id>--continue--abortgs amend rewrites the commit at HEAD. The review it belongs to classifies as
revised, so its LGTMs reset. At the top of the stack nothing above needs to
move. Mid-stack, gs amend rebases every review above the one you changed, and
those rebased reviews keep their approvals.
--no-edit keeps the existing message. --resolves marks threads resolved on
the next push, the same as on gs commit.
gs checkout r1
gs add internal/billing/model.go
gs amend --no-edit --resolves 01H8
gs push
A conflict during the downstream rebase pauses the amend. Resolve, gs add the
files, then gs amend --continue (or gs amend --abort to discard it).
A revised review needs a fresh sign-off. The reviews above keep their approvals, because they were replayed onto your new commit, not rewritten.
gs push#
Push the branch and its manifest in one atomic update.
gs push
| Flag | Description |
|---|---|
--force |
force-with-lease the branch (rarely needed) |
--allow-dirty |
push even when the tree has uncommitted or untracked changes |
--force--allow-dirtyA single push updates the branch ref and the manifest ref together, and the
server classifies each patchset in the same transaction. The push is atomic:
if the server refuses the branch update (another clone pushed first), it
refuses the manifest too, so the server never holds a manifest for a branch
tip it does not have. Run gs sync and push again. After a rewrite that
gs performed (a mid-stack commit, an amend, or a sync rebase) gs arms the lease
and pushes with --force-with-lease for you. Do not pass a manual --force.
The flag exists for rare recovery and is usually redundant.
gs push refuses when the working tree has uncommitted or untracked changes,
because a push only sends commits and a forgotten gs commit is the usual
cause. When those changes are meant to stay local (scratch files, a build
artifact, an edit you are not ready to commit), pass --allow-dirty.
The commits push and the rest stays in your working tree. gs review create,
gs review split, gs review fold, and gs commit --review take the same
flag for the push they make.
gs push prints one line per changed review:
r1 patchset 3 (revised) gp_a1b2
r2 patchset 2 (rebased) gp_c3d4
resolved thread 01H8The kinds map to what happened to the review. extended means new commits
fast-forwarded onto it, revised means its commit was rewritten, and rebased
means it was replayed onto a moved base with no content change. Any threads you
marked with --resolves print their own outcome line, and a warning prints when
the server could not resolve one.
If push refuses with this message, another clone pushed since you last synced.
Run gs sync to reconcile, then push again.
gs sync#
Reconcile the local manifest with the server, then rebase onto a moved base.
gs sync
gs sync --manifest-only
| Flag | Description |
|---|---|
--manifest-only |
reconcile the manifest only, never rebase the stack |
--discard-local-edits |
adopt the server's stack even when that drops a split, fold, or reorder you have not pushed |
--continue |
resume a sync paused on a rebase conflict |
--abort |
discard a paused sync and restore the stack |
--manifest-only--discard-local-edits--continue--abortgs sync pulls the server's authoritative manifest and replaces the local copy
when they differ. When the base branch has moved past your stack, sync rebases
the whole stack onto the new base and pushes it, printing a line like:
rebased r1 r2 onto mainA split, fold, or reorder you have not pushed yet (one made with --no-push, or
whose push failed) is kept: sync rebases the stack with it and pushes it. If the
server's stack also changed since your last push, sync cannot carry the edit
over safely, so it refuses and names it. Run
gs sync --discard-local-edits to take the server's stack instead, then redo
the edit.
Sync is idempotent, so running it again on a current stack does nothing. With
--manifest-only it reconciles the manifest and never rebases or touches the
working tree, which is the safe form to run when you only want the latest review
state.
A conflict during the rebase pauses sync. Resolve the files, gs add them, then
gs sync --continue. Use gs sync --abort to drop the paused sync and restore
the stack to where it started.
A dirty working tree blocks the rebase. Commit or stash your changes first,
then run gs sync again.
gs status#
Show working-tree state and where HEAD sits in the stack. It is local only and makes no server calls.
gs status
gs status --remote
| Flag | Description |
|---|---|
--remote |
also show remote branch diagnostics |
--remotegs status prints a single line: the branch, the review HEAD sits in out of the
total, and whether the tree is clean or how many files changed.
on add-billing · r2 of 3 · 2 changedWhen the repo is in a recovery state, a paused rebase or HEAD parked off the
stack, a banner prints above that line with the command to get unstuck. Pass
-v to expand the changed-file detail. --remote adds remote diagnostics:
where this worktree fetches and pushes, and whether the branch exists on the
server yet.
For moving HEAD around the stack that gs status reports on, see
stacks and navigation.