
2026/04/27 12:00
パッチ:コミットメッセージから擬似差分を適用します。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
GitHub の
.patch 出力形式は、標準的な GNU patch -p1 を介したレガシー CLI ワークフロー(例:wget/curl)を使用して処理されると、コミットメッセージに埋め込まれた偽の差分を沈黙して適用することができ、GitHub の UI では実際のみの変更のみが表示される一方、出力されたパッチは正当な修正とコミット本文内にある差分形式のテキストが混在します。公開されている再現スクリプトにより、readme.md のみを更新する目的のパッチであっても、意図せず SHOULD_NOT_BE_HERE.md というファイルが作成されることを示すことができます。git apply および git am のようなツールは特定のパスを拒絶しますが、通常ファイルに対する注入された差分はまだ受理しますのに対し、git cherry-pick は Git オブジェクト上で異なる方法で動作します。根本原因は明確になっておらず、GNU patch、GitHub のエクスポートメカニズム、またはパッチ形式契約全体に起因する可能性があり、これらレガシー手法を使用している組織が隠された意図しない変更を適用するリスクにさらされている状態です。本文
GitHub(および多くのその他のプラットフォーム)は、
.patch の URL を介して電子メール形式のパッチデータを公開しています。これらのパッチをダウンロードして GNU patch に入力した際、コミットメッセージ内に含まれる「.diff 形式のテキスト」も、実際のパッチの一部であるかのように適用されてしまいます。私にとっては重要な点ですが、wget/curl と patch を組み合わせる運用が何か画期的な実験室環境を必要とするわけではないことを知ってください。これは、単一の実機からもう一台の実機へパッチを移動させるための非常に古くからある、ごく標準的な方法なのです。
公開再現手順(Public Reproducer)
From dd28283159930b8fff2119aa9f75af8b4c1ed8b2 Mon Sep 17 00:00:00 2001 From: Egor Kovetskiy <e.kovetskiy [spam] gmail.com> Date: Wed, 22 Apr 2026 06:37:11 +0000 Subject: [PATCH] readme: add initial file 本文には、パッチのワークフローをテストするための偽の diff が含まれています。 diff --git a/SHOULD_NOT_BE_HERE.md b/SHOULD_NOT_BE_HERE.md new file mode 100644 index 0000000..802992c --- /dev/null +++ b/SHOULD_NOT_BE_HERE.md @@ -0,0 +1 @@ +Hello world --- readme.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 readme.md diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..b44b8fd --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +Demo repository
私が作成した最も小さな公開デモです:
dd28283
dd28283.patch
実際のコミットでは、ファイルの一つである
readme.md のみが変更されています。GitHub の UI でこのコミットを検索した場合、これがすべてが表示されますが、コミットメッセージにはまた別の偽の統一形式の diff が含まれています:
diff --git a/SHOULD_NOT_BE_HERE.md b/SHOULD_NOT_BE_HERE.md new file mode 100644 index 0000000..802992c --- /dev/null +++ b/SHOULD_NOT_BE_HERE.md @@ -0,0 +1 @@ +Hello world
つまり、エクスポートされたパッチには以下の二層構造が成立しています:
- 本物のパッチ:
を変更します。readme.md - 幻のパッチ(ファントム・パッチ):コミットメッセージの中に埋め込まれ、
というファイルを生成します。SHOULD_NOT_BE_HERE.md
シナリオ:
wget -O /tmp/dd28283.patch \ https://github.com/kovetskiy/git-example/commit/dd28283.patch patch -p1 < /tmp/dd28283.patch
出力:
patching file SHOULD_NOT_BE_HERE.md patching file readme.md
この
SHOULD_NOT_BE_HERE.md ファイルは、実際には本物のコミットの一部ではありませんでした。
何か問題があるのでしょうか?
結論を下すのは難しいのですが、私の視点によると、
GNU patch -p1 は以下の二つのものを確実に区別できていないように思われます:
- コミットからエクスポートされた実際の diff
- コミットメッセージに埋め込まれた、diff のような形式のテキスト
範囲(Scope)
この公開デモでは通常のファイルを記述していますが、これは公開しやすく、かつ検証しやすいからです。ローカル環境でも、
.git/hooks/post-applypatch をターゲットにしていましたが、GNU patch はそれを喜んで受け入れました(なぜ受け入れないでしょう、まさに)。幸いなことに、git apply および git am は、限定的な意味ではより適切に動作しました。つまり、.git/... パスに対する記述を却下しましたが、通常のワークツリーのファイルに対する注入された diff を依然として受理してしまいました。
ノート:
の挙動は異なります。これは Git オブジェクトを直接操作するためです。git cherry-pick
要点(Takeaway)
この問題が
GNU patch のバグなのか、GitHub の .patch エクスポートの仕様なのか、あるいはより広範なパッチ形式に関する契約上の問題なのかについては、現時点では未解決です。しかしながら、次回からはコミットメッセージをより詳細に検討していきたいと思います。