关于 graphite
Graphite Skill 提供使用 Graphite(`gt`)创建、导航和管理堆叠式 Pull Request 的命令指引,面向维护分支堆栈的开发者,涵盖提交、变基和故障恢复流程。
主要功能
- 01创建并修改堆叠分支
- 02导航和查看分支堆栈
- 03提交堆栈以供审查
- 04调整分支顺序和父级
- 05重新堆叠分支并处理冲突
- 06恢复中断的变基
适用场景
- 01构建一组范围明确的 Pull Request
- 02在堆栈分支间切换
- 03将堆栈变基到 main
- 04处理更新堆栈时的问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ withgraphite/ agent-skills --skill graphite安装后在 Claude Code 中输入/graphite确认已加载。
详细介绍
Graphite 技能
使用 Graphite(gt)创建、浏览和管理堆叠式拉取请求。
快速参考
| 我想要…… | 命令 |
|---|---|
| 创建新分支/PR | gt create branch-name -m "message" |
| 修改当前分支 | gt modify -m "message" |
| 向上浏览堆栈 | gt up |
| 向下浏览堆栈 | gt down |
| 跳到堆栈顶部 | gt top |
| 跳到堆栈底部 | gt bottom |
| 查看堆栈结构 | gt ls |
| 提交堆栈以供审查 | gt submit --no-interactive |
| 将堆栈变基到主干分支 | gt restack |
| 更改分支父级 | gt track --parent <branch> |
| 重命名当前分支 | gt rename <new-name> |
| 移动堆栈中的分支 | gt move |
什么样的 PR 才算好?
大致按重要性降序排列:
- 原子化/自包含 - 不依赖其他更改;可通过 CI,并且单独部署也安全
- 语义范围窄 - 只更改模块 X,或在模块 X、Y、Z 中进行相同的更改
- 差异小 - (经验法则)总差异行数较少
不要担心创建太多拉取请求。 创建更多拉取请求总是优于创建更少拉取请求。
再小的更改也值得提交: 微小的 PR 有助于让中型/大型 PR 更清晰。
只要每个 PR 都能独立通过构建,就应始终倾向于创建更多 PR。
分支命名约定
为堆栈中的 PR 命名时,请遵循以下格式:
terse-stack-feature-name/terse-description-of-change
例如,一个包含 4 个 PR 的堆栈:
auth-bugfix/reorder-args
auth-bugfix/improve-logging
auth-bugfix/improve-documentation
auth-bugfix/handle-401-status-codes
创建堆栈
基本工作流
- 修改文件
- 暂存更改:
git add <files> - 创建分支:
gt create branch-name -m "commit message" - 为堆栈中的每个 PR 重复上述步骤
- 提交:
gt submit --no-interactive
处理未跟踪的分支(worktree 中很常见)
创建分支前,检查当前分支是否已被跟踪:
gt branch info
如果看到“ERROR: Cannot perform this operation on untracked branch”:
选项 A(推荐):先临时跟踪,再重新设置父级
- 跟踪当前分支:
gt track -p main - 使用
gt create正常创建堆栈 - 创建完所有分支后,将第一个新分支的父级重新设为 main:
gt checkout <first-branch-of-your-stack> gt track -p main gt restack
选项 B:暂存更改并从 main 开始
git stashgit checkout main && git pull- 创建新分支并恢复暂存的更改:
git checkout -b temp-working && git stash pop - 继续执行
gt track -p main和gt create
浏览堆栈
# Move up one branch (toward top of stack)
gt up
# Move down one branch (toward trunk)
gt down
# Jump to top of stack
gt top
# Jump to bottom of stack (first branch above trunk)
gt bottom
# View the full stack structure
gt ls
修改堆栈
修改当前分支
git add <files>
gt modify -m "updated commit message"
重新排序分支
使用 gt move 重新排列堆栈中的分支。这比尝试使用 gt create --insert 更简单。
重新设置堆栈的父级
如果你在某个功能分支上创建了堆栈,但希望以 main 为基础:
# Go to first branch of your stack
gt checkout <first-branch>
# Change its parent to main
gt track --parent main
# Rebase the entire stack
gt restack
重命名分支
gt rename new-branch-name
将提交重置为未暂存的更改
如果更改已经提交,但你想以不同方式重新堆叠:
# Reset the last commit, keeping changes unstaged
git reset HEAD^
# Reset multiple commits (e.g., last 2 commits)
git reset HEAD~2
# View the diff to understand what you're working with
git diff HEAD
提交前
确认堆栈以 main 为根
运行 gt submit 前,确认第一个 PR 的父级是 main:
gt ls
如果第一个分支的父级不是 main:
gt checkout <first-branch>
gt track -p main
gt restack
运行验证
创建每个 PR 后,运行适当的代码检查、构建和测试:
- 参考项目的 CLAUDE.md,了解具体命令
- 如果验证失败,修复问题、暂存更改,然后使用
gt modify
提交和更新 PR
提交堆栈
gt submit --no-interactive
更新 PR 描述
提交后,使用 gh pr edit 设置合适的标题和描述。
**重要:**切勿使用 Bash heredoc 编写 PR 描述——shell 转义会破坏 Markdown 表格、代码块等内容。请改用以下方式:
- 使用
Write工具创建/tmp/pr-body.md,写入完整的 Markdown 内容 - 使用
gh pr edit和--body-file:
gh pr edit <PR_NUMBER> --title "stack-name: description" --body-file /tmp/pr-body.md
PR 描述必须包含:
- Stack Context:此堆栈的更大目标是什么?
- What?(小改动可选):尽量简洁,重点说明改了什么,而不是为什么改
- Why?:是什么促成了这次改动?为什么选择此方案?它如何融入堆栈?
示例(在一个由 3 个 PR 组成、用于添加警告功能的堆栈中提交 PR):
## Stack Context
This stack adds a warning on the merge button when users are bypassing GitHub rulesets.
## Why?
Users who can bypass rulesets (via org admin or team membership) currently see no indication
they're circumventing branch protection. This PR threads the bypass data from the server to
enable the frontend warning (PR 2) to display it.
故障排除
| 问题 | 解决方案 |
|---|---|
| "Cannot perform this operation on untracked branch" | 先运行 gt track -p main |
| 堆栈的父分支不正确 | 使用 gt track -p main,然后运行 gt restack |
| 需要调整 PR 顺序 | 使用 gt move |
| restack 期间发生冲突 | 解决冲突,然后运行 git rebase --continue |
| 想要拆分 PR | 重置提交(git reset HEAD^),选择性地重新暂存,然后创建新分支 |
| 需要删除分支(非交互模式) | gt delete <branch> -f -q |
gt restack 遇到无关冲突 | 改用指定目标的 git rebase <target>(见下文) |
| rebase 在冲突处理中断 | 检查文件是否已解决但尚未暂存,然后运行 git add 和 git rebase --continue |
进阶:在复杂堆栈中精准 rebase
在分支众多、嵌套层级较深的堆栈中,gt restack 可能会带来问题:
- 它会重排所有需要重排的分支,而不只是你的堆栈
- 可能会遇到完全无关分支中的冲突
- 它会一次性全部执行,很难精准控制
何时使用 git rebase 而不是 gt restack
在以下情况下,使用直接的 git rebase:
- 你只想更新堆栈中的特定分支
gt restack在无关分支中遇到冲突- 你需要在 rebase 期间跳过过时的提交
指定目标的 rebase 工作流
# 1. Checkout the branch you want to rebase
git checkout my-feature-branch
# 2. Rebase onto the target (e.g., updated parent branch)
git rebase target-branch
# 3. If you hit conflicts:
# - Resolve the conflict in the file
# - Stage it: git add <file>
# - Continue: git rebase --continue
# 4. If a commit is obsolete and should be skipped:
git rebase --skip
# 5. After rebase, use gt modify to sync graphite's tracking
gt modify --no-edit
从中断的 rebase 中恢复(上下文重置)
如果 rebase 中断(例如,Claude 会话耗尽上下文):
-
检查状态:
git status # Look for "interactive rebase in progress" and "Unmerged paths" -
查看“未合并”的文件——它们可能已经解决(不含冲突标记)
-
如果冲突已解决,只需暂存并继续:
git add <resolved-files> git rebase --continue -
如果仍有冲突标记,先解决冲突,然后暂存并继续
从堆栈中删除分支
# Delete a branch (non-interactive, even if not merged)
gt delete branch-to-delete -f -q
# Also delete all children (upstack)
gt delete branch-to-delete -f -q --upstack
# Also delete all ancestors (downstack)
gt delete branch-to-delete -f -q --downstack
标志:
-f/--force:即使分支尚未合并或已关闭,也强制删除-q/--quiet:隐含--no-interactive,减少输出
删除中间分支后,其子分支会自动重排到父分支之上。如果需要手动更新跟踪关系:
gt checkout child-branch
gt track --parent new-parent-branch