更新日:2026年9月29日
17分で読めます
最新のGitリリースにおける新機能と変更点を紹介します。git-history(1)の新しいdropサブコマンド、参照を変更できるようになったgit-refs(1)の新サブコマンド、git-replay(1)による履歴の直線化などを取り上げます。

Gitプロジェクトから先日、Git 2.56.0がリリースされました。GitLabのGitチームによる貢献も含め、今回のリリースの注目点を紹介します。
本記事で取り上げる内容:
drop今回のリリースサイクルは、リスボンで開催されたGit Merge 2026と重なりました。会期は3日間で、初日がJJ Con、2日目がGit Talks、最終日がアンカンファレンスとGit Contributor Summitという構成です。Git Talksのセッションは近日中に公開される予定です。
Git Contributor Summitで大きな議題となったのが、Git 3.0のリリースをめぐる計画でした。GitのDocumentation/BreakingChanges.adocには3.0で予定されている変更がまとめられていますが、これまでは「この破壊的変更を含むバージョンのリリース日は未定」という但し書きが付いていました。その前提が、今回のContributor Summitでの議論によって変わります。
Git 3.0で予定されている主な変更は次のとおりです。
これらの変更を実現するコード自体は、現行のGitにすでに入っています。ただし、Gitのライブラリやアプリケーション、フォージを含むエコシステム全体を見ると、対応状況にはばらつきがあるのが実情です。エコシステム側の対応が追いつかなければ、あるツールでは新機能が使えるのに別のツールでは動かないという宙ぶらりんの状態にユーザーが置かれてしまいます。
なかでもSHA-256については、フォージ側の対応が最大の懸念材料でした。GitLabは1年前からSHA-256に対応しています。GitHubもGit Mergeの場でプライベートベータを発表しており、数か月後には一般公開される見通しです。
こうした状況を踏まえ、サミットでの議論はGit 3.0に向けた次のスケジュールにまとまりました。
| リリース | 時期 |
|---|---|
| 2.56 | 2026年9月(本リリース) |
| 2.98 | 2026年12月 |
| 2.99 および 3.0 | 2027年春 |
2.56の次は2.98へと一気に番号を飛ばす計画です。この大きなジャンプは、大きな変更が近いことをダウンストリームのメンテナーとユーザーの双方に伝えるシグナルになります。その後は2.99と3.0を同時に出荷し、両者の違いは破壊的変更の機能フラグが有効かどうかだけ。こうすることで2.99と3.0の機能を揃えたまま、3.0での変更を小さく限定的に抑えられます。
2.99はLTSリリースと位置付けられ、Rustのツールチェーンを持たないプラットフォームでも引き続きアップデートを受け取れます。詳細については、いつものとおりメーリングリスト上で議論が進みます。
dropGit 2.55のブログ記事では、git-history(1)のfixupサブコマンドを取り上げました。今回のリリースでは、同じコマンドに新しくdropサブコマンドが加わります。
既存のコミットを削除したい場合、これまではgit rebase -iを実行し、エディタ上で対象のコミットを1つずつ対話的にマークするという手順が必要でした。新しいdropサブコマンドを使えば、同じ操作がたった1行で済みます。
$ git history drop <commit>
指定したコミットが削除され、その子孫にあたるコミットは親コミットの上にリベースされます。git-history(1)の他のサブコマンドと同様に、元のコミットの子孫にあたるブランチはすべて、書き換え後のコミットを指すように更新されます。
このパッチはPatrick Steinhardt氏によって提出されました。
マージ済みのブランチを整理するとき、筆者はこれまで次のようなコマンドを使ってきました。
$ git branch --merged main | grep -v main | xargs git branch --delete
ただしこの方法で削除できるのは、指定したブランチにマージされたブランチだけです。mainから分岐してorigin/mainにマージされたブランチは、対象から漏れてしまいます。今回のリリースでは、この課題を埋める2つのフラグが追加されました。
1つ目は--forkedフラグです。これは一覧表示用のフィルターで、設定されたアップストリームが指定した参照・リモート名・ブランチと一致するブランチだけを表示します。
$ git switch --create feature-a origin/main
Switched to a new branch 'feature-a'
branch 'feature-a' set up to track 'origin/main'.
$ git branch --forked origin
feature-a
feature-b
* main
これにより、特定の統合ブランチから派生したブランチを把握できます。各ブランチの状態は次のように確認します。
$ git branch -vv
feature-a b3ebf58 [origin/main: behind 1] Add feature A
feature-b 34c0403 [origin/main: ahead 1, behind 1] Add feature B
* main 230a3b0 [origin/main] Document the parser
この例ではfeature-aがorigin/mainより遅れており、すでにorigin/mainへマージ済みであることを示しています。一方のfeature-bはまだマージされていません。このユーザビリティ上のギャップを埋めるのが、もう1つの新オプション--delete-mergedです。設定されたアップストリームから先端コミットに到達できるブランチをすべて削除するため、統合ブランチにマージ済みのフィーチャーブランチを一括で片付けられます。
$ git branch --delete-merged origin
Deleted branch feature-a (was b3ebf58).
ヒント: これらのオプションは、ブランチが統合ブランチを追跡していることを前提としています。ローカルの統合ブランチから分岐する運用であれば、
branch.autoSetupMergeの設定にあるinheritを確認してみてください。
この機能はHarald Nordgren氏によって提出されました。
Git 2.46で導入されたgit-refs(1)は、参照に関わる操作をまとめる新しい受け皿です。導入以降、ストレージバックエンド間での参照の移行、整合性チェック、既存参照の一覧表示、参照の存在確認といったサブコマンドが順次追加されてきました。今回のリリースで加わったのは、参照のcreate、delete、update、renameへの対応です。
$ git refs list
689f6e8164e070ed133d5176806ad69e31d22142 commit refs/heads/branch-d
689f6e8164e070ed133d5176806ad69e31d22142 commit refs/heads/branch-r
689f6e8164e070ed133d5176806ad69e31d22142 commit refs/heads/branch-u
689f6e8164e070ed133d5176806ad69e31d22142 commit refs/heads/main
$ git refs create refs/heads/branch-c main
$ git refs update refs/heads/branch-u main~1
$ git refs rename refs/heads/branch-r refs/heads/foo
$ git refs delete refs/heads/branch-d
$ git refs list
689f6e8164e070ed133d5176806ad69e31d22142 commit refs/heads/branch-c
c4e9b6bafb7ac9a96c5d9337cd60a0ec6d5a240d commit refs/heads/branch-u
689f6e8164e070ed133d5176806ad69e31d22142 commit refs/heads/foo
689f6e8164e070ed133d5176806ad69e31d22142 commit refs/heads/main
updateとdeleteのサブコマンドでは、変更前の値を任意で指定できます。指定した場合は、操作を実行する前にその値が現在の値と一致するかどうかが検証されます。
これらのパッチはPatrick Steinhardt氏によって実装されました。
今回のリリースは、Google Summer of Codeの4つのプロジェクトがすべて無事に完了した節目でもあります。いずれのプロジェクトにも、GitLabのエンジニアがメンターとして加わりました。
部分クローンを使うと、すべてのオブジェクトをダウンロードしなくてもリポジトリを操作できます。Gitは必要になった時点でオブジェクトを遅延取得する仕組みです。git-cat-file(1)は指定したオブジェクトハッシュのobject-infoを読み取れますが、その際にはオブジェクト全体の転送が発生していました。Git 2.56ではgit-cat-file(1)の--batch-commandモードにremote-object-infoコマンドが追加され、Gitプロトコルv2経由でメタデータだけを要求できるようになりました。blobを一切含まないblobless cloneを例に見てみましょう。
$ git rev-parse HEAD:model.weights
42ec5fc0f485f764cdf0eaa85ab061c055f5f518
$ git cat-file --batch-all-objects --batch-check | grep -c blob
0
$ echo "remote-object-info origin 42ec5fc0f485f764cdf0eaa85ab061c055f5f518" |
git cat-file --batch-command
42ec5fc0f485f764cdf0eaa85ab061c055f5f518 blob 3000000
$ git cat-file --batch-all-objects --batch-check | grep -c blob
0
このようにblob本体を転送することなく、そのサイズだけを取得できます。300万バイト分のネットワーク帯域の節約です。
このプロジェクトはPablo Sabater氏が担当し、Eric Ju氏とCalvin Wan氏が着手していた作業を引き継ぐ形で進められました。メンターはKarthik Nayak氏とChandra Pratap氏です。
部分クローンはblobを遅延取得することで、ディスク容量を大きく節約します。ただし時間が経つにつれて取得したblobが積み重なり、リポジトリが肥大化して当初の利点は薄れがちです。このGSoCプロジェクトで追加されたのが、git-repack(1)の--drop-filteredオプションです。指定したフィルターを超えるサイズのpromisor blobを見つけ出し、ローカルから削除します。
次の例は、履歴に3MBのblobを含むリポジトリをフィルター付きでクローンしたものです。git cloneの直後はリポジトリのサイズが小さいものの、blobを参照しただけでローカルディスクに取得されてしまいます。
$ du -sh .git
144K .git
$ git cat-file -s b8086a678595c9fce29d980f7a12ca069b466f6c
3000000
$ du -sh .git
3.1M .git
このblobはワークツリーには必要ありませんが、自動的に取り除く仕組みはありませんでした。--drop-filteredを実行するとblobが破棄され、将来必要になった時点でGitが改めて遅延取得します。
$ git repack -a -d --filter=blob:limit=1k --drop-filtered
$ du -sh .git
156K .git
このプロジェクトはSiddharth Shrimali氏が担当し、Christian Couder氏とSiddharth Asthana氏がメンターを務めました。
git-repo(1)コマンドは、リポジトリに関する情報を取得するコマンドです。GSoCプロジェクトの一環として、git repo infoサブコマンドにpath.gitdirとpath.commondirが追加されました。いずれも絶対パスと相対パスの両方の形式で取得できます。
$ git repo info --all
layout.bare=false
layout.shallow=false
object.format=sha1
path.commondir.absolute=/home/karthik/code/git/.git
path.commondir.relative=.git
path.gitdir.absolute=/home/karthik/code/git/.git
path.gitdir.relative=.git
references.format=reftable
パス関連の情報をさらに追加するパッチについては、現在メーリングリストで議論が進んでいます。
このプロジェクトはK Jayatheerth氏が担当し、Justin Tobler氏とLucas Seiki Oshiro氏がメンターを務めました。
Gitのコアコードベースは、よく知られたthe_repository変数から数多くの設定オプションに至るまで、いまだにグローバル状態への依存が強く残っています。これがGitのライブラリ化を進めるうえでの障害でした。本プロジェクトでは、グローバルな設定変数の一部をstruct repository上の新しいrepo_config_values構造体へ移しています。呼び出し側も、グローバルなthe_repositoryを使うのではなくstruct repositoryを明示的に渡す形へと更新されました。
このプロジェクトはTian Yuchen氏が担当し、Christian Couder氏、Ayush Chandekar氏、Bello Caleb Olamide氏がメンターを務めました。
git-replay(1)は、サーバーサイドでのリベースを可能にする実験的なコマンドです。動作にワークツリーを必要としません。
$ git log --oneline --graph --all
* 1756840 (main) main: unrelated upstream work
| * 286e7f1 (topic) topic: add two
| * 4324bcd topic: add one
|/
* 9497867 Initial commit
$ git replay --ref-action=print --onto main topic
update refs/heads/topic a144de2fc13ac40c8a481052be5e4d42071c4908 286e7f186f229ac4dd5ecb68a372951003f16224
$ git log --oneline --graph a144de2fc13ac40c8a481052be5e4d42071c4908
* a144de2 topic: add two
* 6422f37 topic: add one
* 1756840 (main) main: unrelated upstream work
* 9497867 Initial commit
ただし、これまでは1つ課題がありました。マージコミットを含むコミット範囲では動作しなかった点です。たとえばfeatureブランチで作業している最中に、mainに入ったバグ修正をfeatureブランチにもマージしたとします。その結果、featureブランチには次のようにマージコミットが含まれます。
$ git log --graph --oneline --decorate --all
* cb996b6 (HEAD -> feature) feature: handle the empty-input edge case
* 4f76f3d Merge branch 'bugfix' into feature
|\
| * 4959734 (main, bugfix) bugfix: do not crash on null input
* | 829b62c feature: add parser tests
* | 7fd60db feature: add the parser
|/
* 9497867 Initial commit
$ git replay --onto main main..feature
fatal: replaying merge commits is not supported yet!
このように、マージコミットが存在するとgit-replay(1)はリベースを拒否します。Git 2.56で追加された--linearizeは、git-rebase(1)ですでにデフォルトとなっている--no-rebase-mergesオプションに近い動作をします。
$ git replay --linearize --onto main main..feature
$ git log --graph --oneline --decorate --all
* da8df6e (HEAD -> feature) feature: handle the empty-input edge case
* f68889f feature: add parser tests
* f13885b feature: add the parser
* 4959734 (main, bugfix) bugfix: do not crash on null input
* 9497867 Initial commit
この機能はToon Claes氏によって提出されました。
2.54のリリースブログでは、プラグイン可能なオブジェクトデータベースとは何か、どのように動作するのかを解説しました。おさらいすると、Gitはオブジェクト(blob、tree、commit)を.git/objects配下に2種類の形式で保存します。個別のファイルとして置かれる「loose」オブジェクトと、複数のオブジェクトをまとめて圧縮した「パックファイル」です。これまでは抽象化レイヤーが存在せず、各サブシステムがストレージ層に直接手を伸ばしてオブジェクトを操作していました。2.54でようやく抽象化レイヤーが導入され、この状況が変わっています。
今回のリリースでは、バックエンドを真の意味でプラグイン可能にするために必要なインターフェースの整備が、さらに一歩進みました。具体的には次のとおりです。
.git/objectsフォルダーが作成されますが、この責務が個々のバックエンド側に移りました。struct odb_streamに一本化され、任意のオブジェクト型をストリーム処理できるようになりました。ほかにも多くの変更が含まれています。これだけ大量の変更が入ったにもかかわらず、ユーザーから見た挙動は何も変わりません。これは意図したとおりの結果です。GitLabにとっては、必要に応じてバックエンドを差し替えられるようになることで、Gitを大規模に運用するための基盤が整うことを意味します。しかもそれを、Gitコミュニティの一員として進められます。続報にご期待ください。
これらの変更はJustin Tobler氏とPatrick Steinhardt氏の共同作業によって提出されました。
本記事では、今回のリリースに対するGitLabとGitコミュニティからの貢献のごく一部を紹介しました。全体像については、Gitプロジェクトの公式リリースアナウンスをご覧ください。また、これまでのGitリリースのブログ記事では、GitLabチームメンバーによる過去の貢献の数々を紹介しています。
無料の
30日間のGitLabトライアルを開始
クレジットカードなしでご登録いただけます。
このブログ記事を楽しんでいただけましたか?ご質問やフィードバックがあればお知らせください。GitLabコミュニティフォーラムで新しいトピックを作成してあなたの声を届けましょう。
フィードバックを共有する