GitHub Projects ガントチャート(Roadmap)完全ガイド2026 — 自動化コード付き、フリーランスの複数案件管理まで

GitHub Projects ガントチャート(Roadmap)完全ガイド2026 — 自動化コード付き、フリーランスの複数案件管理まで

GitHub ProjectsのRoadmapビュー(タイムライン/ガントチャート)の設定手順から、GitHub Actions自動化・Sub-issues対応・フリーランスの複数案件管理パターンまで2026年最新仕様で解説。できないことの正直な整理と代替策も含む。

エンジニアのゆとです。

GitHub Projects の Roadmap ビューを「ガントチャートとして実務で使えるか」について調べている人向けに書く。

検索すると「Roadmapビューの設定手順」を説明した初心者向け記事は大量にある。でも「どんな場面で使うべきか」「GitHub Actionsで自動化するにはどうするか」「できないことは何か」まで踏み込んだ記事がほとんどない。

この記事は、GitHub を普段から使っているエンジニアが実務判断をするための情報にフォーカスする。フリーランスで複数案件を持っている場合の設計パターンと、GitHub Actions を使った自動化コードも含めて書く。

GitHub Projects の Roadmap ビューとは

タイムライン = ガントチャートと考えてOK

Roadmap ビューは、プロジェクト内のアイテム(Issue・PR・Draft Issue)をタイムライン上に並べて可視化する機能だ。横軸が時間、各アイテムが棒グラフのように表示される。

ガントチャートに馴染みがある人には「そのまんまガントチャート」と理解して問題ない。ただし、「タスク間の依存関係を矢印で引く」という、一般的なガントチャートソフトが持つ機能は現時点で非対応だ(後述する)。

Roadmap ビューでできること:

  • Issue・PR の開始日と終了日をビジュアルで管理できる
  • ドラッグ操作で日付を変更できる
  • Iteration フィールドをタイムライン軸として使える
  • マイルストーンや Iteration の境界を垂直線(Marker)として表示できる
  • 月・四半期・年の3単位でズームを切り替えられる
  • フィールド値でスライスして、担当者別・ラベル別の表示ができる

2025年1月に公開プレビューとなった Sub-issues(親子 Issue)の階層表示は、2026年3月に一般利用可能(GA)になった。新規プロジェクトビューではデフォルトで Hierarchy(階層表示)が有効になっており、8階層まで展開できる。

Milestone との違い(使い分けの判断基準)

Milestone は「複数の Issue をひとつの期日でまとめる」機能だ。対して Roadmap ビューの日付フィールドは「個々の Issue に開始日・終了日を持たせる」機能になる。

Milestone をタイムライン上に表示することはできる——Marker として垂直線で表示される。ただし Milestone 自体の「期間」は表現できない。

判断基準を整理すると:

用途MilestoneRoadmap(Date フィールド)
v1.0リリース等の期日管理向いているMarkerとして表示可
個々のタスクの作業期間管理向いていない向いている
スプリント計画Iteration で代替Iteration × Roadmapが最適
複数リポジトリ横断での管理リポジトリごとに別1つのProjectに集約可

Milestone はリポジトリ単位の概念で、プロジェクト横断的に使いにくい。複数リポジトリをまたぐ案件を管理するなら、Roadmap ビューに一本化するほうがすっきりする。

比較検討の文脈では、他のプロジェクト管理ツールとの使い分けについて別記事で整理している。

Backlog vs GitHub Projects vs Linear——エンジニアが本当に使えるプロジェクト管理ツール比較【2026年版】
Backlog vs GitHub Projects vs Linear——エンジニアが本当に使えるプロジェクト管理ツール比較【2026年版】プロジェクト管理ツールBacklog・GitHub Projects・Linearの3製品を、料金・機能・タスク管理・ガントチャート・カンバン・スプリント・AI機能・選び方まで網羅した2026年版エンジニア視点の徹底比較ガイド。読む →

初期設定:日付フィールドとビューの追加

Date型カスタムフィールドの追加(開始日・終了日)

Roadmap ビューを機能させるには、まず「開始日」と「終了日」にあたる Date 型フィールドを作る必要がある。デフォルトでは存在しないので手動追加が必要だ。

  1. プロジェクトを開いてテーブルビューに移動する
  2. 右端の「+」列をクリックして「New field」を選択する
  3. フィールド名に「Start Date」と入力し、Type を「Date」に設定して保存する
  4. 同じ手順で「End Date」(または「Target Date」)フィールドを追加する

フィールド名の命名は何でも構わない。後から Roadmap ビューの設定でこれらのフィールドを指定するので、チームで意味が伝わる名前にしておけばいい。

Iteration フィールドを使ったスプリント管理をしている場合は、Iteration を日付フィールドとして代用することもできる。この場合はデフォルトの開始日・終了日を別途作らなくてもよい。

Roadmapビューの表示単位設定(日・週・月)

Roadmap ビューを追加する手順:

  1. ビュータブの「+」をクリックして「New view」を選択する
  2. レイアウトから「Roadmap」を選ぶ
  3. ビュー右上の「Date fields」ボタンをクリックし、作成した「Start Date」と「End Date」を指定する

表示単位(ズームレベル)の切り替えは、虫眼鏡アイコンか Ctrl+スクロールで操作できる。選択肢は「Month(月単位)」「Quarter(四半期単位)」「Year(年単位)」の3段階だ。

実務的には:

  • スプリント計画中 → Month(週・日レベルの粒度が見えやすい)
  • QPI レビューや中長期の振り返り → Quarter または Year

「日単位」の表示は現時点で提供されていない。1〜2日スパンのタスクを細かく管理したい場合は向いていないので注意が必要だ。

Issue・PRをタイムラインに配置する

手動配置の手順

Issue や PR をタイムラインに配置するには2つの方法がある。

方法1: Roadmap ビューの棒グラフ部分をドラッグして期間を設定する。アイテム行の棒グラフエリアをクリック+ドラッグすることで直接期間を設定できる。既存の棒グラフの端をドラッグすれば期間の変更も可能だ。

方法2: テーブルビューで Date フィールドに日付を直接入力する。大量のアイテムを一括で設定するなら、テーブルビューのほうが操作が速い。

Roadmap ビューで日付が設定されていないアイテムは、ビューの最上部に「未設定アイテム」として表示される。この状態のアイテムをドラッグして棒グラフエリアに配置することで期間を設定できる。

Sub-issues(親子issue)を使った階層管理(2026年対応)

2026年3月に GA となった Hierarchy ビューにより、Sub-issues の親子関係をそのまま Roadmap ビューで可視化できるようになった。

Sub-issues の基本的な使い方:

  1. 親 Issue を開いて「Sub-issues」セクションの「Add sub-issue」ボタンをクリックする
  2. 既存 Issue を追加するか、新規で作成する
  3. プロジェクトビューで「View menu → Show hierarchy」を有効にする

Hierarchy ビューを有効にした状態で Roadmap を見ると、親 Issue の棒グラフの下に子 Issue が折りたたみ表示される。親 Issue の期間を動かすと、子 Issue の期間は追従しない(独立して管理される)ので注意が必要だ。

実務での推奨設計:

  • Epic(大きなまとまり)→ 親 Issue
  • Story(機能単位)→ 子 Issue(親 Issue の下)
  • Task(実装タスク)→ 孫 Issue(さらに下)

GitHub Projects は8階層まで Sub-issues をネストできる。ただし実運用では3〜4階層が限界で、それ以上深くなると Roadmap が見づらくなる。

プロジェクトビューに Sub-issues が自動的に追加されない場合は、フィルター済みビューを使っているかを確認してほしい。2026年3月のアップデートで「フィルター済みビューに追加された Sub-issue に対してマッチするフィルタを自動適用する」機能が追加されているが、既存ビューでは設定が必要なケースがある。

Iteration × Roadmap の組み合わせ(スプリント管理)

Iteration フィールドは「2週間ごとのスプリント」のような繰り返しサイクルを定義できる機能だ。これを Roadmap ビューの日付軸として使うことができる。

設定手順:

  1. プロジェクトの Settings → Fields から「New field」で Iteration フィールドを追加する
  2. スプリントの期間(例:2週間)と開始日を設定する
  3. Roadmap ビューの「Date fields」で、Start date と End date に Iteration フィールドを指定する

Iteration を使うメリットは、個々の Issue に手動で日付を設定する手間が省けることだ。Issue に Iteration を割り当てれば、そのスプリントの期間が自動的に棒グラフの範囲になる。

Iteration と Date フィールドを組み合わせることもできる。Start date に Iteration、End date に Date フィールドを指定すれば「スプリント開始で計画、実際の完了日で終了」という使い方も可能だ。

Roadmap ビューでは Iteration の境界を Marker として表示できるため、スプリントの区切りを可視化しながら全体のロードマップを眺めるという使い方ができる。これはスプリント計画とリリース計画を同じビューで確認したいチームに向いている。

フリーランスが複数案件を管理するパターン

1つのProjectに複数リポジトリのissueを集約する

フリーランスで複数クライアントの案件を掛け持ちしている場合、案件ごとにリポジトリが別れていることが多い。GitHub Projects はクロスリポジトリ対応なので、1つのプロジェクトに複数リポジトリの Issue を集約できる。

自分が使っているパターンはこうだ:

  1. 個人の GitHub アカウントまたは Organization に「Master Project」を1つ作る
  2. 各クライアント案件のリポジトリ(client-a/webappclient-b/api など)の Issue を、この1つのプロジェクトに追加していく
  3. Roadmap ビューで「どの案件に、いつ何日を使うか」を俯瞰する

Issue を既存プロジェクトに追加する方法は2つある。Issue 画面右サイドバーの「Projects」セクションからプロジェクトを選択するか、プロジェクトビューの「Add item」から Issue URLを入力する。

クライアント別フィルタリング設定

複数案件が1つのビューに混在すると見づらいので、フィールドとフィルターで整理する。

設定手順:

1.「Client」または「Repository」という名前の Single Select フィールドを追加する(クライアント名をオプションとして登録) 2. Issue 追加時にクライアントを設定する 3. ビューの「Slice by」で「Client」フィールドを選択する

Slice by を設定すると、左パネルにクライアント一覧が表示され、クリックするとそのクライアントの Issue だけに絞り込める。複数案件の切り替えがワンクリックで済む。

リポジトリ名でフィルターをかける場合は、フィルター欄に repo:client-a/webapp と入力する。GitHub Projects はリポジトリ名でのフィルタリングに対応している。

タイムラインを見て「この週は A 案件と B 案件が被っていてキャパオーバーだ」と気づいたら、Issue の日付をドラッグして調整する。この判断を週次でやるようにしてからは、締め切り直前に気づくという事態がなくなった。

GitHub Actions で日付更新を自動化する

GitHub Projects の日付フィールドは手動管理が基本だが、GitHub Actions と GraphQL API を使うと自動化できる。

自動化には1点注意がある。通常の GITHUB_TOKEN はリポジトリスコープに限定されており、Projects(organization または personal project)には権限が届かない。以下のいずれかの方法で追加の認証が必要だ:

  • Personal Access Token(classic)の project スコープ
  • GitHub App のインストールトークン(組織での利用推奨)

PAT をリポジトリの Secrets に PROJECT_TOKEN として登録してから使う。

PRマージ時に終了日を自動更新するワークフロー

PR がマージされたタイミングで、対応する Issue の「End Date」フィールドを今日の日付に自動更新するワークフローだ。

# .github/workflows/update-project-on-merge.yml
name: Update Project End Date on PR Merge

on:
  pull_request:
    types: [closed]

jobs:
  update-end-date:
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    steps:
      - name: Get linked issue and project data
        env:
          GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
          ORGANIZATION: ${{ github.repository_owner }}
          PROJECT_NUMBER: "1"   # 管理しているプロジェクトの番号に変更する
        run: |
          # プロジェクトのIDとEnd Dateフィールドのメタデータを取得する
          gh api graphql -f query='
            query($org: String!, $number: Int!) {
              organization(login: $org) {
                projectV2(number: $number) {
                  id
                  fields(first: 20) {
                    nodes {
                      ... on ProjectV2Field {
                        id
                        name
                        dataType
                      }
                    }
                  }
                }
              }
            }' \
            -f org="$ORGANIZATION" \
            -F number="$PROJECT_NUMBER" > project_data.json

          echo "PROJECT_ID=$(jq -r '.data.organization.projectV2.id' project_data.json)" >> "$GITHUB_ENV"
          echo "END_DATE_FIELD_ID=$(jq -r '.data.organization.projectV2.fields.nodes[] | select(.name == "End Date") | .id' project_data.json)" >> "$GITHUB_ENV"

      - name: Get project item ID for this PR
        env:
          GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
          PR_NODE_ID: ${{ github.event.pull_request.node_id }}
          PROJECT_ID: ${{ env.PROJECT_ID }}
        run: |
          gh api graphql -f query='
            query($pr: ID!) {
              node(id: $pr) {
                ... on PullRequest {
                  projectItems(first: 10) {
                    nodes {
                      id
                      project {
                        id
                      }
                    }
                  }
                }
              }
            }' \
            -f pr="$PR_NODE_ID" > pr_items.json

          # 対象プロジェクトのアイテムIDを抽出する
          ITEM_ID=$(jq -r --arg project_id "$PROJECT_ID" \
            '.data.node.projectItems.nodes[] | select(.project.id == $project_id) | .id' \
            pr_items.json)
          echo "ITEM_ID=$ITEM_ID" >> "$GITHUB_ENV"

      - name: Update End Date to today
        if: env.ITEM_ID != ''
        env:
          GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
          TODAY: ${{ github.event.pull_request.merged_at }}
        run: |
          # マージ日をISO 8601の日付形式(YYYY-MM-DD)に変換する
          MERGE_DATE=$(echo "$TODAY" | cut -c1-10)

          gh api graphql -f query='
            mutation($project: ID!, $item: ID!, $field: ID!, $date: Date!) {
              updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $field
                value: { date: $date }
              }) {
                projectV2Item {
                  id
                }
              }
            }' \
            -f project="${{ env.PROJECT_ID }}" \
            -f item="${{ env.ITEM_ID }}" \
            -f field="${{ env.END_DATE_FIELD_ID }}" \
            -f date="$MERGE_DATE"

          echo "End Date updated to $MERGE_DATE"

PROJECT_NUMBER はプロジェクトの URL(https://github.com/orgs/YOUR_ORG/projects/1 など)の末尾の数字だ。個人アカウントのプロジェクトを使う場合は organizationuser に変更する必要がある。

issueクローズ時にステータスを自動更新するワークフロー

Issue がクローズされたタイミングで、プロジェクト内のステータスフィールドを自動的に「Done」に更新するワークフローだ。

# .github/workflows/update-project-status-on-close.yml
name: Update Project Status on Issue Close

on:
  issues:
    types: [closed]

jobs:
  update-status:
    runs-on: ubuntu-latest
    steps:
      - name: Get project metadata
        env:
          GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
          ORGANIZATION: ${{ github.repository_owner }}
          PROJECT_NUMBER: "1"   # 管理しているプロジェクトの番号に変更する
        run: |
          gh api graphql -f query='
            query($org: String!, $number: Int!) {
              organization(login: $org) {
                projectV2(number: $number) {
                  id
                  fields(first: 20) {
                    nodes {
                      ... on ProjectV2SingleSelectField {
                        id
                        name
                        options {
                          id
                          name
                        }
                      }
                    }
                  }
                }
              }
            }' \
            -f org="$ORGANIZATION" \
            -F number="$PROJECT_NUMBER" > project_data.json

          echo "PROJECT_ID=$(jq -r '.data.organization.projectV2.id' project_data.json)" >> "$GITHUB_ENV"

          # StatusフィールドのIDを取得する
          echo "STATUS_FIELD_ID=$(jq -r \
            '.data.organization.projectV2.fields.nodes[] | select(.name == "Status") | .id' \
            project_data.json)" >> "$GITHUB_ENV"

          # DoneオプションのIDを取得する(オプション名が "Done" の場合)
          echo "DONE_OPTION_ID=$(jq -r \
            '.data.organization.projectV2.fields.nodes[] | select(.name == "Status") | .options[] | select(.name == "Done") | .id' \
            project_data.json)" >> "$GITHUB_ENV"

      - name: Get project item ID for this issue
        env:
          GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
          ISSUE_NODE_ID: ${{ github.event.issue.node_id }}
          PROJECT_ID: ${{ env.PROJECT_ID }}
        run: |
          gh api graphql -f query='
            query($issue: ID!) {
              node(id: $issue) {
                ... on Issue {
                  projectItems(first: 10) {
                    nodes {
                      id
                      project {
                        id
                      }
                    }
                  }
                }
              }
            }' \
            -f issue="$ISSUE_NODE_ID" > issue_items.json

          ITEM_ID=$(jq -r --arg project_id "$PROJECT_ID" \
            '.data.node.projectItems.nodes[] | select(.project.id == $project_id) | .id' \
            issue_items.json)
          echo "ITEM_ID=$ITEM_ID" >> "$GITHUB_ENV"

      - name: Update Status to Done
        if: env.ITEM_ID != '' && env.DONE_OPTION_ID != ''
        env:
          GH_TOKEN: ${{ secrets.PROJECT_TOKEN }}
        run: |
          gh api graphql -f query='
            mutation($project: ID!, $item: ID!, $field: ID!, $option: String!) {
              updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $field
                value: { singleSelectOptionId: $option }
              }) {
                projectV2Item {
                  id
                }
              }
            }' \
            -f project="${{ env.PROJECT_ID }}" \
            -f item="${{ env.ITEM_ID }}" \
            -f field="${{ env.STATUS_FIELD_ID }}" \
            -f option="${{ env.DONE_OPTION_ID }}"

          echo "Status updated to Done"

ステータスフィールドのオプション名が「Done」と異なる場合は、select(.name == "Done") の部分を実際の名前に変えてほしい。

このワークフローはリポジトリ単位に設置するので、複数リポジトリの Issue を1つのプロジェクトで管理している場合は、各リポジトリにこのファイルを置く必要がある。

GitHub Actions の CI/CD 全般については以下の記事も参考になる。

Claude Code × GitHub Actions でCI/CDを賢くする——AIレビュー・自動修正・コスト管理の実装パターン
Claude Code × GitHub Actions でCI/CDを賢くする——AIレビュー・自動修正・コスト管理の実装パターンClaude Code と GitHub Actions を連携してCI/CDパイプラインにAIを組み込む実践ガイド。PRレビュー自動化・テスト失敗の自動分析・コスト最適化まで、settings.jsonとワークフローファイルを丸ごと公開。読む →

GitHub Projects Roadmap でできないこと(正直整理)

便利なものほど、できないことを把握してから使ったほうがいい。以下は実際に使っていて「あれ、これできないの」と気づいた点だ。

タスク間依存関係(矢印)は引けない

「タスクAが完了してからタスクBを開始する」という依存関係を矢印で表現する機能は、2026年6月時点で GitHub Projects Roadmap には存在しない。

Microsoft Project や Asana、Notion タイムラインが対応している「前提タスクの設定(predecessor)」がないため、依存関係を可視化したガントチャートを期待していると期待外れになる。

現実的な代替策:

  • Issue の説明欄に「depends on #123」と書いてリンクを貼る(視覚的な矢印はないが、クリックで遷移できる)
  • Labels を「Blocked」「Blocker」で分けて、ステータス管理として代用する
  • Sub-issues の階層構造を使って「親がBlockerの場合は子も動かない」という設計ルールをチームで決める

依存関係の可視化が要件として必須なら、Linear や Asana のタイムラインビューを検討するほうがいい。

外部カレンダー同期は非対応

Google Calendar や Outlook への同期機能はない。GitHub Projects の日付情報をカレンダーアプリで確認することはできない。

代替策:

  • iCal URL を使った GitHub Releases / Milestones のカレンダー連携はできるが、Projects の Date フィールドはエクスポートできない
  • GitHub Apps の Marketplace に「Projects → Google Calendar」連携ツールがいくつか存在する(有料のものが多い)
  • 自前で GitHub Actions + Google Calendar API を組み合わせて同期処理を書けば技術的には可能だが、工数が割に合わない場合が多い

チームの予定管理はカレンダー、タスク進捗管理は GitHub Projects と割り切って使い分けるのが現実的だ。

ガントチャートからのissue自動クローズは不可

Roadmap ビュー上でアイテムの棒グラフを End Date の日付を超えて移動させても、Issue が自動クローズされるわけではない。Roadmap ビューはあくまで「可視化ツール」であって、Issue のライフサイクルとは独立している。

Issue のクローズはコードやコメントで手動で行うか、前述のような GitHub Actions ワークフローで自動化する必要がある。

それでもGitHub Projectsを選ぶ基準

上記の制約を踏まえた上で「GitHub Projects の Roadmap ビューを選ぶ」判断基準はこうだ。

選んでいい条件:

  • 開発チームが既に GitHub でコードを管理している
  • 追加費用をゼロにしたい(GitHub Projects は全プランで無料)
  • 依存関係の矢印表現は不要で、大まかな期間管理ができれば十分
  • Issue・PR とタイムラインの紐付けを一元管理したい
  • フリーランスや小規模チームで「管理ツールにコストをかけたくない」

見直したほうがいい条件:

  • タスク間の依存関係の可視化が必須の場合
  • 非エンジニアのステークホルダー(クライアント等)がガントチャートを見て承認・確認する必要がある場合
  • 日単位の精密なスケジューリングが必要な場合

GitHub でコードを管理しているなら、追加ツールを入れずに Issues と Projects の Roadmap ビューで十分回せる場面は多い。「足りない部分だけ GitHub Actions で補う」という設計で運用コストをかなり下げられる。

FAQ

GitHub Projects の Roadmap ビューについてよく聞かれることをまとめた。

Q. GitHub Projectsのガントチャートは無料で使える?

使える。GitHub Projects は GitHub の全プランで追加費用なしで利用できる。Free・Pro・Team・Enterprise のどれでも Roadmap ビュー(タイムライン/ガントチャート機能)を使える。2023年3月に GA になって以来、有料オプション化されたことはない。

Q. タスク間に依存関係(矢印)は設定できる?

2026年6月時点では設定できない。GitHub Issues の Community Discussions でも長年リクエストが上がっているが、現時点では実装されていない。代替策として、Issue の説明欄に depends on #123 と手動で書く方法か、Labels で「Blocked」管理をする方法が現実的だ。

Q. 複数リポジトリのIssueを1つのガントチャートにまとめられる?

まとめられる。GitHub Projects はクロスリポジトリ対応のため、Organization 内の複数リポジトリはもちろん、個人アカウントが所有する複数リポジトリの Issue を1つのプロジェクトに集約して Roadmap ビューで管理できる。「Add item」から各リポジトリの Issue URL または Issue 検索で追加する。

Q. GitHubのRoadmapビューとMilestoneはどう違う?

Milestone はリポジトリ単位で「複数 Issue をひとつの期日でまとめる」機能、Roadmap ビューは「個々の Issue に開始日・終了日を持たせてタイムラインで可視化する」機能だ。Roadmap ビューでは Milestone を Marker(垂直線)として表示できるが、Milestone 自体に期間(開始日〜終了日)の概念はない。

Q. 日付を手動で入力しなくていい自動化方法はある?

GitHub Actions + GraphQL API の組み合わせで自動化できる。本記事で紹介している「PRマージ時に終了日を自動更新するワークフロー」と「Issueクローズ時にステータスを自動更新するワークフロー」がその例だ。ただし GITHUB_TOKEN ではプロジェクトに権限が届かないため、project スコープの PAT または GitHub App のインストールトークンが別途必要になる。

← 記事一覧に戻る