用途
Bail 是一套“退出协议”(bail-out protocol),用于在开发任务需要中止时,按固定顺序完成反思与清理。它的核心原则是:始终先反思(reflect FIRST),然后再清理(then clean up)。所有命令均使用绝对路径和 git -C 形式执行。
主要能力
- 自动识别当前所处阶段:通过检查已存在的产物判断进度,例如仅有 Issue 无分支对应 Step 0(Capture),存在 .branch-context.md 但无工作树对应 Step 1(Orient),工作树存在但无代码改动对应 Step 2(Isolate),分支上有计划文件对应 Step 3-4(Design/Review),代码改动已提交对应 Step 5-7(Build/Verify/Archive),GitHub 上 PR 已打开对应 Step 8(Ship)。
- 记录退出上下文:将退出原因、尝试内容与经验教训追加写入工作树中的 .branch-context.md,并提交为 “docs: capture bail context”。
- 汇总经验到 MEMORY.md:通过一次性克隆(disposable clone)读取并追加相关经验,提交后推送;遇到 non-fast-forward 时先 pull --rebase 再 push,最多重试 3 次,完成后删除临时克隆目录。
- 更新 GitHub Issue:在可访问时添加评论说明退出原因与经验已记录,并添加 deferred 标签、移除 triage 标签。
- 关闭 PR:若该分支存在打开的 PR,则将其关闭。
- 分支保留与删除:默认保留分支以便日后恢复;仅当用户明确要求删除时,展示将被销毁的内容并要求输入 'delete' 确认,之后才移除工作树并删除分支。
使用方式
输入包括:WORKTREE(当前工作树的绝对路径,若无工作树则为主仓库路径),以及可选的原因字符串(未提供时会询问)。若未提供原因,会先提示补充。
写入退出上下文示例:
cat >> "$WORKTREE/.branch-context.md" <<EOF
## Bail
- Reason: <reason>
- What was attempted: <summary>
- What was learned: <learnings>
EOF
git -C "$WORKTREE" add .branch-context.md
git -C "$WORKTREE" commit -m "docs: capture bail context"
汇总经验到 MEMORY.md 时使用一次性克隆,不在工作树中 checkout main:
BAIL_DIR="${CLAUDE_SESSION_DIR:-$TMPDIR}/bail-reflect"
[ -d "$BAIL_DIR" ] && rm -rf "$BAIL_DIR"
git clone --depth 50 "$(git -C "$WORKTREE" remote get-url origin)" "$BAIL_DIR"
读取 $BAIL_DIR/ai-workspace/MEMORY.md,追加 .branch-context.md 中的相关经验,然后提交并推送:
git -C "$BAIL_DIR" add ai-workspace/MEMORY.md
git -C "$BAIL_DIR" commit -m "docs: consolidate learnings from abandoned <branch>
Co-Authored-By: Claude <model>"
git -C "$BAIL_DIR" push
更新 GitHub Issue:
GH_REPO=<owner/repo> gh issue comment <number> --body "Bailing: <reason>. Learnings captured in MEMORY.md."
GH_REPO=<owner/repo> gh issue edit <number> --add-label "deferred" --remove-label "triage"
关闭 PR(若存在):
PR_NUM=$(GH_REPO=<owner/repo> gh pr list --head "<branch>" --json number -q '.[0].number')
if [ -n "$PR_NUM" ]; then
GH_REPO=<owner/repo> gh pr close "$PR_NUM"
fi
删除分支前需用户输入 'delete' 确认,并校验分支已合并:
PRIMARY="$(git -C "$WORKTREE" worktree list --porcelain | grep -m1 '^worktree ' | sed 's/^worktree //')"
git -C "$PRIMARY" worktree remove "$WORKTREE"
git -C "$PRIMARY" branch -d <branch>
若 branch -d 因未合并而失败,会警告用户并停止,不使用 branch -D 强制删除。完成后不 checkout main,保持会话当前工作目录不变。
适用场景
适用于在结构化开发流程中需要中途放弃某个任务、但希望保留经验教训并保持仓库整洁的场景,例如任务被推迟、方向调整或外部条件变化导致无法继续。
限制与边界情况
- 无工作树(在 Step 0-1 退出)时跳过工作树清理,仅更新 Issue。
- 无 GitHub 访问权限时跳过 Issue 更新,仍执行本地清理与记忆汇总。
- PR 已合并时不关闭,仅在输出中说明。
- 无 .branch-context.md 时,先创建一个仅含退出原因的文件再进行汇总。
- CLAUDE_SESSION_DIR 未设置时,回退到 $TMPDIR 作为克隆目录。
- 输出为清理内容与经验保存位置的摘要。