git format-patch と git am をマスターする:メールによるプロフェッショナルなコード送信ワークフロー

Git tutorial - IT technology blog
Git tutorial - IT technology blog

メールによるコード送信:古くて新しい、色褪せない手法

GitHubで「Create Pull Request」ボタンを押すことに慣れていると、メールでコードを送るというのは、少し……手動すぎるように聞こえるかもしれません。しかし、Linux Kernel、Git、PostgreSQLといったテクノロジー界の巨頭たちは、数十年にわたりメーリングリストとパッチファイルに基づいた運用を続けています。これは保守的だからではなく、非中央集権性と効率性を追求した結果の選択なのです。

私は以前、極めて高いセキュリティ要件が求められる金融プロジェクトに参加したことがあります。Gitサーバーはインターネットから隔離されたネットワーク(エアギャップ)内にあり、中央サーバーにコードをpushすることは不可能でした。その際、git format-patchgit am が、コミット履歴や作成者情報を完全に保持したままチーム内でコードをやり取りするための唯一の手段となりました。

クイック比較:Pull Request と Email Patch

なぜオープンソースの「ベテラン」たちは、現代的なプラットフォームではなくメールを優先するのでしょうか?

1. Pull Request (GitHub/GitLab)

  • メリット: 直感的なWebインターフェース、コードレビューのしやすさ、統合されたCI/CD。
  • デメリット: プラットフォームへの完全な依存(ベンダーロックイン)。アカウント作成やリポジトリのフォークといった、やや煩雑な手順が必要です。

2. Email Patch (format-patch & am)

  • メリット: 究極の非中央集権性。メンテナのメールアドレスさえあれば貢献を送ることができます。パッチファイルは非常に軽量(通常は数KB)でありながら、作成者、日付、コミットメッセージなどのメタデータをすべて含んでいます。
  • デメリット: 学習曲線が急であり、議論の流れを管理するために優れたコマンドライン(CLI)スキルが求められます。

パッチが必要となる3つの現実的なシナリオ

Linux Kernelだけでなく、このコンビは以下のようなケースで非常に有用です:

  1. オフライン環境: 外部接続が遮断された社内ネットワークや、共有Gitサーバーがダウンしている場合。
  2. クイックな修正案の送付: サーバー上に一時的なブランチを作る代わりに、パッチファイルを書き出してSlackで同僚に送り、30秒でテストしてもらうことができます。
  3. 純粋なオープンソースプロジェクト: 簡素さを優先し、Microsoft (GitHub) のような巨大企業への依存を避けたいコミュニティ。

ステップ1:git format-patch でパッチファイルを書き出す

feature-fix ブランチで機能実装を完了したと仮定します。コミットをファイルにパッケージ化するには、次のコマンドを使用します:

# 最新の1コミットのみを書き出す
git format-patch -1 HEAD

# mainブランチと比較してfeature-fixブランチの全コミットを書き出す
git format-patch main..feature-fix

Gitは 0001-ten-commit.patch のような形式のファイルを生成します。このファイルが通常の git diff コマンドと異なる点は、デジタル署名、作成者のメールアドレス、およびコミットメッセージの内容が含まれていることです。

経験則: 複数のファイル(シリーズ)を送る場合は、--cover-letter フラグを追加してください。これにより、変更全体の概要を記述するための 0000 ファイルが作成され、メンテナが文脈を把握しやすくなります。

git format-patch main -o outgoing/ --cover-letter

ステップ2:git send-email でパッチを送信する

よくある間違いは、GmailやOutlookでパッチファイルを手動で添付することです。メールソフトは自動的に文字を挿入したり、テキスト形式を変更したり(タブをスペースに変換するなど)することがあります。これによってパッチファイルの構造が壊れ、受信側で適用できなくなってしまいます。

最も標準的なツールは git send-email です。まず、SMTPを設定します(例:Gmailの場合):

git config --global sendemail.smtpserver smtp.gmail.com
git config --global sendemail.smtpserverport 587
git config --global sendemail.smtpencryption tls
git config --global sendemail.smtpuser [email protected]

その後、次の1行のコマンドでパッチを送信します:

git send-email --to="[email protected]" outgoing/*.patch

ステップ3:git am でパッチを適用する

パッチファイルを受け取ったメンテナは、git am (Apply Mail) コマンドを使用してコードをプロジェクトに統合します。

# 適用前にパッチの整合性をチェックする
git apply --check 0001-fix-bug-logic.patch

# パッチを適用し、対応するコミットを自動的に作成する
git am 0001-fix-bug-logic.patch

コマンド実行後、あなたのコミットはプロジェクトのGit履歴に元の情報のまま表示されます。まるで彼らのマシンで直接コミットしたかのような状態になります。

コンフリクト(衝突)への対処法

元のコードが大きく変更されている場合、git am は失敗します。心配はいりません。--3way フラグを使用すると、Gitが3ウェイマージを試行し、手動での修正が必要になる確率を最小限に抑えてくれます。

git am --3way 0001-fix-bug-logic.patch

それでもコンフリクトが残る場合は、Gitが停止するので手動で修正します。修正が完了したら、以下を実行するだけです:

git add .
git am --continue

おわりに

最初は、UI上でクリックするよりもこのプロセスの方が面倒に感じるかもしれません。しかし、慣れてしまえば、これが非常に大きな自由をもたらしてくれることに気づくでしょう。すべてはプレーンテキストです。サーバーのダウンタイムやGitHubのインターフェース変更を心配する必要はありません。

最後に一つアドバイス:パッチを送る際は、コミットメッセージを非常に明確に書いてください。メールの世界では、コミットメッセージこそが他人に自分の考えを理解してもらうための唯一のドキュメントです。皆さんの成功を祈っています!

Share: