GitHub Projects(V2)と gh CLI を組み合わせて、Issue を Epic / Story / Task の3階層で管理する方法を紹介します。
実際のプロジェクトで運用してみて分かったコツや、Sub-issues を使った親子関係の設定方法も含めてまとめました。
なぜ GitHub Projects なのか
Notion や Jira を使う選択肢もありますが、コードと課題管理が同じ場所にあるメリットは大きいです。
- PR に
Closes #12と書くだけで Issue が自動クローズされる -
ghCLI でターミナルから Issue 作成・編集が完結する - Sub-issues 機能で親子関係がネイティブに表現できる(2024年〜)
- Iteration(スプリント)・カスタムフィールド・Insights が標準搭載
「ブラウザを開かなくても、CLI だけでプロジェクト管理が回る」のが最大の利点です。
前提:gh CLI のセットアップ
# インストール
brew install gh
# ログイン
gh auth login
# Projects 操作に必要なスコープを追加(初回のみ)
gh auth refresh -s project,read:project
1. ラベル設計 — フェーズ × 種別の2軸
Issue を分類するために、フェーズラベルと種別ラベルの2軸でラベルを設計します。
フェーズラベル(いつやるか)
| ラベル | 色 | 意味 |
|---|---|---|
第1弾 |
🟢 緑 | MVP・最初のリリース |
第2弾 |
🔵 青 | 次の機能追加 |
第3弾 |
🟡 黄 | 自動化・効率化 |
第4弾 |
🔴 赤 | 将来検討 |
種別ラベル(何のレベルか)
| ラベル | 色 | 粒度 |
|---|---|---|
Epic |
🟣 紫 | フェーズのゴール |
Story |
🔵 青 | ユーザー価値の単位 |
Task |
🟡 黄 | 1〜3日で終わる作業 |
# ラベル作成の例
gh label create "Epic" --color "6A0DAD" --description "フェーズのゴール単位"
gh label create "Story" --color "0075CA" --description "ユーザー価値単位"
gh label create "Task" --color "E4E669" --description "作業単位"
gh label create "第1弾" --color "0E8A16" --description "フェーズ1"
ポイント: フェーズラベルと種別ラベルを必ず両方付けることで、「第2弾の Story 一覧」のようなフィルタリングが簡単にできます。
2. Issue の3階層 — Epic / Story / Task
各レベルの判断基準
| レベル | 判断基準 | テンプレート |
|---|---|---|
| Epic | 「〇〇ができる状態」と表現できる | ゴール + 完了の定義 |
| Story | 「〇〇として、△△したい」と表現できる | ユーザーストーリー + 受け入れ条件 |
| Task | 1人が1〜3日で完了できる | 概要 + 完了条件チェックリスト |
具体例:階層の分解
[Epic] Looker Studio でセグメント別集計ができる
├── [Story] 既存の運用を把握し、接続方式を設計する
│ ├── [Task] データ形式(Wide/Long)を確定する
│ └── [Task] JOIN キーを決定する
└── [Story] セグメントデータを Looker に反映する
├── [Task] 同期スクリプトを実装する
└── [Task] Looker 上で動作確認する
Issue の作成(下から順に)
重要: Task → Story → Epic の順に作成します。先に子を作っておくことで、親の本文に #番号 で参照を書けます。
Task を作成
gh issue create \
--title "データ形式(Wide/Long)を確定する" \
--label "第2弾" --label "Task" \
--body "$(cat <<'EOF'
## 概要
Looker Studio のデータソースとして最適な形式を決定する。
## 完了条件
- [ ] Wide/Long の比較表を作成
- [ ] チームで合意
EOF
)"
Story を作成
gh issue create \
--title "[Story] 既存Looker運用を把握し接続方式を設計する" \
--label "第2弾" --label "Story" \
--body "$(cat <<'EOF'
## ユーザーストーリー
開発者として、既存の Looker 運用を理解し、新しいデータの接続方式を設計したい。
## 受け入れ条件
- データ形式が確定している
- JOIN キーが決定している
## Tasks
- #10 データ形式(Wide/Long)を確定する
- #11 JOIN キーを決定する
EOF
)"
Epic を作成
gh issue create \
--title "[Epic] Looker Studioでセグメント別集計ができる" \
--label "第2弾" --label "Epic" \
--body "$(cat <<'EOF'
## ゴール
Looker Studio 上でセグメント別の絞り込み・集計ができる状態を作る。
## 完了の定義
- Looker Studio でセグメント別フィルタが動作する
- テストデータで動作確認済み
## Stories
- 既存Looker運用を把握し接続方式を設計する
- セグメントデータを Looker に反映する
EOF
)"
3. Sub-issues で親子関係を設定する
GitHub の Sub-issues 機能を使うと、Issue 間に親子関係を持たせることができます。Project ボード上で「Sub-issues progress」として進捗バーが表示されるのが便利です。
設定には GraphQL API を使います。
# ① 親 Issue の node ID を取得
PARENT_ID=$(gh api graphql -f query='query {
repository(owner:"YOUR_ORG", name:"YOUR_REPO") {
issue(number:12) { id }
}
}' --jq '.data.repository.issue.id')
# ② 子 Issue の node ID を取得
CHILD_ID=$(gh api graphql -f query='query {
repository(owner:"YOUR_ORG", name:"YOUR_REPO") {
issue(number:10) { id }
}
}' --jq '.data.repository.issue.id')
# ③ 紐付け
gh api graphql -f query="mutation {
addSubIssue(input: { issueId: \"$PARENT_ID\", subIssueId: \"$CHILD_ID\" }) {
issue { number }
subIssue { number }
}
}"
ヘルパー関数を作っておくと楽
.bashrc や .zshrc に以下を追加しておくと、繰り返し使えます。
# node ID 取得
get_node_id() {
gh api graphql \
-f query="query { repository(owner:\"YOUR_ORG\", name:\"YOUR_REPO\") { issue(number:$1) { id } } }" \
--jq '.data.repository.issue.id'
}
# Sub-issue 紐付け
add_sub_issue() {
gh api graphql \
-f query="mutation { addSubIssue(input: { issueId: \"$1\", subIssueId: \"$2\" }) { issue { number } subIssue { number } } }" \
--jq '.data.addSubIssue | "#\(.issue.number) <- #\(.subIssue.number)"'
}
# 使い方
add_sub_issue "$(get_node_id 12)" "$(get_node_id 10)"
# => #12 <- #10
4. Project ボードに追加する
Issue を作っただけでは Project ボードに表示されません。明示的に追加する必要があります。
# 1件ずつ追加
gh project item-add 29 --owner YOUR_ORG \
--url "https://github.com/YOUR_ORG/YOUR_REPO/issues/10"
# まとめて追加(シェルのループ)
for i in 10 11 12 13 14; do
gh project item-add 29 --owner YOUR_ORG \
--url "https://github.com/YOUR_ORG/YOUR_REPO/issues/$i"
done
忘れがちポイント: Issue 作成後に Project への追加を忘れると、ボード上に表示されません。作成と追加はセットで行いましょう。
5. Project ボードの View を使い分ける
ラベルと種別を分けて設計したことで、View のフィルタが効果的に使えます。
| View 名 | フィルタ | 用途 |
|---|---|---|
| Epics | label:Epic |
フェーズ単位のゴール一覧 |
| Stories | label:Story |
ユーザー価値の進捗確認 |
| Sprint Board |
label:Task + Iteration で絞り込み |
今スプリントの作業 |
| Roadmap | 全件、Start/End で時系列表示 | 全体の見通し |
ロードマップビューの作成
- Project 画面で「+ New view」→「Roadmap」を選択
- Date fields に
Start/Endカスタムフィールドを設定 - Group by:
Phaseを選択
これで「どのフェーズが、いつからいつまでか」がガントチャート風に見えます。
6. スプリント管理(Iteration フィールド)
GitHub Projects の Iteration フィールド型を使うと、スプリント単位の管理ができます。
セットアップ
- Project の「+ Add field」→ Field name:
Sprint、Type: Iteration - Duration を設定(例: 2 weeks)
- 同様に
Story Points(Type: Number)も作成
ストーリーポイントの可視化
- Sum 機能: Group by Sprint にすると、各スプリントのポイント合計がヘッダーに表示される
-
Insights: 「New chart」→ Y-axis に
Sum of Story Points、Group byStatusで消化グラフが作れる
ポイントの基準
| Story Points | 目安 | 備考 |
|---|---|---|
| 1〜3 | 1日以内 | 小さなタスク |
| 5 | 3日以内 | 標準的なタスク |
| 8以上 | スプリントを跨ぐ | 分割を検討する |
7. 開発フロー(Issue → Branch → PR → Close)
# 1. Issue に対応するブランチを作成
git checkout -b issue/10-fix-data-format
# 2. 作業してコミット
git add .
git commit -m "データ形式を Wide に確定する (#10)"
# 3. Push して PR を作成
git push -u origin issue/10-fix-data-format
gh pr create --title "データ形式を Wide に確定する" --body "Closes #10"
# 4. マージ後にクリーンアップ
git checkout main && git pull
git branch -d issue/10-fix-data-format
PR に Closes #10 と書くことで、マージ時に Issue が自動でクローズされます。
8. Milestone でリリース日を管理する
Iteration(スプリント)が「作業の区切り」なら、Milestone は「絶対的な納期」です。
# Milestone を作成
gh api repos/YOUR_ORG/YOUR_REPO/milestones \
--method POST \
-f title="第1弾リリース" \
-f due_on="2026-04-01T00:00:00Z" \
-f description="スプレッドシートでの週次提供を開始"
# Issue に Milestone を設定
gh issue edit 10 --milestone "第1弾リリース"
| 概念 | 用途 | 例 |
|---|---|---|
| Iteration(Sprint) | 作業の区切り(2週間ごと) | Sprint 1, Sprint 2 |
| Milestone | リリース日・納期 | 第1弾リリース |
この2つを組み合わせることで、「この納期までに、あと何スプリント分の作業があるか?」が見えるようになります。
よく使うコマンドまとめ
# Issue 操作
gh issue list # 一覧
gh issue list --label "第2弾" --label "Task" # フィルタ
gh issue view 10 # 詳細表示
gh issue view 10 --web # ブラウザで開く
gh issue create --title "..." --label "..." --body "..." # 作成
gh issue edit 10 --add-label "第2弾" # ラベル追加
gh issue edit 10 --add-assignee "@me" # アサイン
gh issue comment 10 --body "進捗: 完了" # コメント
gh issue close 10 # クローズ
# Project 操作
gh project view 29 --owner YOUR_ORG --web # ボードを開く
gh project item-add 29 --owner YOUR_ORG --url <URL> # Issue を追加
# ラベル操作
gh label list # 一覧
gh label create "名前" --color "FFFFFF" # 作成
まとめ
GitHub Projects を使った階層管理のポイントは3つです。
- ラベル2軸(フェーズ × 種別)で、フィルタとビューを使い分ける
- Sub-issues で親子関係を持たせ、進捗バーで完了度を可視化する
-
ghCLI で Issue 作成から Project 追加まで、ターミナルで完結させる
Jira ほどの複雑さは不要だけど、フラットな Issue 管理では物足りない — そんなチームにとって、GitHub Projects + Sub-issues の組み合わせはちょうどいい選択肢になるはずです。