create-issue-tree

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

create-issue-tree

create-issue-tree

要件・タスク一覧から Phase 分割された GitHub Issue ツリーを新規作成する。 ルート(トラッキング issue)→ Phase 親 issue → issue → sub-issue の 4 階層を構築し、implement-issue-tree が post-order DFS で消化できる構造を維持する。
从需求与任务列表中创建按Phase划分的GitHub Issue树。 构建根(追踪Issue)→ Phase父Issue→ Issue→ sub-issue的4层结构,维持可被implement-issue-tree通过后序DFS方式处理的结构。

使い方

使用方法

引数としてタスク要件テキストまたはファイルパスを渡す。
--phase
オプションで特定 Phase のみ起票することもできる(大規模ツリーを段階的に起票する場合)。
2 回目以降の部分起票では
--root
で既存ルート issue 番号を渡し、同じツリーに継ぎ足す (指定しないと新しいルート issue が重複作成される)。
--milestone
オプションで起票する issue 全件に割り当てる GitHub Milestone を指定できる (
--root
指定時は省略可。既存ルートの milestone を自動継承する)。
create-issue-tree "ユーザー認証機能を実装する"
create-issue-tree requirements.md
create-issue-tree requirements.md --phase 2 --root 123
create-issue-tree requirements.md --milestone "v2.0"
传入任务需求文本或文件路径作为参数。
可通过
--phase
选项仅发起指定Phase的Issue(适用于大规模树的分步发起场景)。
第二次及以后的部分发起需通过
--root
传入已存在的根Issue编号,以追加到同一树中 (若不指定,会重复创建新的根Issue)。
可通过
--milestone
选项为所有发起的Issue指定GitHub Milestone (指定
--root
时可省略,会自动继承已有根Issue的milestone)。
create-issue-tree "实现用户认证功能"
create-issue-tree requirements.md
create-issue-tree requirements.md --phase 2 --root 123
create-issue-tree requirements.md --milestone "v2.0"

前提条件

前提条件

  • gh
    CLI がインストールされ、認証済みであること(
    gh auth status
    で確認)
  • 対象リポジトリへの Issue 書き込み権限があること
  • 已安装
    gh
    CLI并完成认证(可通过
    gh auth status
    确认)
  • 拥有目标仓库的Issue写入权限

フロー

流程

Step 1: 要件を分析してタスクを分解する

Step 1: 分析需求并分解任务

入力テキストまたはファイルから要件を読み込み、以下の観点でタスクを分解する。
  • 粒度基準: 1 issue は実装 4h 程度に収める。 4h を超えると判断した場合は sub-issue に再分解する
  • 各タスクの依存関係・実行順を把握する
  • タスク数を集計し、Phase 分割の要否を判断する(目安: 10 件超で Phase 分割を検討)
分解結果をユーザーに提示し、Phase 構成・issue 数について確認を取る。
--phase
オプションが指定されている場合は該当 Phase のタスクのみ対象とする。
从输入文本或文件中读取需求,从以下维度分解任务:
  • 粒度标准:1个Issue的实现工作量控制在4小时左右。 若判断超过4小时,则进一步分解为sub-issue
  • 掌握各任务的依赖关系与执行顺序
  • 统计任务数量,判断是否需要进行Phase划分(参考标准:任务数超过10件时考虑Phase划分)
将分解结果展示给用户,确认Phase构成与Issue数量。
若指定了
--phase
选项,则仅处理对应Phase的任务。

Step 2: Phase 構成を設計する

Step 2: 设计Phase构成

タスク数・依存関係をもとに Phase を設計する。
  • Phase は独立して開発可能な単位で分割する(例: Phase 1 基盤・Phase 2 機能・Phase 3 改善)
  • 各 Phase に親 issue タイトル(Conventional Commits 形式推奨)を割り当てる
  • 全体をまとめるルート(トラッキング)issue のタイトルを決定する
    • 例:
      chore(global): 全 open issue の Phase 別トラッキング (YYYY-MM-DD)
タスクが少数(Phase 分割不要)の場合はルート issue + 子 issue の 2 階層構成にする。
基于任务数量与依赖关系设计Phase:
  • Phase需按可独立开发的单元划分(例如:Phase 1 基础架构、Phase 2 功能实现、Phase 3 优化改进)
  • 为每个Phase分配父Issue标题(推荐使用Conventional Commits格式)
  • 确定用于汇总全局的根(追踪)Issue标题
    • 示例:
      chore(global): 所有open Issue的Phase别追踪 (YYYY-MM-DD)
若任务数量较少(无需Phase划分),则采用根Issue + 子Issue的2层结构。

Step 2.5: milestone を決定する

Step 2.5: 确定milestone

このツリーに割り当てる GitHub Milestone を決定する。ルート・Phase 親・子・sub-issue の 全件に同一 milestone を適用する(ツリー単位で 1 milestone)。
--root
が指定されている場合は、ここで先に
ROOT_NUMBER
を設定し、milestone の 継承・書き込みを行う前に OPEN 状態を検証する(closed なルートの milestone を 書き換えてから中断する事故を防ぐ。Step 3 側では再代入・再検証しない)。
bash
undefined
确定为该树分配的GitHub Milestone。根Issue、Phase父Issue、子Issue、sub-issue均应用同一milestone(树级统一1个milestone)。
若指定了
--root
,需先在此处设置
ROOT_NUMBER
,并在继承/写入milestone前验证根Issue处于OPEN状态(避免出现修改已关闭根Issue的milestone后中断操作的问题。Step 3不再重复赋值与验证)。
bash
undefined

--root で渡された Issue 番号を実際の値で代入する(実行時に Claude が置き換える)

将--root传入的Issue编号替换为实际值(执行时由Claude替换)

例: --root 123 が指定された場合 → ROOT_NUMBER="123" / --root 未指定の場合 → ROOT_NUMBER=""

示例:指定--root 123时 → ROOT_NUMBER="123" / 未指定--root时 → ROOT_NUMBER=""

ROOT_NUMBER="<--root で渡された Issue 番号(未指定なら空文字)>"
ROOT_NUMBER="<--root传入的Issue编号(未指定则为空字符串)>"

--root 指定時のみ: OPEN でなければ milestone 操作より前に中止する

仅当指定--root时:若根Issue非OPEN状态,在milestone操作前终止

(新規ツリー作成で ROOT_NUMBER が空の場合はこの検証をスキップする)

(新建树且ROOT_NUMBER为空时跳过此验证)

if [[ -n "${ROOT_NUMBER}" ]]; then ROOT_STATE=$(gh issue view "${ROOT_NUMBER}" --json state --jq '.state') if [[ "${ROOT_STATE}" != "OPEN" ]]; then echo "エラー: ルート issue #${ROOT_NUMBER} は OPEN ではありません (state: ${ROOT_STATE})。中止します。" exit 1 fi fi

**milestone 非運用リポジトリのガード**: `--milestone` が明示されていない場合、リポジトリに
milestone が 1 件も存在しなければ(closed 含む)milestone 非運用リポジトリとみなし、
以降の確認をすべてスキップして `MILESTONE` は空のまま Step 3 へ進む
(milestone を使わないリポジトリの起票フローに確認を増やさない)。

```bash
MILESTONE_COUNT=$(gh api "repos/{owner}/{repo}/milestones?state=all" --jq 'length')
if [[ -n "${ROOT_NUMBER}" ]]; then ROOT_STATE=$(gh issue view "${ROOT_NUMBER}" --json state --jq '.state') if [[ "${ROOT_STATE}" != "OPEN" ]]; then echo "错误:根Issue #${ROOT_NUMBER} 不是OPEN状态(状态:${ROOT_STATE})。终止操作。" exit 1 fi fi

**非milestone运营仓库防护**: 若未指定`--milestone`,且仓库中不存在任何milestone(含已关闭),则视为非milestone运营仓库,跳过后续所有确认步骤,保持`MILESTONE`为空进入Step 3
(避免给不使用milestone的仓库增加额外确认步骤)。

```bash
MILESTONE_COUNT=$(gh api "repos/{owner}/{repo}/milestones?state=all" --jq 'length')

MILESTONE_COUNT が 0 かつ --milestone 未指定なら、このステップの残りをスキップする

若MILESTONE_COUNT为0且未指定--milestone,则跳过此步骤剩余操作


優先順位は **`--milestone` > `--root` からの継承 > ユーザーへの確認** の順。

- `--milestone` が指定されている場合: その値をそのまま `MILESTONE` として使用する
  (`--root` も同時指定されている場合、ルート側の milestone より `--milestone` を優先する。
  ルート側と異なる値の場合は、ルートの milestone も合わせて更新してよいかユーザーに確認する。
  更新しないと回答された場合はツリー内で milestone が混在する点を伝えたうえで続行する)
- `--milestone` 未指定かつ `--root` 指定時: 既存ルートの milestone を自動継承する
  (milestone が取得できた場合のみユーザーへの確認は不要)

  ```bash
  MILESTONE=$(gh issue view "${ROOT_NUMBER}" --json milestone --jq '.milestone.title // empty')
MILESTONE
が空(既存ルートに milestone が未設定)の場合は自動継承とみなさず、 「どちらも未指定の場合」と同じユーザー確認フローへ進む(リポジトリに milestone が 存在するのにサイレントに milestone なしで進行しない。milestone が 1 件もない場合は 冒頭の非運用ガードが先に働くため、この確認には到達しない)。
  • どちらも未指定の場合、または
    --root
    指定時に継承すべき milestone が空だった場合: milestone を割り当てるかユーザーに確認する。 割り当てる場合はオープン中の milestone 一覧を提示して選ばせるか、新規 milestone 名の 入力を受け付けて
    MILESTONE
    に設定する。割り当てないと回答されたら
    MILESTONE
    は 空のまま Step 3 以降へ進む(issue は milestone なしで作成される)。
    bash
    gh api "repos/{owner}/{repo}/milestones" --jq '.[] | select(.state=="open") | .title'
    ユーザーが一覧にない新規 milestone 名を入力した場合、
    gh issue create --milestone
    は 既存の milestone 名しか受け付けないため、使用前に milestone 自体を作成する。 同名の closed milestone が既に存在すると作成が 422(already_exists)で失敗するため、 その場合は reopen するか別名にするかをユーザーに確認する。
    bash
    gh api --method POST "repos/{owner}/{repo}/milestones" -f "title=${MILESTONE}"
    --root
    指定時に継承すべき milestone が空でこのフローに合流した場合、決定した
    MILESTONE
    を既存ルート issue にも反映する(子だけ milestone が付き、ルートが 未設定のまま残る不整合を防ぐ)。
    bash
    if [[ -n "${ROOT_NUMBER}" && -n "${MILESTONE}" ]]; then
      gh issue edit "${ROOT_NUMBER}" --milestone "${MILESTONE}"
    fi

优先级顺序为 **`--milestone` > 从`--root`继承 > 用户确认**:

- 若指定了`--milestone`:直接使用该值作为`MILESTONE`
  (若同时指定了`--root`,则`--milestone`优先级高于根Issue的milestone。若二者值不同,需询问用户是否同步更新根Issue的milestone。若用户选择不更新,则需告知用户树内milestone会存在不一致后再继续)
- 未指定`--milestone`但指定了`--root`:自动继承已有根Issue的milestone
  (成功获取到milestone时无需用户确认)

  ```bash
  MILESTONE=$(gh issue view "${ROOT_NUMBER}" --json milestone --jq '.milestone.title // empty')
MILESTONE
为空(已有根Issue未设置milestone),则不视为自动继承,进入「二者均未指定」的用户确认流程(避免仓库存在milestone却静默无milestone推进。若仓库无任何milestone,开头的非运营防护会先触发,不会进入此确认环节)。
  • 二者均未指定,或指定
    --root
    时无可用继承milestone: 询问用户是否分配milestone。若分配,则展示当前开放的milestone列表供用户选择,或接收用户输入的新milestone名称并设置为
    MILESTONE
    。若用户选择不分配,则保持
    MILESTONE
    为空进入Step 3以后的流程(Issue将无milestone创建)。
    bash
    gh api "repos/{owner}/{repo}/milestones" --jq '.[] | select(.state=="open") | .title'
    若用户输入列表中不存在的新milestone名称,由于
    gh issue create --milestone
    仅接受已存在的milestone名称,需先创建milestone本身。 若已存在同名的已关闭milestone,创建会因422(already_exists)失败,此时需询问用户是重新打开该milestone还是使用其他名称。
    bash
    gh api --method POST "repos/{owner}/{repo}/milestones" -f "title=${MILESTONE}"
    若指定
    --root
    且因无继承milestone进入此流程,确定
    MILESTONE
    后需同步更新已有根Issue的milestone(避免仅子Issue有milestone而根Issue未设置的不一致情况)。
    bash
    if [[ -n "${ROOT_NUMBER}" && -n "${MILESTONE}" ]]; then
      gh issue edit "${ROOT_NUMBER}" --milestone "${MILESTONE}"
    fi

Step 3: ルート(トラッキング)issue を作成する

Step 3: 创建根(追踪)Issue

ルート issue はツリー全体の進捗を管理するトラッキング issue として作成する。ルート issue 自体には phase ラベルは付与しない(Phase 親以下の issue にのみ付与する)。
--root
指定時は新規作成をスキップする。
--phase
での 2 回目以降の部分起票で ルート issue を重複作成しないため、Step 2.5 で設定・OPEN 検証済みの
ROOT_NUMBER
を そのまま再利用する(ここで再代入・再検証しない)。
--root
未指定の場合のみ、以下でルート issue を新規作成する。
bash
undefined
根Issue作为管理整个树进度的追踪Issue创建。根Issue本身不添加phase标签(仅Phase父及以下的Issue添加)。
指定
--root
时跳过新建操作。
为避免在
--phase
的第二次及以后部分发起时重复创建根Issue,直接复用Step 2.5中已设置并验证OPEN状态的
ROOT_NUMBER
(此处不再重复赋值与验证)。
仅当未指定
--root
时,按以下步骤新建根Issue:
bash
undefined

MILESTONE が空でなければ --milestone を付与する(Step 2.5 で決定済み)

若MILESTONE不为空,则添加--milestone参数(Step 2.5已确定)

ROOT_ARGS=(--title "chore: 全 open issue の Phase 別トラッキング ($(date +%Y-%m-%d))") if [[ -n "${MILESTONE}" ]]; then ROOT_ARGS+=(--milestone "${MILESTONE}") fi
ROOT_ARGS=(--title "chore: 所有open Issue的Phase别追踪 ($(date +%Y-%m-%d))") if [[ -n "${MILESTONE}" ]]; then ROOT_ARGS+=(--milestone "${MILESTONE}") fi

gh issue create は issue URL を stdout に出力する(--json 非対応)。URL 末尾から番号を抽出する

gh issue create会将Issue URL输出到stdout(不支持--json)。从URL末尾提取编号

ROOT_URL=$(gh issue create "${ROOT_ARGS[@]}"
--body "$(cat <<'EOF'
ROOT_URL=$(gh issue create "${ROOT_ARGS[@]}"
--body "$(cat <<'EOF'

概要

概述

全 open issue を Phase 別に 1 ツリーへ整理する。各 Phase 親 issue を sub-issues として紐付け。
将所有open Issue按Phase整理为一个树结构。各Phase父Issue作为sub-issues关联到根Issue。

Phase 別実装計画

Phase别实施计划

Phase親 issue直下総 open 件数
(作成後に更新)
Phase父Issue直接子Issue数总open数量
(创建后更新)

運用

运营规则

  • 新規 issue は起票時に Phase 親へ紐付ける
  • 実行順は sub-issues リスト順が正
  • closed 親の下に open issue を残置しない
  • implement-issue-tree が post-order DFS で消化可能な構造を維持する EOF )") ROOT_NUMBER=$(printf '%s' "${ROOT_URL}" | grep -oE '[0-9]+$') echo "ルート issue: ${ROOT_NUMBER}"
undefined
  • 新Issue发起时需关联到对应Phase父Issue
  • 执行顺序以sub-issues列表顺序为准
  • 已关闭的父Issue下不得遗留open Issue
  • 维持可被implement-issue-tree通过后序DFS处理的结构 EOF )") ROOT_NUMBER=$(printf '%s' "${ROOT_URL}" | grep -oE '[0-9]+$') echo "根Issue: ${ROOT_NUMBER}"
undefined

Step 4: Phase 親 issue を作成して紐付ける

Step 4: 创建Phase父Issue并关联

Phase ごとに親 issue を作成し、sub_issues API でルートへ紐付ける。 以下のスニペットは
PHASE
変数で Phase 番号を切り替える。
--phase
指定時はその番号を、 全 Phase 起票時は処理中の Phase 番号を設定する(タイトル・ラベルとも
PHASE
に追従させる)。
bash
undefined
为每个Phase创建父Issue,通过sub_issues API关联到根Issue。 以下代码片段通过
PHASE
变量切换Phase编号。指定
--phase
时设置为对应编号,全Phase发起时设置为当前处理的Phase编号(标题与标签均跟随
PHASE
)。
bash
undefined

処理対象の Phase 番号(--phase 指定時はその番号、全 Phase 起票時はループ中の番号)

当前处理的Phase编号(指定--phase时为该编号,全Phase发起时为循环中的编号)

PHASE=1
PHASE=1

phase ラベルが存在しないリポジトリでは issue 作成が失敗するため、必ず事前作成する

若仓库中不存在phase标签,Issue创建会失败,因此必须提前创建

(作成済みの場合は失敗を無視して続行する)

(若已存在则忽略错误继续执行)

gh label create "phase:${PHASE}" --color "0075ca" 2>/dev/null || true
gh label create "phase:${PHASE}" --color "0075ca" 2>/dev/null || true

--root 再実行時の重複防止: ルート直下に同じ Phase の open な親が既にあれば再利用する

避免--root重复执行时创建重复项:若根Issue下已存在同Phase的open父Issue,则复用

closed な親は再利用しない(closed 親の下に open issue を残置しない運用ルールと整合させる)。

不复用已关闭的父Issue(与「已关闭父Issue下不得遗留open Issue」的运营规则保持一致)。

phase ラベルだけでは同ラベルの一般 issue がルート直下に混在した場合に誤マッチするため、

仅靠phase标签可能会误匹配根Issue下的普通同标签Issue,因此同时通过Phase父Issue的标题规则(feat(phase-N):前缀)筛选。

Phase 親のタイトル規約(feat(phase-N): 接頭辞)でも絞り込む。

为应对子Issue超过100件的情况,通过分页遍历所有子Issue

直下が 100 件を超える場合に備えてページングで全件走査する

PHASE_NUMBER="" PAGE=1 while true; do RESULT=$(gh api
"repos/{owner}/{repo}/issues/${ROOT_NUMBER}/sub_issues?per_page=100&page=${PAGE}") PHASE_NUMBER=$(echo "${RESULT}" | jq -r
"[.[] | select(.state == "open" and (.title | startswith("feat(phase-${PHASE}):")) and any(.labels[]?; .name == "phase:${PHASE}"))][0].number // empty") COUNT=$(echo "${RESULT}" | jq 'length') if [[ -n "${PHASE_NUMBER}" || "${COUNT}" -lt 100 ]]; then break; fi PAGE=$((PAGE + 1)) done [[ -n "${PHASE_NUMBER}" ]] && echo "既存の Phase 親 issue を再利用: #${PHASE_NUMBER}"
PHASE_NUMBER="" PAGE=1 while true; do RESULT=$(gh api
"repos/{owner}/{repo}/issues/${ROOT_NUMBER}/sub_issues?per_page=100&page=${PAGE}") PHASE_NUMBER=$(echo "${RESULT}" | jq -r
"[.[] | select(.state == "open" and (.title | startswith("feat(phase-${PHASE}):")) and any(.labels[]?; .name == "phase:${PHASE}"))][0].number // empty") COUNT=$(echo "${RESULT}" | jq 'length') if [[ -n "${PHASE_NUMBER}" || "${COUNT}" -lt 100 ]]; then break; fi PAGE=$((PAGE + 1)) done [[ -n "${PHASE_NUMBER}" ]] && echo "复用已有的Phase父Issue: #${PHASE_NUMBER}"

再利用する Phase 親が milestone 未設定の場合はここで揃える(milestone 導入前に

若复用的Phase父Issue未设置milestone,在此处统一设置(避免给milestone引入前创建的树追加Issue时,仅新子Issue有milestone的不一致问题。此操作幂等)

作られたツリーへの追記で、新規の子だけに milestone が付く不整合を防ぐ。冪等)

if [[ -n "${PHASE_NUMBER}" && -n "${MILESTONE}" ]]; then gh issue edit "${PHASE_NUMBER}" --milestone "${MILESTONE}" fi

タイトル規約が `feat(phase-N):` と異なるツリーでは上記の自動判定に頼らず、候補をユーザーに
提示して再利用すべき Phase 親を確認する。

`PHASE_NUMBER` が空(既存の Phase 親がない)場合のみ、以下で新規作成してルートへ紐付ける。

```bash
if [[ -n "${PHASE_NUMBER}" && -n "${MILESTONE}" ]]; then gh issue edit "${PHASE_NUMBER}" --milestone "${MILESTONE}" fi

若树的标题规则与`feat(phase-N):`不同,则不依赖上述自动判定,而是将候选Issue展示给用户,确认需复用的Phase父Issue。

仅当`PHASE_NUMBER`为空(无已存在的Phase父Issue)时,按以下步骤新建并关联到根Issue:

```bash

MILESTONE が空でなければ --milestone を付与する(Step 2.5 で決定済み)

若MILESTONE不为空,则添加--milestone参数(Step 2.5已确定)

PHASE_ARGS=(--title "feat(phase-${PHASE}): Phase ${PHASE} 基盤整備" --label "phase:${PHASE}") if [[ -n "${MILESTONE}" ]]; then PHASE_ARGS+=(--milestone "${MILESTONE}") fi
PHASE_ARGS=(--title "feat(phase-${PHASE}): Phase ${PHASE} 基础架构搭建" --label "phase:${PHASE}") if [[ -n "${MILESTONE}" ]]; then PHASE_ARGS+=(--milestone "${MILESTONE}") fi

Phase 親 issue を作成(URL 末尾から番号を抽出)

创建Phase父Issue(从URL末尾提取编号)

PHASE_URL=$(gh issue create "${PHASE_ARGS[@]}"
--body "$(cat <<'EOF'
PHASE_URL=$(gh issue create "${PHASE_ARGS[@]}"
--body "$(cat <<'EOF'

概要

概述

この Phase の実装タスクをまとめる親 issue。
汇总该Phase所有实现任务的父Issue。

タスク一覧

任务列表

Issueタイトル分解
(子 issue 作成後に更新)
EOF
)")
PHASE_NUMBER=$(printf '%s' "${PHASE_URL}"grep -oE '[0-9]+$')
Issue标题分解情况
(子Issue创建后更新)
EOF
)")
PHASE_NUMBER=$(printf '%s' "${PHASE_URL}"grep -oE '[0-9]+$')

ルートへ紐付け。sub_issue_id は issue 番号ではなく database id を渡す(GitHub sub-issues API 仕様)

关联到根Issue。sub_issue_id需传入database id而非Issue编号(GitHub sub-issues API规范)

PHASE_ID=$(gh api "repos/{owner}/{repo}/issues/${PHASE_NUMBER}" --jq '.id') gh api
--method POST
"repos/{owner}/{repo}/issues/${ROOT_NUMBER}/sub_issues"
-F "sub_issue_id=${PHASE_ID}"
undefined
PHASE_ID=$(gh api "repos/{owner}/{repo}/issues/${PHASE_NUMBER}" --jq '.id') gh api
--method POST
"repos/{owner}/{repo}/issues/${ROOT_NUMBER}/sub_issues"
-F "sub_issue_id=${PHASE_ID}"
undefined

Step 5: 子 issue・sub-issue を作成して紐付ける

Step 5: 创建子Issue・sub-issue并关联

各タスクを issue として作成し、Phase 親へ紐付ける。4h 超のタスクはさらに sub-issue に分解する。
bash
undefined
将每个任务创建为Issue,关联到对应Phase父Issue。超过4小时工作量的任务需进一步分解为sub-issue。
bash
undefined

MILESTONE が空でなければ --milestone を付与する(Step 2.5 で決定済み)

若MILESTONE不为空,则添加--milestone参数(Step 2.5已确定)

CHILD_ARGS=(--title "feat: タスク名" --label "phase:${PHASE}") if [[ -n "${MILESTONE}" ]]; then CHILD_ARGS+=(--milestone "${MILESTONE}") fi
CHILD_ARGS=(--title "feat: 任务名称" --label "phase:${PHASE}") if [[ -n "${MILESTONE}" ]]; then CHILD_ARGS+=(--milestone "${MILESTONE}") fi

子 issue を作成(URL 末尾から番号を抽出)。PHASE は Step 4 で設定した番号を引き継ぐ

创建子Issue(从URL末尾提取编号)。PHASE沿用Step 4设置的编号

CHILD_URL=$(gh issue create "${CHILD_ARGS[@]}"
--body "$(cat <<'EOF'
CHILD_URL=$(gh issue create "${CHILD_ARGS[@]}"
--body "$(cat <<'EOF'

概要

概述

...
...

受け入れ条件

验收条件

  • 条件1
  • 条件2 EOF )") CHILD_NUMBER=$(printf '%s' "${CHILD_URL}" | grep -oE '[0-9]+$')
  • 条件1
  • 条件2 EOF )") CHILD_NUMBER=$(printf '%s' "${CHILD_URL}" | grep -oE '[0-9]+$')

Phase 親へ紐付け(sub_issue_id は database id)

关联到Phase父Issue(sub_issue_id需传入database id)

CHILD_ID=$(gh api "repos/{owner}/{repo}/issues/${CHILD_NUMBER}" --jq '.id') gh api
--method POST
"repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues"
-F "sub_issue_id=${CHILD_ID}"
CHILD_ID=$(gh api "repos/{owner}/{repo}/issues/${CHILD_NUMBER}" --jq '.id') gh api
--method POST
"repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues"
-F "sub_issue_id=${CHILD_ID}"

4h 超の場合は sub-issue を作成して子 issue へ紐付け(同じく MILESTONE を付与)

若任务超过4小时,则创建sub-issue并关联到子Issue(同样添加MILESTONE)

SUB_ARGS=(--title "feat: サブタスク名" --label "phase:${PHASE}") if [[ -n "${MILESTONE}" ]]; then SUB_ARGS+=(--milestone "${MILESTONE}") fi SUB_URL=$(gh issue create "${SUB_ARGS[@]}" --body "...") SUB_NUMBER=$(printf '%s' "${SUB_URL}" | grep -oE '[0-9]+$')
SUB_ID=$(gh api "repos/{owner}/{repo}/issues/${SUB_NUMBER}" --jq '.id') gh api
--method POST
"repos/{owner}/{repo}/issues/${CHILD_NUMBER}/sub_issues"
-F "sub_issue_id=${SUB_ID}"

issue 数が多い場合(50 件超が目安)は `per_page=100` パラメータを使用し、ページネーションで全件確認する。

```bash
SUB_ARGS=(--title "feat: 子任务名称" --label "phase:${PHASE}") if [[ -n "${MILESTONE}" ]]; then SUB_ARGS+=(--milestone "${MILESTONE}") fi SUB_URL=$(gh issue create "${SUB_ARGS[@]}" --body "...") SUB_NUMBER=$(printf '%s' "${SUB_URL}" | grep -oE '[0-9]+$')
SUB_ID=$(gh api "repos/{owner}/{repo}/issues/${SUB_NUMBER}" --jq '.id') gh api
--method POST
"repos/{owner}/{repo}/issues/${CHILD_NUMBER}/sub_issues"
-F "sub_issue_id=${SUB_ID}"

若Issue数量较多(参考标准:超过50件),需使用`per_page=100`参数,通过分页遍历所有Issue。

```bash

ページネーション例(全 sub-issues を取得)

分页示例(获取所有sub-issues)

PAGE=1 while true; do RESULT=$(gh api
"repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues?per_page=100&page=${PAGE}") COUNT=$(echo "${RESULT}" | jq 'length') echo "${RESULT}" if [ "${COUNT}" -lt 100 ]; then break; fi PAGE=$((PAGE + 1)) done
undefined
PAGE=1 while true; do RESULT=$(gh api
"repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues?per_page=100&page=${PAGE}") COUNT=$(echo "${RESULT}" | jq 'length') echo "${RESULT}" if [ "${COUNT}" -lt 100 ]; then break; fi PAGE=$((PAGE + 1)) done
undefined

Step 6: ルート issue 本文を Phase 別表で更新する

Step 6: 更新根Issue正文的Phase别表格

全 issue の作成が完了したら、ルート issue 本文の Phase 別表を実際の issue 番号・件数で更新する。
--root
での部分起票では本文を全置換しない。
既存ルートの本文には先行 Phase の表が 含まれるため、現在の本文を取得し、今回起票した Phase の行・セクションのみを追記・更新した 本文で
gh issue edit
する。以下の全置換テンプレートは新規作成(
--root
未指定)時のみ使う。
bash
undefined
所有Issue创建完成后,将根Issue正文的Phase别表格更新为实际的Issue编号与数量。
通过
--root
进行部分发起时,不替换整个正文。
已有根Issue的正文包含之前Phase的表格,因此需获取当前正文,仅追加/更新本次发起的Phase行与章节,再通过
gh issue edit
更新。以下全替换模板仅在新建(未指定
--root
)时使用。
bash
undefined

--root 指定時: 既存本文を取得し、今回の Phase 分をマージしてから編集する

指定--root时:获取已有正文,合并本次Phase内容后再编辑

CURRENT_BODY=$(gh issue view "${ROOT_NUMBER}" --json body --jq '.body')
CURRENT_BODY=$(gh issue view "${ROOT_NUMBER}" --json body --jq '.body')

CURRENT_BODY の「Phase 別実装計画」表へ今回の Phase 行を追記し、

在CURRENT_BODY的「Phase别实施计划」表格中追加本次Phase的行,并添加「### Phase N」章节,组合成新正文后传入gh issue edit --body。

「### Phase N」セクションを追加した本文を組み立てて gh issue edit --body に渡す。

若需要盘点已有树,也可委托给update-issue-tree处理

既存ツリーの棚卸しを伴う場合は update-issue-tree への委譲でもよい


`--root` 未指定(新規作成)の場合は以下で全体を更新する。

```bash
gh issue edit "${ROOT_NUMBER}" --body "$(cat <<'EOF'

未指定`--root`(新建)时,按以下步骤更新整个正文:

```bash
gh issue edit "${ROOT_NUMBER}" --body "$(cat <<'EOF'

概要

概述

全 open issue を Phase 別に 1 ツリーへ整理する。各 Phase 親 issue を sub-issues として紐付け。
将所有open Issue按Phase整理为一个树结构。各Phase父Issue作为sub-issues关联到根Issue。

Phase 別実装計画

Phase别实施计划

Phase親 issue直下総 open 件数
Phase 1#<phase1_number> タイトルNN
Phase 2#<phase2_number> タイトルNN
Phase父Issue直接子Issue数总open数量
Phase 1#<phase1_number> 标题NN
Phase 2#<phase2_number> 标题NN

Phase 1: 基盤整備

Phase 1: 基础架构搭建

Issueタイトル分解
#Nタイトル-
#Nタイトルsub-issue あり
Issue标题分解情况
#N标题-
#N标题存在sub-issue

運用

运营规则

  • 新規 issue は起票時に Phase 親へ紐付ける
  • 実行順は sub-issues リスト順が正
  • closed 親の下に open issue を残置しない
  • implement-issue-tree が post-order DFS で消化可能な構造を維持する EOF )"
undefined
  • 新Issue发起时需关联到对应Phase父Issue
  • 执行顺序以sub-issues列表顺序为准
  • 已关闭的父Issue下不得遗留open Issue
  • 维持可被implement-issue-tree通过后序DFS处理的结构 EOF )"
undefined

Step 7: 作成結果を報告する

Step 7: 报告创建结果

undefined
undefined

create-issue-tree 完了レポート

create-issue-tree 完成报告

ルート issue

根Issue

  • #N: タイトル
  • #N: 标题

Phase 別作成サマリー

Phase别创建汇总

Phase親 issue起票数
Phase 1#NN 件
Phase父Issue发起数量
Phase 1#NN 件

作成した issue 一覧

创建的Issue列表

  • #N: タイトル(Phase 1 / 親: #M) ...
  • #N: 标题(Phase 1 / 父Issue: #M) ...

次のアクション

后续操作

  • 実装消化: implement-issue-tree スキルに ルート issue 番号を渡す
  • ツリー更新: update-issue-tree スキルでトラッキング issue を棚卸しする
undefined
  • 任务落地:将根Issue编号传入implement-issue-tree技能
  • 树更新:使用update-issue-tree技能盘点追踪Issue
undefined

検証

验证

  • ルート issue の sub-issues に各 Phase 親 issue が列挙されていることを確認する
  • 各 Phase 親 issue の sub-issues に子 issue が列挙されていることを確認する
  • gh issue view "${ROOT_NUMBER}"
    でルート issue 本文の Phase 別表が正しく生成されていることを確認する
  • MILESTONE
    を割り当てた場合、
    gh issue view <N> --json milestone --jq '.milestone.title'
    でルート・Phase 親・子いずれも
    ${MILESTONE}
    と一致することを確認する
bash
undefined
  • 确认根Issue的sub-issues中列出了各Phase父Issue
  • 确认各Phase父Issue的sub-issues中列出了子Issue
  • 通过
    gh issue view "${ROOT_NUMBER}"
    确认根Issue正文的Phase别表格生成正确
  • 若分配了
    MILESTONE
    ,通过
    gh issue view <N> --json milestone --jq '.milestone.title'
    确认根Issue、Phase父Issue、子Issue的milestone均与
    ${MILESTONE}
    一致
bash
undefined

sub-issues は 1 ページ最大 100 件。100 件超のツリーは Step 5 のページネーション

sub-issues每页最多100件。超过100件的树需通过Step 5的分页

ループで全件確認する(以下は per_page=100 で先頭ページのみ。件数が 100 未満なら全件)

循环遍历所有Issue(以下为per_page=100时仅获取第一页。若数量少于100则为全部)

ルート直下の sub-issues を確認

确认根Issue下的sub-issues

gh api "repos/{owner}/{repo}/issues/${ROOT_NUMBER}/sub_issues?per_page=100" --jq '.[].number'
gh api "repos/{owner}/{repo}/issues/${ROOT_NUMBER}/sub_issues?per_page=100" --jq '.[].number'

Phase 親直下の sub-issues を確認

确认Phase父Issue下的sub-issues

gh api "repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues?per_page=100" --jq '.[].number'
gh api "repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues?per_page=100" --jq '.[].number'

phase ラベルの同期確認(Phase 親・子 issue にラベルが付いているか確認)

确认phase标签同步(Phase父Issue、子Issue均已添加标签)

gh api "repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues?per_page=100"
--jq '.[] | {number: .number, labels: [.labels[].name]}'
undefined
gh api "repos/{owner}/{repo}/issues/${PHASE_NUMBER}/sub_issues?per_page=100"
--jq '.[] | {number: .number, labels: [.labels[].name]}'
undefined

よくある失敗

常见问题

問題回避策
--root
を指定せず 2 回目の部分起票でルート issue が重複作成される
2 回目以降は必ず
--root <既存ルートissue番号>
を渡す
sub_issue_id
に issue 番号をそのまま渡す
gh api .../issues/<number> --jq '.id'
で database id を取得してから POST する
phase ラベルが存在しないリポジトリで issue 作成が失敗するStep 4 冒頭の
gh label create "phase:${PHASE}"
を必ず先に実行する
--root
追記時に既存ルートの milestone が未設定なのに気づかず milestone なしで起票してしまう
リポジトリに milestone が存在する場合、Step 2.5 は継承結果が空ならユーザー確認フローへ自動的に合流する(確認で milestone を選ぶとルート issue にも反映される)。milestone が 1 件もない非運用リポジトリでは非運用ガードによる milestone なし起票が正常動作
closed 親の下に open issue が残置されるPhase 親を close する前に全子 issue の close を確認する
问题解决方法
未指定
--root
进行第二次部分发起时,重复创建了根Issue
第二次及以后发起必须传入
--root <已有根Issue编号>
直接将Issue编号传入
sub_issue_id
通过
gh api .../issues/<number> --jq '.id'
获取database id后再POST
仓库中不存在phase标签导致Issue创建失败必须先执行Step 4开头的
gh label create "phase:${PHASE}"
通过
--root
追加Issue时,未注意到已有根Issue未设置milestone,导致无milestone发起
若仓库存在milestone,Step 2.5会在继承结果为空时自动进入用户确认流程(用户选择milestone后会同步更新根Issue)。无任何milestone的非运营仓库会通过非运营防护正常发起无milestone的Issue
已关闭的父Issue下遗留了open Issue关闭Phase父Issue前需确认所有子Issue已关闭

注意事項

注意事项

  • 1 issue は 4h 程度に収める。 4h を超えると判断した場合は sub-issue に分解する
  • issue タイトルは Conventional Commits 形式を推奨(
    feat:
    fix:
    chore:
    等)
  • --phase
    指定で部分起票した場合、別 Phase の追加起票では 必ず
    --root <既存ルートissue番号>
    を渡す
    (Step 3 の新規作成をスキップして既存ツリーへ継ぎ足し、Step 6 も全置換せず既存本文へ差分追記する)。起票後は update-issue-tree に同じルート issue 番号を渡して棚卸しする
  • ページネーション: sub-issues が 100 件を超える場合は
    per_page=100&page=N
    でページングして全件取得する
  • シェルコマンドの変数は必ず
    "${var}"
    でクォートする(コマンドインジェクション対策)
  • --no-verify
    は絶対に使用しない
  • gh issue create
    --json
    非対応
    。issue URL を stdout に出力するため、
    | grep -oE '[0-9]+$'
    で末尾の番号を抽出して変数に保持する
  • sub_issues API の
    sub_issue_id
    は issue 番号ではなく database id
    (GitHub 仕様)。
    gh api "repos/{owner}/{repo}/issues/<number>" --jq '.id'
    で id を取得してから POST する。番号をそのまま渡すと誤った issue を紐付ける/404 になる
  • phase ラベルは Step 4 冒頭の
    gh label create "phase:${PHASE}" --color "0075ca"
    で issue 作成より前に必ず作成する(作成済みリポジトリでは no-op)
  • 1个Issue的工作量控制在4小时左右。 若判断超过4小时,需分解为sub-issue
  • Issue标题推荐使用Conventional Commits格式(
    feat:
    fix:
    chore:
    等)
  • 通过
    --phase
    指定部分发起后,追加其他Phase时必须传入
    --root <已有根Issue编号>
    (跳过Step 3的新建操作,追加到已有树中,Step 6也不会全替换正文而是追加差分)。发起后需将同一根Issue编号传入update-issue-tree进行盘点
  • 分页处理:若sub-issues超过100件,需使用
    per_page=100&page=N
    分页获取所有Issue
  • 脚本变量必须用
    "${var}"
    包裹(防止命令注入)
  • 绝对禁止使用
    --no-verify
  • gh issue create
    不支持
    --json
    。会将Issue URL输出到stdout,需通过
    | grep -oE '[0-9]+$'
    提取末尾的编号并保存到变量中
  • sub_issues API的
    sub_issue_id
    需传入database id而非Issue编号
    (GitHub规范)。通过
    gh api "repos/{owner}/{repo}/issues/<number>" --jq '.id'
    获取id后再POST。直接传入编号会导致关联错误的Issue或返回404
  • phase标签必须在Issue创建前通过Step 4开头的
    gh label create "phase:${PHASE}" --color "0075ca"
    创建(已存在的仓库中此操作为空操作)