docs reference Feedback & approvals
15-feedback-and-approvals.md ReferenceJul 17, 2026

Feedback & approvals

Review feedback in GitStack lives on threads attached to a single review. You read the threads with gs review comments, start one with gs review comment, and answer with gs review reply or gs review resolve as you push fixes. Approvals ride the same surface: gs review approve marks a review good to land, and a later patchset can clear that approval. Every command here takes a review ref like r1 (see reference syntax) and infers the repo from your git origin unless you pass --repo.

gs review comments#

List the comment threads on a review.

bash
gs review comments [r<n>] [--unresolved] [--patchset N] [--filter human|agent|all]
Flag Description
--unresolved Show only threads that are still open.
--patchset N View threads against patchset N. 0, the default, means the latest.
--filter <who> Limit to human, agent, or all threads. Default is all.
--repo <name> Repo name. Default is inferred from origin.
Flag
--unresolved
Description
Show only threads that are still open.
Flag
--patchset N
Description
View threads against patchset N. 0, the default, means the latest.
Flag
--filter <who>
Description
Limit to human, agent, or all threads. Default is all.
Flag
--repo <name>
Description
Repo name. Default is inferred from origin.

The review ref is optional; with no ref the command reads the review at HEAD. Each row shows the thread id, its state (open or resolved), the author, and the comment body. Replies print under their thread with an /reply suffix on the id.

bash
gs review comments r1 --unresolved

Thread ids are ULIDs. They print as the shortest prefix (at least four characters) that is unique among that review's threads, so you copy the short prefix straight into reply, resolve, or --resolves.

Off-branch reviews

r1 reads like a stack position, but review ids are global. If r1 is not on your current branch, gs review comments prints a warning naming the branch and stack it found, then still shows the threads. The mutating commands below refuse instead of warning.

gs review comment#

Open a new comment thread on a review, optionally anchored to a file and line.

bash
gs review comment [r<n>] -m "..." [--file F --line N[:M]]
Flag Description
--message, -m Comment body. Opens $EDITOR when omitted.
--file <path> Anchor the thread to a file, relative to the repo root.
--line <N or N:M> Anchor to a single line or a range. Requires --file.
--commit <sha> Commit the anchor refers to. Default is HEAD.
--patchset N Patchset to attach to. Default is the latest.
--repo <name> Repo name. Default is inferred from origin.
Flag
--message, -m
Description
Comment body. Opens $EDITOR when omitted.
Flag
--file <path>
Description
Anchor the thread to a file, relative to the repo root.
Flag
--line <N or N:M>
Description
Anchor to a single line or a range. Requires --file.
Flag
--commit <sha>
Description
Commit the anchor refers to. Default is HEAD.
Flag
--patchset N
Description
Patchset to attach to. Default is the latest.
Flag
--repo <name>
Description
Repo name. Default is inferred from origin.

Leave off --file for a review-level thread. Add --file and --line to pin the thread to a specific spot in the diff.

bash
gs review comment r2 --file internal/billing/proration.go --line 42 \
  -m "guard against a zero denominator here"
--line needs --file

A line anchor only makes sense against a file, so --line without --file is an error. Ranges use N:M, for example --line 42:57.

gs review reply#

Reply to an existing thread.

bash
gs review reply <r<n>> <thread> -m "..."
Flag Description
--message, -m Reply body. Opens $EDITOR when omitted.
--repo <name> Repo name. Default is inferred from origin.
Flag
--message, -m
Description
Reply body. Opens $EDITOR when omitted.
Flag
--repo <name>
Description
Repo name. Default is inferred from origin.

Both the review ref and the thread prefix are required. The thread prefix is the short id from gs review comments.

bash
gs review reply r2 01H8 -m "fixed in patchset 2"

gs review resolve#

Mark a thread resolved.

bash
gs review resolve <r<n>> <thread>
Flag Description
--repo <name> Repo name. Default is inferred from origin.
Flag
--repo <name>
Description
Repo name. Default is inferred from origin.
bash
gs review resolve r2 01H8
Reply first, resolve last

A reply posted on an already-resolved thread reopens it. If you resolve a thread and then add a closing reply, the thread comes back as open. Reply first and resolve last, or let --resolves (below) resolve the thread at push time so you never touch it again by hand.

gs commit --resolves / gs amend --resolves#

--resolves records which threads a fix closes so the resolution rides along with your next push. It lives on both gs commit and gs amend, takes a thread-id prefix, and repeats.

bash
gs amend --no-edit --resolves 01H8
gs commit -m "billing: add the missing guard" --resolves 01J3 --resolves 01H8
Flag Description
--resolves <prefix> Thread id or prefix to resolve on the next push. Repeatable.
Flag
--resolves <prefix>
Description
Thread id or prefix to resolve on the next push. Repeatable.

Each prefix expands against the threads on the review at HEAD, so run it from the review the thread belongs to. The ids accumulate across every commit and amend (including across a rebase conflict you resume with --continue) and drain on the next gs push. The push prints one outcome line per id, resolved thread <id> on success and warning: thread <id> was not resolved: <reason> when the server rejects it, so trust those lines rather than re-checking the thread list. Pushes made on your behalf by gs sync or autostack print the same lines.

--resolves avoids the reopen trap

Because the server resolves the thread as part of the push, there is no separate gs review resolve call to sequence against a reply. This is the safe way to close threads you also replied to.

gs review approve#

Approve a review, signalling it is good to land.

bash
gs review approve [r<n>]
Flag Description
--patchset N Patchset to approve. Default is the latest.
--repo <name> Repo name. Default is inferred from origin.
Flag
--patchset N
Description
Patchset to approve. Default is the latest.
Flag
--repo <name>
Description
Repo name. Default is inferred from origin.

The review ref is optional; with no ref the command approves the review at HEAD.

bash
gs review approve r1

Approvals clear automatically when a new patchset changes the review's content. A fast_forward that appends commits (extending the review) and a force_push that rewrites them (revising it) both drop the approval, so the author cannot slip new code past a stale LGTM. A rebase, where the diff is unchanged and only the commits underneath were rewritten, keeps the approval. gs review comments and gs review show label each patchset with its kind, so you can see which change reset an approval. See reviews for the patchset model.

How many approvals a review needs is up to the repo. By default a review needs no LGTM: a writer can land their own review, and a repo owner can land anyone's. A repo can require LGTMs, require every requested reviewer, or hold owners to the same rule in the [approvals] table of .gitstack/policy.toml. Only LGTMs from people who can currently write to the repo count.

gs review unapprove#

Withdraw an approval you previously gave.

bash
gs review unapprove [r<n>]
Flag Description
--patchset N Patchset to unapprove. Default is the latest.
--repo <name> Repo name. Default is inferred from origin.
Flag
--patchset N
Description
Patchset to unapprove. Default is the latest.
Flag
--repo <name>
Description
Repo name. Default is inferred from origin.
bash
gs review unapprove r1

gs review reviewers#

List the reviewers on a review, or add and remove them.

bash
gs review reviewers <r<n>> [--add <user>] [--remove <user>]
Flag Description
--add <user> Reviewer to add, by handle (or ULID). Repeatable.
--remove <user> Reviewer to remove, by handle or ULID. Repeatable.
--repo <name> Repo name. Default is inferred from origin.
Flag
--add <user>
Description
Reviewer to add, by handle (or ULID). Repeatable.
Flag
--remove <user>
Description
Reviewer to remove, by handle or ULID. Repeatable.
Flag
--repo <name>
Description
Repo name. Default is inferred from origin.

The bare form lists the current reviewers. Pass --add or --remove (each repeatable, and you can mix both in one call) to change the set. Name reviewers by handle; a ULID works too. --remove drops the reviewer whichever spelling you or they were added with.

Requested reviewers put the review in their queue. They gate landing only when the repo's landing policy sets require_requested_reviewers = true: then every requested reviewer who can approve (a writer or owner other than the author) must LGTM before the review lands, and gs submit names who it is waiting on. A requested reviewer who can only read the repo is skipped, so they never block a land.

bash
gs review reviewers r1
gs review reviewers r1 --add dana --remove sam

For the wider review lifecycle (create, split, land) see reviews and landing and cleanup. New to the flow, start with the getting started guide.