本文へ移動
cccskills
無料GitHub で公開

git-stack

Stack an existing or new git branch on top of another branch, restacking it in a git worktree when needed, then align the GitHub PR bases and stack metadata with `gh stack`. Use when invoked as `$git-stack` or when the user asks to stack or restack a branch or PR onto another branch.

インストール方法を見る

含まれるファイル(2)

  • SKILL.md10.2 KB
  • agents/openai.yaml43 B

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

git-stack

Stack <branch> onto <base-branch> (or restack it onto its current base) in a dedicated worktree, then align GitHub PR bases and the gh stack object with the resulting local chain.

Workflow

  1. Parse arguments (drop a bare literal onto token):

    TokensMeaning
    0subject = current branch; base resolved in step 2 (restack mode)
    1base = token; subject = current branch
    2subject = token 1; base = token 2
    3+Stop: usage is stack [<branch>] [<base-branch>]

    Stop if subject equals base.

  2. Resolve repo, remote, trunk, and (restack mode) the base:

    repo_root=$(git rev-parse --path-format=absolute --git-common-dir); repo_root=${repo_root%/.git}
    current=$(git branch --show-current)
    remote=$(git config --get "branch.${subject}.remote" || true)
    if [ -z "$remote" ]; then
      remotes=$(git remote); remote_count=$(echo "$remotes" | wc -l)
      [ "$remote_count" -eq 1 ] && remote=$(echo "$remotes" | head -1)
    fi
    [ -n "$remote" ] || { git remote | grep -qx origin && remote=origin; }
    [ -n "$remote" ] || { echo "Multiple remotes found, none configured for branch. Candidates: $(git remote | tr '\n' ' ')"; exit 1; }
    trunk=$(git symbolic-ref "refs/remotes/${remote}/HEAD" 2>/dev/null | sed "s|refs/remotes/${remote}/||")
    [ -n "$trunk" ] || trunk=$(git config init.defaultBranch || echo main)
    git fetch --prune "$remote"
    

    Never hard-code origin — the repo's remote may be named anything.

    Restack mode (0 tokens) resolves base as the first hit of:

    base=$(gh pr view "$subject" --json baseRefName -q .baseRefName 2>/dev/null)
    [ -n "$base" ] || base=$( (cd "$repo_root" && gh stack view --json 2>/dev/null) | jq -r --arg s "$subject" '
      .branches | to_entries | map(select(.value.name == $s))[0].key as $i
      | if $i == null or $i == 0 then empty else .[$i-1].value.name end')
    

    Stop with the usage line if both are empty. Stop if base resolves to neither refs/heads/$base nor refs/remotes/$remote/$base.

  3. Pick the working checkout — prefer the worktree that already holds subject so a branch checked out elsewhere is never rewritten from the wrong worktree:

    work_dir=$(git worktree list --porcelain | awk -v b="refs/heads/$subject" '
      /^worktree /{ wt=$2 } /^branch /{ if ($2 == b) print wt }')
    
    • work_dir non-empty → use it; if git -C "$work_dir" status --porcelain=v1 is non-empty, stop and tell the user to commit or stash there first.

    • work_dir empty and repo_root is $HOME (dotfiles repo) → do not create a worktree; using-git-worktrees forbids implicit dotfiles worktrees. If subject is the current branch and the tree is clean, set work_dir="$repo_root"; otherwise stop and tell the user to run wt switch "$subject" --allow-home first.

    • Otherwise create one under the using-git-worktrees convention:

      path_key=${repo_root#"$HOME"/}; path_key=${path_key//\//-}
      work_dir="$HOME/.worktrees/${path_key}/${subject}"
      if git show-ref --quiet "refs/heads/${subject}"; then
        git worktree add "$work_dir" "$subject"
      elif git show-ref --quiet "refs/remotes/${remote}/${subject}"; then
        git worktree add --track -b "$subject" "$work_dir" "${remote}/${subject}"
      else                                                        # new-branch mode
        base_ref="${remote}/${base}"; git show-ref --quiet "refs/remotes/${base_ref}" || base_ref="$base"
        git worktree add "$work_dir" -b "$subject" --no-track "$base_ref"
        git -C "$work_dir" push -u "$remote" "${subject}:${subject}"
        git -C "$work_dir" branch -vv
      fi
      

      --no-track is mandatory here: a branch cut from a remote base must not inherit the base's upstream. Report the branch -vv line as proof it tracks $remote/$subject.

    New-branch mode has no commits to replay: report the ready worktree and stop, unless the branch already has commits, in which case continue at step 7 to open its PR.

  4. Create a backup (existing-branch mode only):

    git -C "$work_dir" branch "${subject}.bak" "$subject"
    

    If ${subject}.bak already exists, ask whether to overwrite (git branch -f) or abort. Keep the backup after success.

  5. Restack locally — --onto replays exactly the commits unique to subject, correct whether it was cut from trunk or an older base tip; never plain git rebase <base> here:

    base_ref="${remote}/${base}"; git show-ref --quiet "refs/remotes/${base_ref}" || base_ref="$base"
    if git -C "$work_dir" merge-base --is-ancestor "$base_ref" "$subject"; then
      echo "already stacked on ${base}; nothing to replay"
    else
      fork=$(git -C "$work_dir" merge-base "$subject" "$base_ref")
      git -C "$work_dir" rebase --onto "$base_ref" "$fork" "$subject"
    fi
    

    (equivalent to git rebase --onto <base_ref> <merge-base> <subject>, run with -C "$work_dir".)

    On conflict, follow git-rebase's conflict handler: recorded rerere resolution as-is; clean-filtered machine state → --ours; version bumps → the higher version; deliberate config updates → --theirs; generated artifacts → regenerate. Stage each fix, verify no conflict markers remain, then GIT_EDITOR=true git -C "$work_dir" rebase --continue (or --skip if the commit went empty). Pause only for genuine semantic collisions in hand-written source. Rollback: git -C "$work_dir" reset --hard "${subject}.bak".

  6. Push the subject — before any gh stack call, since gh stack link pushes without --force-with-lease:

    git -C "$work_dir" push --force-with-lease -u "$remote" "${subject}:${subject}"
    git -C "$work_dir" branch --set-upstream-to="${remote}/${subject}" "$subject"
    git -C "$work_dir" branch -vv | grep '^\*'
    

    The tracking line must show [${remote}/${subject}]; fix it before continuing if it shows the base branch instead.

  7. Build the stack chain bottom→top (trunk excluded), capped at 10 hops against a cycle:

    chain=("$subject"); b="$base"; hops=0
    while [ "$b" != "$trunk" ] && [ "$hops" -lt 10 ]; do
      chain=("$b" "${chain[@]}")
      parent=$(gh pr view "$b" --json baseRefName -q .baseRefName 2>/dev/null) || parent=""
      [ -n "$parent" ] || break            # no PR for $b: treat it as the bottom of the stack
      b="$parent"; hops=$((hops + 1))
    done
    
  8. Ensure every chain member has an open PR based on its parent (previous chain entry, or $trunk for the first):

    pr_json=$(gh pr view "$member" --json number,state,baseRefName 2>/dev/null || echo '{}')
    state=$(echo "$pr_json" | jq -r '.state // empty')
    
    • state is MERGED or CLOSED → stop and report: step 7's chain walk picked up a member whose PR already landed or was abandoned; restacking must resolve this manually (typically by re-running with a base below that member so the chain collapses to $trunk). Never create a spurious new PR for it.
    • No PR, or state is empty → invoke pr-create for that branch so the repo's title, body, label, draft, and @me assignment conventions (pr-style) apply, then retarget: gh pr edit "$number" --base "$parent". Never hand-roll gh pr create or let link auto-create the PR here — both bypass pr-style.
    • state is OPEN and base differs from parent → gh pr edit "$number" --base "$parent".
    • state is OPEN and base already matches parent → leave it.
  9. Align the GitHub stack:

    if [ "${#chain[@]}" -ge 2 ]; then
      (cd "$work_dir" && gh stack link --remote "$remote" --base "$trunk" "${chain[@]}")
    fi
    

    A single-member chain (base is trunk) has no GitHub stack to create — skip link and say so; step 8 already put that PR's base on $trunk. Always pass --remote and --base explicitly. Never pass --open: new PRs stay drafts.

  10. Add local stack tracking, best effort:

    if ! (cd "$work_dir" && gh stack view --json >/dev/null 2>&1) && [ "${#chain[@]}" -ge 2 ]; then
      git -C "$work_dir" config --local rerere.enabled true
      (cd "$work_dir" && gh stack init --base "$trunk" "${chain[@]}") || echo "local stack tracking unavailable"
    fi
    

    A non-zero exit is not a workflow failure — the GitHub metadata from step 9 is already correct; report "local tracking unavailable" and continue. If gh stack view --json already succeeds but lists a different branch set, skip init and report the mismatch instead of guessing.

  11. Report children that now need restacking:

    gh pr list --state open --json number,headRefName,baseRefName \
      --jq ".[] | select(.baseRefName == \"$subject\") | .headRefName"
    

    For each child, print the follow-up stack command with $subject as its new base. Leaving children based on a rewritten branch silently is the main failure mode of manual stacking.

  12. Report:

    Stacked <subject> onto <base>.
      Worktree:     <work_dir>
      Chain:        <trunk> → <b1> → … → <subject>
      PRs:          #<n1> (base <trunk>) → … → #<nk> (base <base>)
      GitHub stack: linked | single PR, no stack | local tracking unavailable
      Tracking:     <remote>/<subject>
      Backup:       <subject>.bak  (kept — git branch -D <subject>.bak)
      Children to restack: stack <child> <subject>   (or "none")
    

Never

  • Never run bare gh stack view — always use gh stack view --json; bare view opens an interactive TUI.
  • Never run the modify subcommand, or bare switch/checkout without a branch argument — both are interactive-only.
  • Never run the submit subcommand — it auto-generates PR titles/bodies, conflicting with this repo's pr-style conventions.
  • Never run unstack [<stack-number>] [--local] unless the user explicitly asks — it deletes the GitHub stack.
  • Never rewrite a branch from a worktree that does not have it checked out.
  • Never create a dotfiles worktree implicitly.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

2ndbrain

無料

Quick-save the last assistant response as a verbatim note in the 2ndBrain Obsidian vault (~/2ndBrain/quick-notes/<year>/). Use when the user asks to quick-save/save the last response to 2ndBrain, or invokes $2ndbrain or /skill:2ndbrain.

日本語の概要は準備中です。原文の説明を表示しています。

phatblat/dotfiles122026年10月11日 更新

Write commit messages under the agent-commits convention - a Conventional Commits fork with no chore catch-all, intent-only type tokens, facts in trailers, and legally-grounded AI provenance (Assisted-by, never Co-authored-by). Use when composing a commit in a repo whose commitlint.config.js extends agent-commits, when deciding between feat/fix/refactor/perf, or when recording AI participation.

日本語の概要は準備中です。原文の説明を表示しています。

phatblat/dotfiles122026年10月11日 更新

Coordinate multi-agent work through durable artifacts in git instead of chat. Use this whenever a task involves sending a message to another agent, agent mailboxes or handoffs, claiming work from a shared queue, notifying another agent or crew (OpenClaw, Grok Bot, Claude Code, Codex, Gas Town/Gas City workers) that work is ready, or whenever the user mentions the artifact bus, message bus, agent mail, beads mail, doorbells, or pings between agents — even if they don't say "bus" explicitly.

日本語の概要は準備中です。原文の説明を表示しています。

phatblat/dotfiles122026年10月11日 更新

aven

無料

Use aven to find tasks, update status, and leave durable handoff context.

日本語の概要は準備中です。原文の説明を表示しています。

phatblat/dotfiles122026年10月11日 更新

boris

無料

Codex workflow tips from Boris Cherny (creator of Codex) and the Codex team. Use when: setting up Codex, optimizing workflows, running parallel sessions, configuring AGENTS.md, using skills/commands, subagents, hooks, MCP integrations, or learning best practices. Covers: git worktrees, plan mode, verification, permissions, Slack MCP, BigQuery, prompting tips, plugins, custom agents, sandboxing, keybindings, status lines, output styles, customization, /simplify for code quality, /batch for parallel code migrations, /loop for scheduled tasks, code review agents, /btw for mid-task questions, /effort max reasoning, remote control sessions, voice mode, setup scripts, session naming, /color, PostCompact hook, auto mode, /schedule cloud jobs, iMessage plugin, auto-memory, and auto-dream, mobile app, session teleporting, Cowork Dispatch, Chrome extension, Desktop app, /branch forking, --bare SDK startup, --add-dir multi-repo, --agent custom agents, /voice input.

日本語の概要は準備中です。原文の説明を表示しています。

phatblat/dotfiles122026年10月11日 更新

boris

無料

Claude Code workflow tips from Boris Cherny (creator of Claude Code) and the Claude Code team. Use when: setting up Claude Code, optimizing workflows, running parallel sessions, configuring CLAUDE.md, using skills/commands, subagents, hooks, MCP integrations, or learning best practices. Covers: git worktrees, plan mode, verification, permissions, Slack MCP, BigQuery, prompting tips, plugins, custom agents, sandboxing, keybindings, status lines, output styles, customization, /simplify for code quality, /batch for parallel code migrations, /loop for scheduled tasks, code review agents, /btw for mid-task questions, /effort max reasoning, remote control sessions, voice mode, setup scripts, session naming, /color, PostCompact hook, auto mode, /schedule cloud jobs, iMessage plugin, auto-memory, and auto-dream, mobile app, session teleporting, Cowork Dispatch, Chrome extension, Desktop app, /branch forking, --bare SDK startup, --add-dir multi-repo, --agent custom agents, /voice input.

日本語の概要は準備中です。原文の説明を表示しています。

phatblat/dotfiles122026年10月11日 更新

phatblat のスキルをすべて見る

このスキルの問題を報告する