gg
Use this skill to operate
git-gud () as a CLI tool for day-to-day stacked-diff workflows across GitHub and GitLab.
When to use
- You need multiple PRs/MRs that depend on each other
- You need to sync stack changes and keep review metadata updated (including GG-ID/GG-Parent normalization)
- You need machine-readable command output for automation ()
Prerequisites
- installed
- Provider CLI installed + authenticated:
- Git repo with initialized ()
Note: Network errors during auth check are non-fatal — gg prints a warning and continues. The operation may fail later if authentication is actually required.
Setup
Interactive wizard (recommended)
bash
gg setup # Quick mode: essential settings (provider, base, username)
gg setup --all # Full mode: all settings organized by category
Quick mode prompts for: provider, base branch, username.
Full mode organizes all settings into groups: General, Sync, Land, Lint, Worktrees, and GitLab (if applicable). Includes sync_draft, sync_update_descriptions, and sync_update_title options.
Global config
Store shared defaults in
that apply to all repos. Local config (
) takes precedence.
Manual setup ()
json
{
"defaults": {
"provider": "github",
"base": "main",
"branch_username": "your-github-user",
"lint": ["cargo fmt --all --check", "cargo clippy -- -D warnings"],
"auto_add_gg_ids": true,
"sync_auto_rebase": false,
"sync_behind_threshold": 1,
"sync_auto_lint": false,
"sync_draft": false,
"sync_update_descriptions": true,
"sync_update_title": false,
"land_auto_clean": false,
"land_wait_timeout_minutes": 30,
"unstaged_action": "ask"
}
}
json
{
"defaults": {
"provider": "gitlab",
"base": "main",
"branch_username": "your-gitlab-user",
"lint": ["cargo fmt --all --check", "cargo clippy -- -D warnings"],
"gitlab": {
"auto_merge_on_land": false
}
}
}
is deprecated and kept only for compatibility with existing configs; runtime behavior always treats it as enabled.
Core workflow
- Create/switch stack (prefer worktree):
When shell integration is installed (
,
, or
),
changes into the stack worktree after checkout succeeds. Without it, read the printed worktree path and
there before editing.
When splitting an existing stack into lower and upper stacks, prefer a managed
worktree for the new upper stack:
bash
gg unstack --target 3 --name feature-auth-followup --wt
- Commit logical changes:
bash
git add <files>
git commit -m "feat: add input validation"
- Check stack state:
bash
gg ls --json # single-stack details + summary metrics
gg log --json # smartlog-style view of the current stack
gg inbox --json # cross-stack triage buckets for action needed
- Publish/update PR/MR chain:
If a mapped PR/MR still points at an old source branch after a stack split,
recreates that PR/MR with the current entry branch, remaps config to
the new number, comments on the old one, and closes it. JSON action is
.
If
returns a warning that the stack branch does not use the
configured prefix, surface it to the user. The command may continue, but stack
discovery/listing and saved PR/MR mappings can be inaccurate until the branch is
renamed to match
.
- When approved + green CI, land only after user confirmation:
Agent operating rules (mandatory)
- Never run without explicit user confirmation.
- Always use for , , , , and .
- Prefer worktrees for isolation (). If shell integration is unavailable, manually to the printed worktree path before editing.
- Verify and success before landing. If the user requests , skip the approval check (GitHub only — GitLab ignores the flag).
- If sync warns stack is behind base, run first.
- Prefer for multi-commit edits.
- Never use blindly. Review first and only stage intended files. Use to avoid leaking secrets, env files, or unrelated changes.
- Respect the immutability guard. Rewrite-style commands (, , /, , , , , ) refuse to rewrite merged PRs/MRs or commits already on the base branch, except that silently skips base-ancestor commits that naturally drop out when rebasing onto the refreshed base. If a command exits with , surface the listed commits and reasons to the user and get explicit confirmation before retrying with / (alias ). If the error comes from 's auto-rebase, the override is /
gg rebase --ignore-immutable
, not .
Common operations
- Navigate: , , , ,
- Amend current commit: /
- Auto-distribute staged hunks:
- Split a commit into two: — opens a two-panel TUI for hunk selection (files on the left, colored diff on the right), followed by inline commit message inputs for both the new and remainder commits. Use to fall back to sequential style prompts. The flag bypasses the TUI message input for the new commit. The flag skips the remainder message input. Pass to auto-select all hunks from those files (e.g.,
gg split -c 3 file1.rs file2.rs
).
- Split a stack into two stacks: — opens a picker by default. The selected entry and descendants become a new independent stack; lower entries remain in the original stack. Use
--target <position|gg-id|sha> --no-tui
for scripts, and to choose the new stack name.
- Drop commits from stack:
gg drop <position|sha|gg-id>... -y
(alias: ). Use / to skip confirmation; add / only to bypass the immutability guard for merged/base-ancestor commits.
- Reorder/drop stack (TUI): (or ) — opens interactive TUI for visual reordering and dropping commits. Press to mark a commit for dropping. Use to fall back to text editor (delete lines to drop).
- Reorder stack (direct):
- Sync subset:
gg sync -u <position|gg-id|sha> --json
- Lint stack:
- Run a command across the stack: (see below)
- Triage multiple stacks at once:
- Repair ancestry drift: /
gg restack --dry-run --json
(see below)
- Clean merged stacks:
- Undo last local mutation: (see below)
Undoing local mutations ()
reverses the ref/
effects of the most recent mutating
command by replaying a snapshot from the per-repo operation log at
<commondir>/gg/operations/*.json
. It never touches the working tree,
index, or untracked files — only refs move.
bash
gg undo # reverse the most recent local operation
gg undo --list # see recent operations (newest-first)
gg undo <op_id> # target a specific record from --list
gg undo; gg undo # redo: a second undo reverses the first
gg undo --json # machine-readable output
Every mutating command (
,
,
,
,
,
,
,
,
,
, nav,
,
,
,
and
) snapshots the refs it will touch before mutating and
records the operation on success. The log keeps the last 100 records;
interrupted/pending records are never pruned.
Refusal modes (exit 1, no refs touched, JSON includes
):
- — target operation pushed/merged/closed/created a PR/MR.
gg prints a provider-specific revert hint (,
, ). Agents must surface the
hint to the user rather than attempt silent remote rollback.
- — operation crashed or was Ctrl-C'd mid-flight.
- — refs moved since the target operation finalised. The error
names the ref, expected OID, and actual OID.
- — record was written by a newer binary.
does
not restore working-tree content (use
or
), does
not touch remotes, and does
not support an
/
mode.
Repairing stack ancestry ()
detects and repairs ancestry drift — when a commit's
trailer no longer matches its expected parent in the stack order. This happens
after manual
,
, cherry-picks, or upstream
rebases that rewrite commit SHAs without updating GG metadata.
bash
gg restack --dry-run # show plan without changes
gg restack --dry-run --json # machine-readable plan
gg restack # execute full ancestry repair
gg restack --from 3 # repair only from position 3 upward
gg restack --json # execute with JSON output
Each step in the plan is one of:
- ok — parent already correct, no action needed
- reattach — parent differs, needs rebasing
- skip — below threshold, not checked
After a successful restack, run
to push the repaired commits.
Running commands across the stack ()
walks every commit in the current stack (oldest → newest) and
executes a command at each one. Use it for things that don't fit the
config — ad-hoc verifications, formatters, single-shot scripts,
etc.
- Read-only (default):
gg run -- cargo test -p mycrate
Each commit is checked out, the command runs, and the tree must stay
clean. Any modification fails that commit (same contract as
without ).
- Amend mode:
gg run --amend -- cargo fmt
Changes the command makes are folded into each commit via
, then the rest of the stack is rebased on top.
This is the same engine uses.
- Discard mode:
gg run --discard -- ./mutating-check.sh
Runs the command and throws away any changes (working tree + index +
untracked). Useful when you only care about the exit code of a
command that happens to mutate state.
- Stop on first failure (default) vs keep going:
Add / to continue through failing commits instead
of aborting at the first one.
- Limit how far you go:
--until <position|gg-id|sha>
stops after
the named commit. Everything above it is left untouched.
- Parallelize read-only runs: / spawns isolated
worktrees per commit. Valid only with the default (read-only) mode.
The dirty-tree check in each worker matches the sequential path
(untracked files are ignored, tracked modifications fail).
- JSON output:
gg run --json -- <cmd...>
emits a single
document on stdout (see ). Failures set
; the process still exits non-zero, but only
the run payload is printed — no trailing object.
Argument boundaries are preserved:
gg run -- git commit -m "multi word"
passes exactly those argv elements to
without shell splitting, so
quoted args with spaces, globs, or shell metacharacters go through
intact. Use
before the command (as shown) so clap treats
subsequent tokens as the command, not as
flags.
For repeatable linter runs with commands configured in
,
prefer
— it's
with the command list coming from
config.
Immutable commits
gg refuses by default to rewrite commits that look "already published":
- the tracked PR/MR is merged, or
- the commit is already reachable from (or the local base, as
a fallback).
The guard protects
,
,
/
,
,
,
,
, and
.
is a special case: merged commits (both base-ancestor commits and squash-merged PRs) are silently skipped because
would drop them naturally via patch-id matching instead of rewriting them. For the remaining commands the command exits with an
error listing every affected position, short SHA, title, and reason (e.g.
,
).
To bypass it intentionally, pass
/
(long alias
). Always surface the listed commits and reasons to the
user first; the override still emits a warning and proceeds.
If
surfaces the guard during auto-rebase, run
or
gg rebase --ignore-immutable
after user confirmation, then retry
.
only affects push behavior.
's post-merge cleanup bypasses the guard by design, and
skips it (no rewrite happens). See
→ "Immutable commits" for details.
PR/MR body ownership
uses managed markers to separate generated content from user edits:
(user content — preserved across syncs)
<!-- gg:managed:start -->
(generated by gg — regenerated on every sync)
<!-- gg:managed:end -->
(user content — preserved across syncs)
- New PRs/MRs: Body is wrapped in managed markers automatically.
- Re-sync with markers: Only the managed block is replaced; user content above/below is preserved.
- Legacy PRs (no markers): Body is left untouched with a warning — no risk of clobbering manual edits.
- Content inside the managed block is regenerated on each sync. Place persistent checklists and notes outside the markers.
Stack-navigation comments
If the repo's
has
defaults.stack_nav_comments: true
,
posts and maintains a managed comment on each open PR/MR in the
stack. The comment lists every entry (
on GitHub,
on GitLab) with a
👉 marker on the current one. The comment is identified by a hidden
marker and managed entirely by git-gud — don't edit
these comments manually, and don't be surprised when
adds, updates,
or removes them automatically.
Disable the feature by setting
defaults.stack_nav_comments: false
(the
default). The next
then cleans up any existing managed comments.
Reconcile is skipped under
to avoid partial-stack inconsistencies.
GitLab-specific
- is GitLab-only and requests queueing/auto-merge.
- With merge trains enabled, landing may enqueue MRs instead of immediate merge.
- After queueing, GitLab may temporarily omit the MR from the merge-train listing. Treat the "not reported yet; still polling" status as non-terminal unless the command reports closed, skipped, failed CI, timeout, or repeated API errors.
- Track train state in with:
- Land action values on GitLab may include / (in addition to ).
- When detects CI failure, the error message includes the names and stages of failed pipeline jobs (fetched from the MR's head pipeline).
- After landing an MR, downstream MRs are automatically retargeted away from the merged branch — no manual retargeting in GitLab UI is needed. also handles this if an MR was merged directly in the UI.
- Use for auxiliary GitLab checks/actions.
- JSON fields always use naming, even for GitLab MRs (, ).
Provider-neutral notes
- values: , , , (same for both GitHub and GitLab).
- format varies by provider ( for GitHub, for GitLab).
See also
- Full command + schema reference:
- End-to-end walkthrough:
- Multi-commit editing:
- Merge trains (GitLab):
- MCP server tools & schemas: → MCP Server section
MCP Server Usage for Agents
The
binary exposes git-gud as an MCP server (stdio transport). Set
to the target repo.
Read-only tools (safe, no side effects)
- / / / — inspect stacks ( gives a smartlog-style view of the current stack; is cross-stack)
- — check PR state, CI, approval
- — read repo configuration
- — list recent operations from the per-repo operation log
Write tools (mutating, use with care)
- — create or switch stacks
- — push and create/update PRs (use for safety)
- — merge approved PRs (always confirm with user first)
- — remove merged stacks
- — rebase onto latest base
- / — amend commits
- — fix out-of-sync remote branches (pass to skip the metadata normalization confirmation prompt in non-interactive/MCP contexts; this does not bypass safety checks or immutability protections)
- — remove commits from the stack (always passes ; set only to bypass the immutability guard for merged/base commits; agent confirms with user before any drop)
- — split a commit using interactive hunk selection (TUI opens by default; pass FILES... to auto-select all hunks for those files)
- — reorder commits with explicit order string (no TUI)
- — repair stack ancestry drift (, params)
- — reverse the ref/HEAD effects of the most recent mutating command (refuses on remote-touching ops, returns provider-specific revert hints; agents must surface those hints rather than attempt silent remote rollback)
Navigation tools
- — jump to a commit by position, GG-ID, or SHA
- — move first/last/prev/next in the stack
Agent guidelines for MCP
- Prefer read-only tools to understand state before writing.
- Use with for new PRs unless the user asks for non-draft. Note: only affects newly created PRs, not existing ones.
- Never call without explicit user approval.
- Parse JSON output from , , , and .
- If shows , run before syncing.
- Rewrite tools (, , , , , , plus CLI ) will fail with when a target commit is merged or already on the base branch. Each tool accepts a parameter that maps to / . Only set after surfacing the affected commits to the user and getting explicit approval. always passes (MCP is non-interactive), but its param is separate from the confirmation-skip — leave it unless the user has approved rewriting merged/base commits.