Git 3.0 で何が変わるのか - SHA-256・reftable・main 既定化と、備えるための自作ツール git3ready

Git 3.0 で何が変わるのか - SHA-256・reftable・main 既定化と、備えるための自作ツール git3ready

作成日:
読了:約25分
更新日:
この記事を読む人におすすめPR / Amazonアソシエイト

当サイトは 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主な理由(文書より)
新規リポジトリのハッシュ関数sha1sha256SHA-1 は NIST が2011年に非推奨化し、SHAttered(2017)や Shambles(2020)など実用的な攻撃が出ている
新規リポジトリの参照(ref)保存形式filesreftable大文字小文字だけ違う参照名の衝突、packed-refs の全書き換え、複数参照更新の非アトミック性などを解消
新規リポジトリの既定ブランチ名mastermain2020年12月から警告を出してきた。主要フォージの既定と揃える
safe.bareRepository の既定allexplicit埋め込まれた 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 --stdingit name-rev --annotate-stdin
git whatchangedgit 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-patternbreak16進数ちょうど40桁の正規表現(同じ行で64桁も受け付けていれば対象外)
sha1-constant-oidbreakSHA-1 の空ツリー・空 blob の ID、Git 文脈の40個のゼロ
ref-files-accessbreak.git/refs/・packed-refs・.git/logs/ の直接参照
head-file-readbreak.git/HEAD をファイルとして読む処理
master-after-initbreakブランチ名を指定しない git init の後で master を参照している
embedded-bare-reporiskツリー内に Git が bare リポジトリとみなすディレクトリがある
git-whatchanged などbreakGit 3.0 で削除されるコマンド・オプション・設定の使用
git-source-buildinfoGit をソースからビルドしている(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-formatinit.defaultObjectFormat=sha256
ref-formatinit.defaultRefFormat=reftable
default-branchinit.defaultBranch=main
safe-bare-repositorysafe.bareRepository=explicit

普段のテストコマンドの前に付けるだけで使えます。

git3ready rehearse -- cargo test
git3ready rehearse -- npm test
git3ready rehearse --without safe-bare-repository -- ./ci/integration.sh

GitHub 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 の日程は未定ですが、準備は既定値に依存しない書き方に寄せるだけなので、いつ始めても無駄になりません。

  1. git3ready scan で、スクリプト・フック・CI の break を洗い出す
  2. .git/HEAD や .git/refs/ の直接参照を、git symbolic-ref / git rev-parse / git for-each-ref などのコマンド経由に置き換える
  3. オブジェクト ID を40桁固定で扱っている箇所を、64桁も受け付けるようにする(必要なら git rev-parse --show-object-format で形式を確認する)
  4. テストや CI で git init するときは、git init -b main のようにブランチ名を明示する
  5. git3ready rehearse -- <テストコマンド> を CI に1ジョブ追加し、新しい既定値でも通ることを継続的に確認する
  6. 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の内部構造入門 - blob・tree・commitとpackfileで理解するバージョン管理の実体

Gitの内部構造入門 - blob・tree・commitとpackfileで理解するバージョン管理の実体

約33分

Gitの.git/objectsに何が保存されているのかを、手元で実行できるコマンドとともに解説します。オブジェクトIDがどう計算されるか、blob/tree/commitの生バイト列、ブランチやHEADの正体、.git/indexとreflogの実体、そしてpackfileのdelta圧縮まで。公式ドキュメントとPro Gitを出典に、スナップショットモデルと差分圧縮という2層の設計を整理します。

leak-museum を公開 - git でシークレットを漏らす26の悪例を「博物館」にした教材リポジトリ

leak-museum を公開 - git でシークレットを漏らす26の悪例を「博物館」にした教材リポジトリ

約11分

git でシークレット(秘密情報)を漏洩させる代表的なアンチパターンを26個「展示」した自作OSS「leak-museum」を公開しました。committed .env、クラウドキー、SSH/TLS秘密鍵、Kubernetes Secret(base64は暗号化ではない)、消したつもりでも履歴に残るケース、フロントエンドのバンドル+ソースマップ、弱いJWT署名鍵まで、なぜ壊滅的かと正しい対処をセットで解説。全て偽の資格情報で、gitleaks / trufflehog などシークレットスキャナーのテスト用コーパスとしても使えます。設計意図(スキャナーの盲点を突く展示、push protection 対策の意図的な破損)と、正しい手本 good-example・チェックリストまで紹介します。