
Git 3.0 で何が変わるのか - SHA-256・reftable・main 既定化と、備えるための自作ツール git3ready
Gitのメンテナ本人によるオブジェクトモデルの解説書。
コマンドの背後にある仕組みを日本語で体系的に。
Git 3.0で必須化されるRustを基礎から学べる定番書。
当サイトは Amazon.co.jp を宣伝しリンクすることで紹介料を得る手段を提供する、Amazonアソシエイト・プログラムの参加者です。価格・在庫はリンク先の最新情報をご確認ください。
Git には「次の破壊的リリースで何を変えるか」を列挙した公式文書があります。git/git リポジトリの Documentation/BreakingChanges.adoc です。ここに Git 3.0 の節があり、新規リポジトリの既定が SHA-256 と reftable と main に変わること、いくつかの古いコマンドや仕組みが削除されることが書かれています。
この記事では、その文書を一次情報として Git 3.0 の予定変更を整理し、あわせて変更で壊れる箇所を事前に洗い出すために作った CLI「git3ready」を紹介します。
NOTE
本記事の内容は、2026-09-24 時点の BreakingChanges.adoc(最終更新コミット 985b38c、2026-04-27)に基づきます。文書自体が「生きた文書」とされており、内容は今後変わる可能性があります。
Git 3.0 はいつ出るのか
結論から言うと、リリース日は決まっていません。文書には次のように明記されています。
There is no planned release date for this breaking version yet.
同じ文書によると、Git の過去の大きな破壊的リリースは Git 1.6.0(2008年8月)と Git 2.0(2014年5月)で、破壊的リリースの間隔は「通常、複数年単位」とされています。Git 2.0 以降はバージョン番号を <major>.<minor> で数えており、次の破壊的リリースで major を上げる、つまり Git 3.0 にする方針です。
執筆時点の Git は、安定版の最新が 2.55.0(2026-06-29 タグ付け)、次の 2.56.0 が rc2(2026-09-22 タグ付け)の段階です。
破壊的変更の実装は、コンパイル時スイッチ WITH_BREAKING_CHANGES で囲って少しずつ本体に入れていく手順になっています。このスイッチを有効にしてビルドした Git は、Git 3.0 の変更がすでに適用されたかのように振る舞い、Git プロジェクトの CI でもこの構成を常に試験しています。
Git 3.0 で予定されている変更
文書の「Changes(既定値などの変更)」と「Removals(削除)」を表にまとめます。
既定値の変更
| 項目 | いま(Git 2.x) | Git 3.0 | 主な理由(文書より) |
|---|---|---|---|
| 新規リポジトリのハッシュ関数 | sha1 | sha256 | SHA-1 は NIST が2011年に非推奨化し、SHAttered(2017)や Shambles(2020)など実用的な攻撃が出ている |
| 新規リポジトリの参照(ref)保存形式 | files | reftable | 大文字小文字だけ違う参照名の衝突、packed-refs の全書き換え、複数参照更新の非アトミック性などを解消 |
| 新規リポジトリの既定ブランチ名 | master | main | 2020年12月から警告を出してきた。主要フォージの既定と揃える |
safe.bareRepository の既定 | all | explicit | 埋め込まれた bare リポジトリの悪意あるフックが、cd しただけで発火し得るため |
| ビルド時の Rust | 任意 | 必須 | Rust の段階的導入の最終段階 |
いくつか補足します。
- SHA-256 への変更は新規に作るリポジトリの既定の話です。文書は「現時点で
sha1形式を非推奨にする計画はない」と明言しており、既存の SHA-1 リポジトリが使えなくなるわけではありません。また、変更の前提条件として「ライブラリ・アプリケーション・フォージなどのエコシステムがsha256に対応していること」が挙げられています。 - reftable も同様に、JGit・libgit2・Gitoxide など別実装の対応が前提条件とされています。
safe.bareRepository=explicitになっても、--git-dirやGIT_DIRで明示的に指定した bare リポジトリは引き続き使えます。拒否されるのは、ディレクトリを上へたどって暗黙的に見つかった bare リポジトリだけです。- Rust については段階が示されています。Git 2.52 で Meson が自動検出、2.55 で両ビルドシステムが既定で有効化(2.55.0 のリリースノートにも「Rust support is enabled by default (but still allows opting out)」とあります)、そして Git 3.0 でビルドオプション自体を削除して必須化、という流れです。ただし、ディストリビューションへの影響が大きい場合は必須化を後のマイナーリリースに先送りする可能性がある、とも書かれています。
Rust 必須化に関連して、Git 3.0 直前のバージョンを長期サポート(LTS)リリースにする方針も記載されています。重要なバグ修正を少なくとも4リリースサイクル、セキュリティ修正を6リリースサイクル提供する予定です。
削除されるもの
| 対象 | 代替 |
|---|---|
grafts(info/grafts) | git replace |
git pack-redundant | なし(2023年から --i-still-use-this 無しでは動かない) |
.git/branches/ と .git/remotes/ による remote 定義 | 設定ファイル(git remote)による remote |
git name-rev --stdin | git name-rev --annotate-stdin |
git whatchanged | git log --raw |
core.commentString=auto | 明示的なコメント文字の指定 |
core.preferSymlinkRefs=true | シンボリック参照はテキストファイルで保存(読み込み側は当面サポート) |
なお、文書には「置き換えがあっても非推奨にしないもの」の節もあり、git checkout は git switch / git restore があっても残すと明記されています。
壊れるのは Git 本体ではなく、Git の周りのコード
Git 3.0 の変更は、Git を普通に使っているだけなら大きな問題になりにくいものです。新しい既定値は新規リポジトリにしか効きませんし、既存リポジトリは形式を保ったまま使えます。
問題になるのは、Git 2.x の既定値を暗黙の前提にしている周辺のコードです。たとえば次のようなものです。
- コミット ID を
[0-9a-f]{40}のような正規表現で検証しているコード(SHA-256 のオブジェクト ID は64桁) .git/HEADや.git/refs/heads/...をファイルとして直接読むデプロイスクリプトgit initした直後にmasterをチェックアウトするテストヘルパーや CI ジョブ- 40個のゼロ(SHA-1 のヌル ID)と比較する pre-push フック
- テストフィクスチャとしてツリーにコミットされた bare リポジトリ
reftable の影響は特に分かりにくいので、実際に手元で確認してみます。reftable 形式でリポジトリを作ると、.git/HEAD は互換用のスタブになり、中身は常に同じ文字列になります(Git 2.52.0 で確認)。
git init -q --ref-format=reftable r && cd r
git commit -q --allow-empty -m x
cat .git/HEAD
# ref: refs/heads/.invalid.git/HEAD を読んでブランチ名を取り出すスクリプトは、エラーにならずに .invalid という誤った値を受け取ってしまいます。こうした「いまは動くが、既定値が変わった瞬間に壊れる」箇所を探すために作ったのが git3ready です。
git3ready の紹介
git3ready は、Git 3.0 で変わる既定値を前提にしたスクリプト・フック・テスト・CI の記述を見つけ、新しい既定値でテストを試走させるための CLI です。Rust 製でオフライン動作し、MIT ライセンスで公開しています。
主なサブコマンドは3つです。
| コマンド | 役割 |
|---|---|
git3ready scan [PATH] | ツリーを走査し、Git 2.x の既定値を前提にした行を報告する |
git3ready rehearse -- COMMAND... | Git 3.0 の既定値を有効にした環境でコマンド(テストスイートなど)を実行する |
git3ready env | インストール済みの Git と現在のリポジトリが、Git 3.0 でどう振る舞うかを報告する |
インストール
Rust の stable ツールチェインがあればソースからビルドできます。
cargo install --git https://github.com/printemps-tokyo/git3readyリリースページには Linux(x86_64)と macOS(x86_64 / arm64)向けのビルド済みバイナリを、.sha256 付きで置いています。
scan: 前提にしている箇所を洗い出す
試しに、ありがちな問題を含む小さなリポジトリを用意しました。
# scripts/release.sh
#!/bin/sh
set -e
branch=$(sed 's#ref: refs/heads/##' .git/HEAD)
sha=$(cat .git/refs/heads/$branch)
echo "release $branch at $sha"# scripts/check_sha.py
import re
SHA_RE = re.compile(r"^[0-9a-f]{40}$")# .github/workflows/ci.yml
jobs:
test:
steps:
- run: |
git init fixture
cd fixture && git checkout masterこれに git3ready scan をかけた実際の出力です。
$ git3ready scan .
BREAK hex40-pattern Pattern accepts exactly 40 hex digits (a SHA-1 object id)
change: New repositories default to the sha256 object format (64-hex object ids).
why: A full object id in a sha256 repository is 64 hex digits, so this pattern rejects every one of them.
fix: Accept both lengths, e.g. [0-9a-f]{40}([0-9a-f]{24})?, or ask Git with git rev-parse --show-object-format.
scripts/check_sha.py:2:24 SHA_RE = re.compile(r"^[0-9a-f]{40}$")
BREAK ref-files-access Reads or writes ref storage files directly
change: New repositories default to the reftable ref storage format.
why: A reftable repository keeps refs and reflogs in .git/reftable/: there is no packed-refs, no .git/logs/, and .git/refs/heads is a placeholder file, not a directory.
fix: Go through Git: git for-each-ref, git rev-parse, git update-ref, git show-ref, git reflog / git log -g.
scripts/release.sh:4:11 sha=$(cat .git/refs/heads/$branch)
BREAK head-file-read Reads .git/HEAD as a file
change: New repositories default to the reftable ref storage format.
why: In a reftable repository .git/HEAD is a compatibility stub that always reads "ref: refs/heads/.invalid".
fix: git symbolic-ref --short -q HEAD, git branch --show-current, or git rev-parse HEAD.
scripts/release.sh:3:37 branch=$(sed 's#ref: refs/heads/##' .git/HEAD)
BREAK master-after-init Assumes a freshly initialized repository is on master
change: New repositories default to a branch named main.
why: The file runs git init without choosing a branch, then refers to master; under Git 3.0 the new repository is on main.
fix: Pin the name at creation: git init -b <name> (or --initial-branch), or -c init.defaultBranch=<name>.
.github/workflows/ci.yml:6:38 cd fixture && git checkout master
(git init at line 5 does not choose a branch)
Summary: 4 break, 0 risk, 0 info in 3 paths (3 scanned, 0 suppressed)
Rules follow git/git Documentation/BreakingChanges.adoc @ 985b38c (read 2026-09-23).
Git 3.0 has no planned release date. Matching is textual, not semantic.各指摘には、どの変更に由来するか(change)・なぜ壊れるか(why)・どう直すか(fix)が付きます。重大度は3段階です。
| 重大度 | 意味 |
|---|---|
break | 新しい既定値で失敗する、または Git 3.0 で削除されるものを使っている |
risk | 失敗する可能性が高いが、テキスト走査では判断できない文脈に依存する |
info | いまは動くが、アップグレード時に見直しが必要 |
break があると終了コード1になるので、そのまま CI のチェックとして使えます。--fail-on risk で risk も失敗扱いにでき、--json で機械処理用の出力も得られます。誤検知は行末に git3ready:ignore を書くか、.git3readyignore(gitignore 形式)や --exclude で除外します。
ルールは全18種で、git3ready rules で一覧できます。代表的なものを挙げます。
| ルール | 重大度 | 検出対象 |
|---|---|---|
hex40-pattern | break | 16進数ちょうど40桁の正規表現(同じ行で64桁も受け付けていれば対象外) |
sha1-constant-oid | break | SHA-1 の空ツリー・空 blob の ID、Git 文脈の40個のゼロ |
ref-files-access | break | .git/refs/・packed-refs・.git/logs/ の直接参照 |
head-file-read | break | .git/HEAD をファイルとして読む処理 |
master-after-init | break | ブランチ名を指定しない git init の後で master を参照している |
embedded-bare-repo | risk | ツリー内に Git が bare リポジトリとみなすディレクトリがある |
git-whatchanged など | break | Git 3.0 で削除されるコマンド・オプション・設定の使用 |
git-source-build | info | Git をソースからビルドしている(Rust 必須化の影響) |
rehearse: 新しい既定値でテストを試走する
テキスト走査には限界があります。リポジトリを作るヘルパーと master を参照するテストが別ファイルにあれば、scan ではつながりが見えません。そこで、自分のテストスイートを Git 3.0 の既定値で実際に動かしてみるのが rehearse です。
先ほどの release.sh は、いまの既定値では問題なく動きます。
$ git init -q r && cd r && git commit -q --allow-empty -m x && sh ../scripts/release.sh
release master at bb4ce03d7e17f00146d7d173baf14b541803b0a7同じ手順を rehearse 経由で実行すると、reftable の .git/HEAD スタブを読んで失敗します。
$ git3ready rehearse -- sh -c 'git init -q r && cd r && git commit -q --allow-empty -m x && sh ../scripts/release.sh'
git3ready: rehearsing Git 3.0 defaults: init.defaultObjectFormat=sha256 init.defaultRefFormat=reftable init.defaultBranch=main safe.bareRepository=explicit
cat: .git/refs/heads/.invalid: Not a directory仕組みは単純で、git-config(1) に記載されている GIT_CONFIG_COUNT / GIT_CONFIG_KEY_<n> / GIT_CONFIG_VALUE_<n> の環境変数で、次の4つの設定を子プロセスの Git すべてに注入しています。設定ファイルより優先されるため、グローバル設定で init.defaultBranch=master にしている環境でも試走できます。
観点(--without で個別に外せる名前) | 注入する設定 |
|---|---|
object-format | init.defaultObjectFormat=sha256 |
ref-format | init.defaultRefFormat=reftable |
default-branch | init.defaultBranch=main |
safe-bare-repository | safe.bareRepository=explicit |
普段のテストコマンドの前に付けるだけで使えます。
git3ready rehearse -- cargo test
git3ready rehearse -- npm test
git3ready rehearse --without safe-bare-repository -- ./ci/integration.shGitHub Actions でジョブ全体に適用したい場合は、環境変数を $GITHUB_ENV に書き出します。
- run: git3ready rehearse --print env >> "$GITHUB_ENV"
- run: cargo test注意点として、rehearse では削除予定のコマンドはまだ手元の Git に存在するので、その検出は scan の役割です。また、clone したリポジトリのハッシュ形式はリモートに従うため、既定値の変更は効きません。init.defaultObjectFormat と init.defaultRefFormat を設定で指定できるのは Git 2.47 以降で、それより古い Git では黙って今の挙動のまま動くのではなく、実行を拒否して --without で外すべき観点を案内します。
env: 手元の Git の状態を確認する
git3ready env は、インストール済みの Git の設定と現在のリポジトリが Git 3.0 でどう変わるかを報告します。筆者の環境(Git 2.52.0)での出力です。
$ git3ready env
git3ready env (git version 2.52.0)
OK init.defaultBranch set to master (global config); new repositories keep this name
INFO init.defaultObjectFormat unset: new repositories use sha1 today and sha256 under Git 3.0
fix: Rehearse with git3ready rehearse -- <test command>, or pin sha1 with git config --global init.defaultObjectFormat sha1
INFO init.defaultRefFormat unset: new repositories use files today and reftable under Git 3.0
fix: Rehearse with git3ready rehearse -- <test command>, or pin files with git config --global init.defaultRefFormat files
INFO safe.bareRepository unset: defaults to all today and explicit under Git 3.0 (cd into a bare repository and run git stops working)
fix: Use --git-dir / GIT_DIR for bare repositories, or pin the old behavior with git config --global safe.bareRepository all
OK repository sha1 objects, files refs
Git 3.0 has no planned release date.init.defaultBranch をグローバル設定で固定しているので、ブランチ名は Git 3.0 でも変わらないことが分かります。一方、ハッシュ形式・参照形式・safe.bareRepository は未設定なので、Git 3.0 にすると既定値が切り替わります。
設計で意識したこと
- すべてのルールを一次情報に対応させる: 各ルールは
BreakingChanges.adocの1項目に対応し、rulesの出力とすべてのレポートに、参照したコミット(985b38c)と読んだ日付を表示します。 - リリース日を推測しない: 文書に予定日がない以上、ツールも「いつまでに対応すべき」とは言いません。出力の末尾には毎回「Git 3.0 has no planned release date.」と表示します。
- 挙動は実機で確かめる: reftable リポジトリで
.git/HEADがref: refs/heads/.invalidになること、safe.bareRepository=explicitで bare リポジトリへのgit -Cが失敗することは Git 2.52.0 で観察して規則に反映し、テストでも実行環境の Git に対して再確認しています。 - テキスト照合であることを隠さない: コードを構文解析しないので、コメントやドキュメント内の記述も検出します。その代わり、シェル・YAML・SQL・各種言語をまとめて走査できます。
いまからできる準備
Git 3.0 の日程は未定ですが、準備は既定値に依存しない書き方に寄せるだけなので、いつ始めても無駄になりません。
git3ready scanで、スクリプト・フック・CI のbreakを洗い出す.git/HEADや.git/refs/の直接参照を、git symbolic-ref/git rev-parse/git for-each-refなどのコマンド経由に置き換える- オブジェクト ID を40桁固定で扱っている箇所を、64桁も受け付けるようにする(必要なら
git rev-parse --show-object-formatで形式を確認する) - テストや CI で
git initするときは、git init -b mainのようにブランチ名を明示する git3ready rehearse -- <テストコマンド>を CI に1ジョブ追加し、新しい既定値でも通ることを継続的に確認する- Git をソースからビルドしている環境は、Rust ツールチェインの用意を計画に入れる
Git の内部でハッシュや参照がどう保存されているかは、Gitの内部構造入門で詳しく解説しています。reftable で何が変わるのかを理解する前提知識として参考にしてください。
まとめ
- Git 3.0 では、新規リポジトリの既定が SHA-256・reftable・
mainに変わり、safe.bareRepositoryがexplicitになり、ビルドに Rust が必須になる予定です(Rust は先送りの可能性あり)。 git whatchanged・git pack-redundant・grafts・.git/branches/などは削除されます。- リリース日は未定で、公式文書にも予定日はありません。
- 影響を受けるのは Git 本体ではなく、Git 2.x の既定値を前提にした周辺のスクリプト・フック・テスト・CI です。
- git3ready の
scanで前提箇所を洗い出し、rehearseで新しい既定値のままテストを試走できます。
参考リンク
- git/git Documentation/BreakingChanges.adoc(本記事は
985b38c時点の内容に基づく) - Git 2.55.0 リリースノート
- git-config(1)
- hash-function-transition(SHA-256 移行の設計文書)
- reftable(参照保存形式の仕様)
- printemps-tokyo/git3ready


