GitHub公式ドキュメント更新で確認すべきglobal.jsonのrollForward設定とロックファイル運用

2026年4月30日に、GitHub上の dotnet/docs 公式リポジトリで global.json に関するドキュメント更新がマージされました。結論から言うと、NuGetのロックファイルを使っている .NET プロジェクトでは、global.json の rollForward を disable にして、SDKバージョンも依存関係グラフも同じ状態に保つべきという点が明確化されています。更新自体は小さな文言追加ですが、CI/CD、GitHub Actions、Azure Pipelines、Dockerビルド、開発者PCのSDK管理に影響する可能性があります。(GitHub)

目次

今回の公式ドキュメント更新で何が変わったか

今回の更新は、GitHub上の dotnet/docs リポジトリにある docs/core/tools/global-json.md に対する変更です。プルリクエスト #53348 は2026年4月30日にマージされ、対象コミットは 74e8a04 です。差分としては1ファイルのみで、rollForward の disable に関する説明へ脚注が追加されました。(GitHub)

変更前の disable は、主に「ロールフォワードせず、完全一致が必要」という説明でした。更新後はその説明に加えて、package lock filesを使う場合は rollForward を disable に設定し、SDKバージョンと依存関係グラフを同期させるというガイダンスが追加されています。Microsoft Learnの現行ページでも、disable は「正確なSDK一致を要求する」設定として説明され、ロックファイル利用時の推奨が脚注で示されています。(Microsoft Learn)

確認項目更新前の読み取り方更新後に強調された実務上の意味
rollForward: disable指定したSDKと完全一致させる設定ロックファイル運用では推奨設定として見る
package lock filesNuGet依存関係を固定する仕組みSDK差分による依存関係グラフのズレも考慮する
CI/CDSDKが近いバージョンなら問題ないと考えがちロックファイル利用時はSDKの完全一致を優先する
影響範囲global.json の説明文レベルGitHub Actions、Azure Pipelines、Docker、開発端末のSDK管理に関わる

重要なのは、今回の更新が「新機能追加」ではなく「既存の推奨事項を見つけやすくしたドキュメント整理」である点です。ただし、実務ではこの種のドキュメント更新が、ビルド失敗やCI再現性の問題を避ける判断材料になります。

rollForward: disable とは何か

global.json は、.NET CLIが使用するSDKバージョンを指定するためのファイルです。リポジトリルートやソリューション配下に配置することで、dotnet build、dotnet restore、dotnet test などで使われるSDKを制御できます。

rollForward は、指定したSDKが見つからない場合や、より新しいSDKを許容する場合の選択ルールです。Microsoft Learnでは、rollForward の値として patch、feature、minor、major、latestPatch、latestFeature、latestMinor、latestMajor、disable などが説明されています。disable はその中でも最も厳しく、指定したSDKバージョンと完全一致しない場合はロールフォワードしません。(Microsoft Learn)

典型的な設定は次の形です。

{
  "sdk": {
    "version": "8.0.302",
    "rollForward": "disable"
  }
}

この例では、8.0.302 のSDKがインストールされている環境だけで、そのSDKを使って .NET CLI が実行されます。8.0.303 や 8.0.400 が入っていても、指定SDKがなければ自動的には使われません。

なぜロックファイル運用で disable が重要なのか

NuGetのロックファイル、つまり packages.lock.json は、復元されるパッケージ依存関係を固定するための仕組みです。NuGet公式ドキュメントでは、RestorePackagesWithLockFile を有効にすると packages.lock.json が生成され、CI/CDなどで依存関係をその場で変えたくない場合は --locked-mode や RestoreLockedMode=true を使う方法が説明されています。(Microsoft Learn)

しかし、ここで見落としやすいのが SDK自体も依存関係グラフに影響する場合がある という点です。

たとえば、開発者PCでは .NET SDK 8.0.407 でロックファイルを生成したのに、CI環境では global.json のロールフォワード設定によって 8.0.408 が使われるケースがあります。関連Issueでは、SDK差分により Microsoft.NET.ILLink.Tasks の参照バージョンが変わり、NU1004 エラーにつながった事例が報告されています。(GitHub)

つまり、ロックファイルでNuGetパッケージを固定していても、SDKが変われば次のようなズレが起きる可能性があります。

起きること具体的な影響
SDKに同梱・暗黙参照されるパッケージが変わるpackages.lock.json と復元結果が一致しない
CIだけ新しいSDKにロールフォワードするローカルでは成功し、CIだけ失敗する
Visual Studioやビルドエージェントの更新でSDKが変わる何も変更していないPRでビルドが落ちる
DockerイメージやGitHub ActionsランナーのSDKが変わる再現性のあるビルドの前提が崩れる

ロックファイルは「依存関係の再現性」を高める仕組みですが、SDK選択が揺れていると、その再現性に穴ができます。今回のドキュメント更新は、その穴を防ぐために global.json 側でもSDKを固定する必要があると明確にしたものです。

影響を受けやすいプロジェクト

今回の更新で特に確認すべきなのは、次のようなプロジェクトです。

対象確認すべき理由
packages.lock.json をリポジトリにコミットしている .NET アプリSDK差分でロックファイルとの差異が出る可能性がある
dotnet restore --locked-mode をCIで使っている依存関係グラフが変わるとCIが失敗する
RestoreLockedMode=true を設定しているロックファイルとの差分を許容しないため影響が出やすい
GitHub Actionsで actions/setup-dotnet を使っているglobal.json やランナー上のSDK選択を確認する必要がある
Azure Pipelinesで UseDotNet@2 の useGlobalJson を使っているパイプライン側のSDK解決と global.json の整合性確認が必要
Dockerfileで mcr.microsoft.com/dotnet/sdk イメージを使っているベースイメージ更新によりSDKが変わる可能性がある
Blazor、MAUI、WASM、トリミング関連を使うプロジェクトSDK依存のタスクや暗黙的なパッケージの影響を受けやすい

特に注意したいのは、rollForward を明示していない global.json です。Microsoft Learnでは、SDKバージョンが指定されていて rollForward がない場合、既定のポリシーとして patch が使われると説明されています。つまり「何も書いていないから完全固定」ではありません。(Microsoft Learn)

まず確認すべきファイルと設定

今回の更新を受けて、開発チームやクラウド管理者が最初に見るべき場所は次の4つです。

確認場所見るポイント
global.jsonsdk.version が完全なバージョンか、rollForward が disable か
packages.lock.jsonロックファイルを使っているか、複数プロジェクトで配置が分散していないか
.csproj / Directory.Build.propsRestorePackagesWithLockFile や RestoreLockedMode の有無
CI/CD定義dotnet restore --locked-mode、setup-dotnet、UseDotNet@2、Docker SDKイメージの指定

確認コマンドとしては、まず次を実行します。

dotnet --version
dotnet --list-sdks

リポジトリ内の global.json を探す場合は、Linux/macOSなら次のように確認できます。

find . -name global.json -o -name packages.lock.json

Windows PowerShellでは次のように確認できます。

Get-ChildItem -Recurse -Filter global.json
Get-ChildItem -Recurse -Filter packages.lock.json

複数の global.json がある場合は、どのディレクトリから dotnet コマンドを実行するかで参照されるファイルが変わる可能性があります。Microsoft Learnでは、.NET SDK muxerは現在の作業ディレクトリから上位階層を検索し、MSBuild SDK resolverはソリューションやプロジェクトの場所を基準に検索すると説明されています。(Microsoft Learn)

推奨される global.json の設定例

ロックファイルを使うアプリケーションでは、基本的に次のようにSDKを完全固定します。

{
  "sdk": {
    "version": "8.0.302",
    "rollForward": "disable"
  }
}

version は自社プロジェクトで実際に採用するSDKバージョンに置き換えてください。8.0.302 は形式を示す例であり、すべてのプロジェクトに推奨される固定値ではありません。

allowPrerelease も必要に応じて明示します。プレビューSDKを使わない通常の本番プロジェクトでは、次のようにしておくと意図が明確になります。

{
  "sdk": {
    "version": "8.0.302",
    "rollForward": "disable",
    "allowPrerelease": false
  }
}

ただし、.NET 10以降の新機能検証やプレビューSDK評価を行う検証ブランチでは、allowPrerelease を別途検討します。本番ビルドと検証ビルドで同じ global.json を使うと、意図せずプレビューSDKが混ざるリスクがあります。

GitHub Actionsで確認すべきポイント

GitHub Actionsを使っている場合は、actions/setup-dotnet の設定を確認します。公式READMEでは、global-json-file 入力を使って global.json からSDKバージョンを読み取れること、dotnet-version と global-json-file の両方を指定した場合は両方のバージョンがインストールされることが説明されています。(GitHub)

ロックファイル運用では、次のように global.json を明示的に参照し、restoreはlocked modeで実行します。

steps:
  - uses: actions/checkout@v6

  - name: Setup .NET SDK
    uses: actions/setup-dotnet@v5
    with:
      global-json-file: ./global.json

  - name: Restore
    run: dotnet restore --locked-mode

  - name: Build
    run: dotnet build --no-restore

注意点は、dotnet-version: 8.0.x のような幅のある指定と、global.json による固定を混在させないことです。幅のある指定は便利ですが、ロックファイルで再現性を優先するビルドでは、意図せず新しいSDKが入る原因になります。

GitHub Actionsのキャッシュも確認が必要です。setup-dotnet にはNuGetパッケージキャッシュ機能があり、ロックファイルをキャッシュキーに使う説明があります。キャッシュはビルド高速化には有効ですが、SDKの不一致を解決するものではありません。(GitHub)

Azure Pipelinesや自己ホストランナーでの注意点

Azure Pipelinesでは、UseDotNet@2 がSDKを取得してPATHに追加します。Microsoft Learnでは、useGlobalJson を使うと global.json からSDKをインストールでき、workingDirectory で検索ルートを指定できると説明されています。(Microsoft Learn)

例は次の通りです。

- task: UseDotNet@2
  inputs:
    packageType: 'sdk'
    useGlobalJson: true
    workingDirectory: '$(Build.SourcesDirectory)'

- script: dotnet restore --locked-mode
  displayName: Restore locked dependencies

- script: dotnet build --no-restore
  displayName: Build

自己ホストランナーや社内ビルドエージェントでは、過去に入れたSDKが残っていることがあります。rollForward が disable でなければ、インストール済みSDKの状態によってビルド結果が変わる可能性があります。クラウド管理者は、エージェントに入っているSDK一覧を定期的に棚卸しし、ジョブ開始時に dotnet --version をログへ出す運用にすると原因調査が早くなります。

- script: |
    dotnet --version
    dotnet --list-sdks
  displayName: Show .NET SDK versions

Dockerビルドで見落としやすいポイント

Dockerを使う場合、global.json とDockerイメージのSDKバージョンをそろえる必要があります。

悪い例は、SDKイメージを広いタグで指定し、リポジトリ側ではロックファイルを使っているケースです。

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet restore --locked-mode
RUN dotnet build --no-restore -c Release

この場合、8.0 タグが将来どのSDKを含むかは更新タイミングに左右されます。ロックファイルの再現性を重視するなら、プロジェクトで採用するSDKバージョンとベースイメージをできるだけ具体的に合わせます。

FROM mcr.microsoft.com/dotnet/sdk:8.0.302 AS build
WORKDIR /src
COPY . .
RUN dotnet --version
RUN dotnet restore --locked-mode
RUN dotnet build --no-restore -c Release

実際に利用可能なタグやパッチの扱いは時期によって変わるため、Dockerfile更新時には公式イメージのタグとプロジェクトの global.json をセットで確認してください。

移行準備の進め方

すでに latestPatch や latestFeature を使っているチームが、いきなり disable に変えると、開発者PCやCIでSDK不足が起きることがあります。移行は次の順序で進めると安全です。

手順作業内容失敗しやすいポイント
1現在CIで使われているSDKを dotnet --version で確認するローカルのSDKだけ見て判断する
2packages.lock.json と RestoreLockedMode の有無を確認するロックファイルが一部プロジェクトにだけある
3採用するSDKバージョンを1つ決めるVisual Studio付属SDKとCI SDKがずれる
4global.json に rollForward: disable を追加するversion が古く、誰もそのSDKを持っていない
5GitHub ActionsやAzure Pipelinesで同じSDKをインストールするdotnet-version: 8.0.x のような指定を残す
6dotnet restore --locked-mode を実行して確認するロックファイル更新が必要な変更と混同する
7SDK更新ルールをチームで決める各自が任意のタイミングでSDKを更新する

移行時にCIが失敗した場合、まず見るべきなのは NU1004 のようなロックファイル関連エラー、dotnet --version の出力、packages.lock.json の差分です。SDKを上げる必要がある場合は、SDK更新とロックファイル再生成を同じPRにまとめるとレビューしやすくなります。

latestPatch や latestFeature を使ってはいけないのか

必ずしもそうではありません。

latestPatch や latestFeature は、SDKのセキュリティ更新や修正を取り込みやすくするためには便利です。Microsoft Learnでも、latestFeature や latestPatch は指定範囲内のより新しいSDKを使う設定として説明されています。(Microsoft Learn)

ただし、ロックファイルを使って「毎回同じ依存関係でビルドする」ことを重視しているプロジェクトでは、SDK側だけ自動的に変わると整合性が崩れます。

判断基準は次のように考えると分かりやすいです。

運用方針向いている設定
アプリ本番ビルドで再現性を最優先するrollForward: disable
ロックファイルを使い、CIで --locked-mode を使うrollForward: disable
OSSライブラリで複数SDKに対する互換性を検証するマトリックスビルドで複数SDKを明示
SDK修正を早めに取り込みたい検証環境latestPatch や latestFeature を検討
開発者の利便性を優先する小規模プロジェクトチーム内合意があれば緩いロールフォワードも可

大切なのは、rollForward の値を「なんとなく」選ばないことです。ロックファイルを使うなら、SDKもロック対象の一部として扱うのが今回の更新の実務的な読み方です。

よくある失敗と対策

rollForward を省略して完全固定したつもりになる

global.json にSDKバージョンだけを書くと、完全固定に見えます。

{
  "sdk": {
    "version": "8.0.302"
  }
}

しかし、SDKバージョンが指定されていて rollForward がない場合、既定では patch ポリシーが使われます。指定SDKがない環境では、より新しいパッチへ進む可能性があります。ロックファイル運用では、意図を明確にするために disable を書くのが安全です。(Microsoft Learn)

CIだけ成功し、ローカルだけ失敗する

CIに正しいSDKが入っていても、開発者PCに同じSDKがないとローカル復元やビルドが失敗します。対策として、READMEやオンボーディング手順に次の情報を明記します。

dotnet --version
dotnet --list-sdks

必要なSDKがなければ、公式の .NET ダウンロードページや社内配布手順からインストールします。Visual Studioユーザーの場合、Visual Studio更新でSDKが変わることもあるため、スタンドアロンSDKの導入要否も検討します。Microsoft Learnでも、Visual Studioのアップグレードで以前のSDKが削除される場合があることに触れています。(Microsoft Learn)

SDK更新とロックファイル更新を別々に行う

SDKだけを上げるPRと、packages.lock.json を更新するPRを分けると、どちらの変更がビルド差分の原因か分かりにくくなります。

実務では、次のように1つの変更単位にまとめるのが分かりやすいです。

- global.json の SDK version を更新
- 必要に応じて Dockerfile / CI 定義のSDK指定を更新
- dotnet restore --force-evaluate などでロックファイルを再生成
- dotnet restore --locked-mode で再確認
- dotnet build / dotnet test を実行

SDK更新は「開発ツールの更新」ではなく「依存関係グラフに影響し得る変更」として扱うと、レビュー品質が上がります。

技術意思決定者が見るべき運用ルール

開発チームが大きくなるほど、global.json とロックファイルの扱いは個人判断に任せない方が安全です。特に、クラウド管理者、ソリューションアーキテクト、テクニカルリードは次のルールを整備しておくとよいでしょう。

ルール目的
本番ビルドでは global.json を必須にするSDK選択を暗黙にしない
ロックファイル利用時は rollForward: disable を標準にするSDKと依存関係グラフを同期させる
CIログに dotnet --version を必ず出す障害調査を早くする
SDK更新PRは月次またはスプリント単位でまとめる開発者ごとの更新タイミング差をなくす
Dockerfile、GitHub Actions、Azure PipelinesのSDK指定を棚卸しする実行環境ごとのズレをなくす
ロックファイルの差分はレビュー対象にする意図しない依存関係変更を検出する

このルールは、セキュリティ更新を止めるためのものではありません。むしろ、SDK更新を計画的に行い、ロックファイル差分とビルド結果を確認したうえで安全に取り込むためのルールです。

今すぐ取るべきアクション

今回のGitHub上の公式ドキュメント更新で確認すべき点は、シンプルです。packages.lock.json を使っているなら、global.json の rollForward を確認し、必要なら disable に変更することです。

最初に次の順で確認してください。

dotnet --version
dotnet --list-sdks
find . -name global.json -o -name packages.lock.json

次に、global.json を次の観点で見直します。

{
  "sdk": {
    "version": "使用するSDKの完全なバージョン",
    "rollForward": "disable"
  }
}

最後に、CIで次を実行して、ロックファイルとSDK選択が一致しているか確認します。

dotnet restore --locked-mode
dotnet build --no-restore
dotnet test --no-build

今回の更新は、見た目には小さなドキュメント差分です。しかし、ロックファイルを使う .NET プロジェクトでは、SDKバージョンの揺れがCI失敗や再現性低下につながります。GitHub Actions、Azure Pipelines、Docker、開発者PCのSDKを一つの運用ルールとして見直し、global.json と packages.lock.json をセットで管理することが、次に取るべき具体的な対応です。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次