はじめに
2026年9月28日(米国時間)、分散バージョン管理システム Git 2.56.0 がリリースされました。メンテナの Junio C Hamano 氏の告知によると、2.55 から 748 のコミットが入り、104 人が貢献し、そのうち 39 人は初めての貢献者です。
新機能は多いのですが、日々の作業に効くのは次の 3 つです。
git add --resolved— マージで衝突したファイルのうち、解決が済んだものだけをステージする。衝突マーカーが 1 つでも残っていれば、何もステージしない- マージベース探索の早期終了 — 2 本のブランチの「共通の祖先」を探す走査を、もう新しい候補が出ないと分かった時点で打ち切る。設定は不要で、大きなリポジトリほど速くなる
git history drop— 途中のコミットを 1 つ取り除き、その後ろのコミットを載せ直す。まだ実験的なコマンド
この記事のゴールは 2 つです。コンフリクト解消の最後の一手を、安全な手順に置き換えられるようになること。そして、大きなリポジトリでマージや比較が速くなる理由を、仕組みから説明できるようになることです。そのために、土台となる「マージベース」と、サーバー側で効く「path-walk repack」の考え方から順に見ていきます。
git add --resolvedは、衝突したファイルだけを見てステージする。 マーカーが残っていれば全体を止めるので、関係ない編集や解き忘れを一緒にコミットしにくくなる- マージベースの探索は、片側の候補が尽きた時点で止まるようになった。 GitHub のモノレポでは 20〜70 倍速くなった例があり、Linux カーネルの v4.8 と v4.9 では走査が 167,441 手から 3,887 手に減った
git history dropは、rebase を使わずにコミットを 1 つ抜く。 衝突しそうなときやマージを含む履歴では最初から止まる、慎重な作りになっている
🧭 1. マージベースとは — 3-way マージの「共通の祖先」
2 本のブランチは、どこかで分かれている
Git のブランチは、コミットの鎖の先端を指す名札です。main から topic ブランチを切って作業すると、2 本の鎖はある 1 つのコミットから枝分かれします。この分かれ目のコミットがマージベース(merge base・共通の祖先)です。
矢印は「親を指す」向きです。main は B→C→D と進み、topic は B→X→Y と進みました。2 本をマージするとき、Git は 3 つの版を突き合わせます。
| 突き合わせる版 | 役割 |
|---|---|
| マージベース B | 「分かれる前はこうだった」という基準 |
| main の先端 D | こちら側の変更 |
| topic の先端 Y | あちら側の変更 |
基準の B と比べて片側だけが変えた行は、その変更を採用します。両側が同じ行を別々に変えたときだけ、Git は決められずに衝突(コンフリクト)として人に委ねます。これが 3-way マージです。基準がなければ「どちらが変えたのか」が分からないので、マージベースはマージの出発点そのものです。
マージのほかにも、git diff main...topic(ドット 3 つ)の比較や、GitHub のプルリクエストの差分表示・マージ可否の判定も、裏でマージベースを計算しています。
なぜ探索が重くなるのか
Git は 2 つの先端から親をたどって過去へ歩き、両方から届いたコミットを探します。GitHub Blog の説明にならうと、片側から届いたコミットを青、もう片側から届いたものを赤で塗り、両方の色がついたコミットがマージベースの候補です。
難しいのは「1 つ見つけたら終わり」ではない点です。マージを互い違いに繰り返した履歴(criss-cross merge)では、互いに祖先関係のないマージベースが複数できます。Git はそれを全部返すために、もう新しい候補が出ないと確信できるまで歩き続けます。従来の止め方では、すでに両側に塗られた古い履歴の長い尻尾を、必要がないのに処理し続けることがありました。古い枝をたくさん取り込んだ長い履歴、つまりモノレポで重くなるのはこのためです。
⚙️ 2. Git 2.56 の新機能 3 つ
| 機能 | これまでの困りごと | 2.56 で |
|---|---|---|
git add --resolved |
git add -u だと関係ない変更や解き忘れまでステージされる |
衝突したファイルだけを見る。マーカーが残れば何もしない |
| マージベースの早期終了 | 古い履歴の尻尾まで歩いて遅い | 片側の候補が尽きたら止まる(自動) |
git history drop |
コミット 1 つ抜くのに rebase -i を開く | コマンド 1 行で抜いて載せ直す |
① 衝突を解決したファイルだけステージする:git add --resolved
困っていたこと
衝突の解消は 2 段階です。まず作業ツリーのファイルを直し、次に git add で「解決した」と Git に伝えます。この 2 段目でよく使う git add -u は、変更のある追跡ファイルをすべてステージします。マージを始める前から手元に別の編集があれば、それも一緒にマージコミットへ入ってしまいます。<<<<<<< のマーカーを 1 か所消し忘れていても、そのままステージされます。
どう変わるか
--resolved は、インデックス上でいま衝突中(unmerged)のパスだけを対象にします。ステージする前に、それらのファイルに衝突マーカーが残っていないかを調べ、1 つでも見つかればどのファイルもステージせず、残っているパスを表示して止まります。全部か無しか、の設計です。
- 衝突していない追跡ファイルは無視する(手元の関係ない編集はステージされない)
- パス指定で対象を絞れる。絞った範囲の中でも「1 つでもマーカーがあれば全部止める」は同じ
- 削除で解決した衝突やバイナリの衝突はマーカーがないので、そのままステージされる
-uや-Aとは組み合わせられない
コマンド例
GitHub Blog の例では、recipe.txt がマージで衝突し、notes.txt にはマージと関係ない手元の編集があります。
$ git add --resolved
fatal: the following paths still have conflict markers:
recipe.txt
$ # recipe.txt のマーカーを消して直す
$ git add --resolved
$ git status --short
M notes.txt
M recipe.txt
git status --short の左の列はステージ済み、右の列は未ステージの変更です。recipe.txt だけが解決済みとしてステージされ、notes.txt は手元の編集のまま残っています。
② マージベース探索の早期終了
困っていたこと
1 章で見たとおり、マージベースを全部見つけるには「もう新しい候補は出ない」と言えるところまで歩く必要があります。従来の止め方はこの判断が遅く、候補が出る見込みのない古い履歴を長々と処理していました。
どう変わるか
2.56 は、走査の待ち行列に残っているコミットのうち、片側の色だけに塗られたものが何個あるかを数えます。どちらかの側の「自分だけの」コミットが尽きれば、2 本が新しく出会う場所はもう現れません。そこで走査を止めても、マージベースはすべて返せます。実装にはこの規則を守るための追加の条件もあると GitHub Blog は書いています。
オプションも設定も要りません。 git merge・git merge-base・git diff A...B など、マージベースを計算するコマンドは自動で速くなります。GitHub Blog が挙げた数字は次のとおりです。
- ある実在のモノレポで、走査が 0.68 秒から 0.01 秒に
- 本番環境での評価では、大きなモノレポの 1 つで約 70 倍速くなった例が多く、もう 1 つでは平均で約 20 倍
- Linux カーネルで
git merge-base --all v4.8 v4.9を実行すると、走査が 167,441 手・0.29 秒から 3,887 手・0.01 秒に(既定の v2 commit-graph の場合)
コマンド例
# 2 つの先端のマージベースをすべて表示する(コマンドは従来どおり)
git merge-base --all main topic
# topic で何をしたかをマージベースから比べる(ドット 3 つ)
git diff main...topic
③ コミットを 1 つ取り除く:git history drop
困っていたこと
途中のコミットを 1 つだけなかったことにしたいとき、これまでは git rebase -i でエディタを開き、該当行を drop に書き換えていました。作業ツリーを使うので、手元に未コミットの変更があると面倒です。
どう変わるか
git history は 2.54 で reword と split を持って登場し、2.55 で fixup が加わった実験的なコマンドです。2.56 で drop が加わりました。指定したコミットを取り除き、その子孫をコミットの親の上に載せ直します。慎重な作りで、次の場合は最初から止まります。
- 子孫を載せ直すと衝突する場合(
git historyは途中で止まって続きを待つ「状態を持つ」操作をしない設計) - 履歴にマージコミットを含む場合(
git rebase --rebase-mergesを使うよう案内されている) - ルートコミット(最初のコミット)やマージコミット自体を落とそうとした場合
HEAD が動くときは、手元の関係ない変更を保ったままインデックスと作業ツリーを更新します。手元の変更を上書きしてしまう場合は、参照を更新する前に中止します。
コマンド例(公式ドキュメントの例)
$ git log --oneline
abc1234 (HEAD -> main) third
def5678 second
ghi9012 first
$ git history drop 'main^{/second}'
$ git log --oneline
jkl3456 (HEAD -> main) third
ghi9012 first
second が消え、third が first の上に載り直しました。載せ直したので third のハッシュも変わっています。落としたコミットを指していたブランチは、その親へ移ります。--dry-run を付けると参照は更新せず、行われるはずの参照の更新を git update-ref が読める形式で表示します。
取り消せるか
drop は履歴の書き換えなので、落としたコミットのオブジェクトはすぐには消えません。さらに git history drop は、reflog(参照の移動記録)に drop: dropping main^{/second} という自前の記録を書きます。この記録が HEAD@{0} になり、1 つ前の HEAD@{1} が drop 前の位置です。戻すときは git reset --hard HEAD@{1} のような、reflog を使う一般的な手順で戻せます(4 章③に実際の出力を載せています)。
📦 3. path-walk repack とは — 同じパスの版を並べて圧縮する
Git はオブジェクトを「パック」という 1 つのファイルにまとめるとき、似たオブジェクト同士を差分(デルタ)で保存して容量を減らします。問題は、何千何万とあるオブジェクトの中から「似ている相手」をどう探すかです。
| 探し方 | 似ている相手の見つけ方 |
|---|---|
| 従来(name-hash) | ファイル名から作ったハッシュで候補を寄せる。違うパスの同名ファイルが混ざりやすい |
| path-walk | ツリーをパスの順に歩き、同じパスの歴代の版を並べてから差分を探す |
同じパスの版どうしは中身も近いので、path-walk のほうが良い差分を見つけやすくなります。GitHub Blog によると、Fluent UI のリポジトリで差分を計算し直した比較では、通常のパックが 558.5 MB、--path-walk では 164.4 MB と、約 71% 小さくなりました。
使うコマンドは git repack --path-walk(内部で git pack-objects --path-walk を呼ぶ)で、設定 pack.usePathWalk で既定にもできます。これまでは、GitHub のようなホスティング事業者が使う 2 つの仕組みと併用できませんでした。
- 到達可能性ビットマップ:どのコミットからどのオブジェクトが届くかを前計算した表。クローンや fetch への応答を速くする
- デルタアイランド:ある参照の集まり(たとえばフォークごと)のオブジェクトが、別の集まりにしかないオブジェクトを差分の元にしないようにする規則
2.56 はこの 2 つの制約を外しました。path-walk で作ったパックでもビットマップを書けるようになり、ビットマップで答えられない要求だけを path-walk で処理します。既定で有効になったわけではありません。 大きなホスティング事業者が、速い配信と隔離の規則を保ったまま、小さいパックを試せるようになった、という段階です。
🛠️ 4. 手元で試す手順 — いまの Git を置き換えずに
2026年10月1日時点で、2.56 の入手先は次のとおりです。
| OS | 入手先 | 状況(10/1 時点) |
|---|---|---|
| Windows | Git for Windows v2.56.0.windows.1 | 9/28 公開。インストーラ・Portable 版・MinGit あり |
| Windows | winget(Git.Git) |
2.56 のマニフェストはまだない |
| Ubuntu | git-core PPA | 最新は 2.55.0。2.56 はまだ |
| Ubuntu | kernel.org のソース | git-2.56.0.tar.xz から自分でビルドできる |
どちらの OS でも、いま使っている Git を上書きせず、別の場所に 2.56 を置いて試す手順にします。
Windows:Portable 版を展開する
- Git for Windows のリリースページから
PortableGit-2.56.0-64-bit.7z.exe(ARM 機はarm64)をダウンロードする - 実行して、展開先を
C:\tools\PortableGit-2.56など既存の Git と別のフォルダにする - 展開先の
git-bash.exeを起動し、git versionを実行する
インストーラ版と違い、Portable 版は PATH やレジストリを書き換えません。以下の操作はこの git-bash.exe の窓の中で行います。Git for Windows の既定(core.autocrlf=true)では、printf で作った LF のファイルを add すると「LF will be replaced by CRLF」という警告が出ますが、改行コードについての警告で、手順の結果には影響しません。
Ubuntu:ホームの下にビルドする
sudo apt install build-essential libssl-dev libcurl4-gnutls-dev \
libexpat1-dev gettext zlib1g-dev
wget https://www.kernel.org/pub/software/scm/git/git-2.56.0.tar.xz
tar xf git-2.56.0.tar.xz && cd git-2.56.0
make prefix="$HOME/git-2.56" NO_TCLTK=YesPlease all
make prefix="$HOME/git-2.56" NO_TCLTK=YesPlease install
"$HOME/git-2.56/bin/git" version
/usr/bin/git はそのまま残ります。以下の操作は、export PATH="$HOME/git-2.56/bin:$PATH" を実行した端末の中で行います。
① わざと衝突を作って --resolved を試す
git init -b main try-resolved && cd try-resolved
printf 'salt\nsugar\nflour\n' > recipe.txt
echo 'memo' > notes.txt
git add . && git commit -m "base"
git switch -c topic
sed -i 's/sugar/honey/' recipe.txt && git commit -am "topic: honey"
git switch main
sed -i 's/sugar/maple/' recipe.txt && git commit -am "main: maple"
echo 'local edit' >> notes.txt # マージと関係ない手元の編集
git merge topic # recipe.txt が衝突する
git add --resolved # マーカーが残っているので止まる
# recipe.txt を開いて <<<<<<< ======= >>>>>>> を消し、1 行に直す
git add --resolved
git status --short # recipe.txt だけがステージされている
git commit --no-edit
実行結果(Git 2.56.0.windows.1・Portable 版):
$ git add --resolved
fatal: the following paths still have conflict markers:
recipe.txt
$ git status --short
M notes.txt
UU recipe.txt
$ # recipe.txt のマーカーを消して 1 行に直す
$ git add --resolved
$ git status --short
M notes.txt
M recipe.txt
1 回目はマーカーが残っているので何もステージされず、recipe.txt は衝突中(UU)のままです。直したあとの git status --short で、notes.txt が未ステージ(右の列に M)のまま残っていれば、関係ない編集がマージコミットに紛れ込まなかったことになります。
② マージベースの計算を新旧で比べる
git merge-base --all main topic
小さなリポジトリでは差は出ません。手持ちで一番長い履歴のリポジトリで、いつもの Git と 2.56 の両方から同じコマンドに time を付けて比べると、早期終了の効き目が見えます。
③ git history drop でコミットを 1 つ抜く
git history はマージを含む履歴では動かないので、新しいリポジトリで試します。
git init -b main try-drop && cd try-drop
for n in first second third; do echo "$n" > "$n.txt"; git add .; git commit -m "$n"; done
git log --oneline
git history drop --dry-run 'main^{/second}' # 参照の更新予定だけを表示
git history drop 'main^{/second}'
git log --oneline # second が消えている
git reflog -3 # drop 前の位置が HEAD@{1} に残る
実行結果(Git 2.56.0.windows.1・Portable 版):
$ git history drop --dry-run 'main^{/second}'
update refs/heads/main 59bff5bd7e63a6803e4e7cf10cc6c6f22128d63b 22b3eb97897fe51e9445a2d8f35c403144432172
$ git history drop 'main^{/second}'
$ git log --oneline
59bff5b third
9492fd8 first
$ git reflog -3
59bff5b HEAD@{0}: drop: dropping main^{/second}
22b3eb9 HEAD@{1}: commit: third
b3ff434 HEAD@{2}: commit: second
--dry-run の行は「update 参照名 新しい値 古い値」の順で、新しい値 59bff5b… が drop 後の third、古い値 22b3eb9… が drop 前の third です。本番の drop は何も表示せずに終わり、reflog の先頭に drop: dropping main^{/second} という記録が残ります。
💭 所感 — 人と AI が同じ作業ツリーを触るなら
ここからは筆者の意見です。
当サイトは、AI のワーカーが下書きを作業ツリーに書き、人がそれを確かめて push する運用です。作業ツリーには、いつも誰かの書きかけの変更があります。この状態で pull やマージが衝突すると、git add -u は書きかけまでまとめてマージコミットに入れてしまいます。--resolved の「衝突したファイルしか触らない・マーカーが残れば止まる」という性質は、まさにこの状況のための安全柵だと感じました。AI エージェントに衝突の解消を任せるなら、指示書に「解決後は git add --resolved でステージする」と 1 行書いておく価値があります。解き忘れがあればエージェント自身が止まって気づけるからです。
もう 1 つ考えたのは、先日の ZCode の記事で扱った「.git に消した秘密が残る」話との関係です。git history drop でコミットを抜いても、オブジェクトと reflog はしばらく .git に残ります。取り消せるのは長所ですが、秘密を消す道具ではありません。push 済みならリモートにも残っています。秘密をコミットしてしまったときは、まず失効・再発行し、そのうえで git-filter-repo で履歴から取り除く、という順番は変わらないと考えています。
⚠️ 注意点
git historyは実験的なコマンド:公式ドキュメントに「振る舞いは変わる可能性がある」と明記されています。フックも今のところ実行しません。チームの共有ブランチで使う前に、手元で挙動を確かめてください- 配布のタイミングは OS とパッケージで違う:10月1日時点で、Git for Windows は公開済み、winget と Ubuntu の git-core PPA は 2.55 のままです。パッケージマネージャで更新する場合は、
git versionで 2.56 になったかを確かめてから新機能を使ってください --resolvedはテキストのマーカーを探す:削除で解決した衝突やバイナリの衝突は、マーカーがないのでそのままステージされます。バイナリは中身を自分で確かめてから進めます- path-walk は既定では無効:個人のリポジトリで
--path-walkを付けて repack すると、差分の計算に時間がかかることがあります。試すなら大きなリポジトリのコピーで
✅ まとめ
- Git 2.56.0 が 2026年9月28日に出た。 748 コミット・104 人(うち 39 人が初参加)
git add --resolvedで、衝突の後始末が安全になった。 衝突したパスだけを見て、マーカーが残っていれば何もステージしない- マージベースの探索が、片側の候補が尽きた時点で止まるようになった。 設定不要で、モノレポでは 20〜70 倍、Linux カーネルの例では走査が 167,441 手から 3,887 手に減った
git history dropで、コミットを 1 つ抜いて子孫を載せ直せる。 衝突やマージを含む場合は最初から止まる慎重な設計で、まだ実験的- path-walk repack が、ビットマップやデルタアイランドと併用できるようになった。 大きなホスティング事業者が小さいパックを試せる段階に進んだ
- 次の一手は、手元で衝突を 1 回作ってみること。 Portable 版やホーム下のビルドなら、いまの Git を置き換えずに試せる
よくある質問(FAQ)
Q: git add --resolved と git add -u は何が違いますか?
A: -u は変更のある追跡ファイルをすべてステージします。--resolved はインデックス上で衝突中のパスだけを対象にし、衝突マーカーが 1 つでも残っていれば何もステージしません。マージ前からあった関係ない編集はステージされずに残ります。2 つは組み合わせられません。
Q: マージベースの早期終了を使うには、設定が必要ですか?
A: 必要ありません。Git 2.56 の内部の改良で、git merge・git merge-base・git diff A...B など、マージベースを計算するコマンドが自動で恩恵を受けます。小さなリポジトリでは差はほとんど出ず、古い枝をたくさん取り込んだ長い履歴ほど効きます。
Q: git history drop と git rebase -i の drop は何が違いますか?
A: 結果は似ていますが、git history drop はエディタを開かずコマンド 1 行で済み、作業ツリーを使わずに載せ直します。そのかわり、載せ直しで衝突する場合やマージを含む履歴では最初から中止します。衝突を解きながら進めたいなら、従来どおり git rebase -i を使います。
Q: git history drop で落としたコミットは元に戻せますか?
A: 戻せます。git history drop は reflog に drop: dropping <指定したコミット> という記録を書くので、git reflog を見るとその 1 つ前(HEAD@{1})が drop 前の位置です。git reset --hard HEAD@{1} のような一般的な手順で戻せます。落としたコミットのオブジェクトもすぐには消えません。逆に言えば、秘密を消す目的には使えません。秘密は失効・再発行したうえで、git-filter-repo などで履歴から取り除きます。
Q: いまの Git を上書きせずに 2.56 を試せますか?
A: Windows は Git for Windows の Portable 版(PortableGit-2.56.0-64-bit.7z.exe)を別フォルダに展開し、その中の git-bash.exe から使えます。Ubuntu は kernel.org のソースを make prefix="$HOME/git-2.56" でホームの下にビルドすれば、/usr/bin/git はそのまま残ります。
関連記事
- ZCode の .git 送信問題と OSS 化|ワークスペース同期とは・自分の AI エージェントの送信範囲を確かめる手順 —
.gitの objects・reflog に消した秘密が残る仕組み - Claude Code スキルで ESP32 開発を自動化|idf.py を直接叩く — AI エージェントに渡す手順を「スキル」として書く
- 自作 Web アプリに MCP を生やして Claude Code から書き込む|状態を持つ MCP サーバーの作り方 — 人と AI が同じ作業を分担する仕組みづくり
参考
- [ANNOUNCE] Git v2.56.0(LWN 転載):Junio C Hamano 氏の告知メール(2026年9月28日 10:20 -0700)。748 の非マージコミット・104 人・うち 39 人が初参加
- Highlights from Git 2.56(GitHub Blog):2026年9月28日・Elijah Newren 氏。
--resolvedの例、マージベースの計測値(0.68 秒→0.01 秒・約 70 倍・平均約 20 倍・167,441 手→3,887 手)、path-walk の計測値(558.5 MB→164.4 MB) - Git v2.56 Release Notes:機能名・オプション名の表記はこれに従った
- git-add・git-history・git-pack-objects(v2.56.0 タグの版):
--resolvedの仕様、dropの制限と例、--path-walkとビットマップの関係 - Git for Windows v2.56.0.windows.1:2026年9月28日公開
- winget(
Git.Git)と Ubuntu の git-core PPA は、10月1日時点で 2.55 系が最新