Gitの「外科手術」:git-merge-fileでコンフリクトを精密に切除する極限テクニック
「ブランチAのこの機能だけ欲しいが、ブランチ全体をマージすると大量のコンフリクトで地獄を見る」。
そんな経験はないだろうか? 多くのエンジニアはここで「cherry-pick」を試すが、依存関係が複雑な場合、cherry-pickすら衝突してコンフリクトの嵐に飲まれる。
今日伝授するのは、Gitの奥底に眠る秘術、`git-merge-file`を用いた「ピンポイント・コード移植術」だ。これはブランチという広大な領域全体を混ぜ合わせるのではなく、ファイルの一部分だけを外科手術のように切り貼りする、熟練工のためのテクニックである。
—
1. なぜ「git-merge-file」なのか?
通常の`git merge`や`git cherry-pick`は、コミットヒストリーという「文脈」を背負っている。だからこそ、関係ない修正まで引きずり込み、コンフリクトを誘発する。
対して`git-merge-file`は、「ただのテキストファイル3つ」をマージする純粋なアルゴリズムだ。Gitのインデックスやブランチのしがらみから解放され、純粋な差分だけを統合できる。
実践:特定のファイルだけを強引に統合する
別ブランチ(`feature-b`)にある`config.yaml`の特定の修正だけを、現在作業中の`main`ブランチに適用したいとしよう。
1. 共通の先祖(マージベース)を取得
git show-branch –merge-base main feature-b > base.yaml
2. 現在のファイルを抽出
git show HEAD:config.yaml > current.yaml
3. 欲しい変更が含まれる別ブランチのファイルを抽出
git show feature-b:config.yaml > incoming.yaml
4. git-merge-fileで強制統合!
-L でラベルを付けると、コンフリクトが発生した時にマーカーが分かりやすくなる
git merge-file -L current -L base -L incoming current.yaml base.yaml incoming.yaml
このコマンドを実行した瞬間、`current.yaml`には`feature-b`の修正が綺麗に反映される。もちろん、競合箇所があれば通常のGitマージと同じく`<<<<<<<`マーカーが挿入されるが、プロジェクト全体を汚すことなく、このファイル単体で解決できるという精神的余裕が生まれる。
—
2. 開発スピードを劇的に高める「神設定」とショートカット
このレベルの作業を日常的に行うなら、ターミナル作業の効率化は必須だ。
おすすめのGitエイリアス ( `.gitconfig` )
いちいち`git show`を打つのは時間の無駄。以下を`.gitconfig`に追記せよ。
[alias]
# 現在のファイルと、指定したブランチのファイルを直接比較する
diff-branch = “!f() { git show $1:$2 > /tmp/tmp_branch_file; diff -u $2 /tmp/tmp_branch_file; rm /tmp/tmp_branch_file; }; f”
# マージベースを素早く取得
mbase = “!git merge-base HEAD”
必須プラグイン:GitLens (VS Code)
GitLensはただの履歴表示ツールではない。「File History」ビューで、特定の行がいつ、誰によって変更されたかを瞬時に把握し、`git-merge-file`でどの範囲を抽出するかの判断材料にする。これなしで複雑なリポジトリを触るのは、地図なしでジャングルを歩くようなものだ。
—
3. 設定ファイルのベストプラクティス:Gitフレンドリーな構成
設定ファイルが「1行で数千文字」のような構成だと、コンフリクトは防げない。
- JSON/YAMLの正規化: プログラムで設定を生成する際は、常にキーをアルファベット順にソートする。
- 構造の細分化: 大規模な設定は単一ファイルに詰め込まず、`config/features/.yaml`のようにディレクトリ分割せよ。Gitはファイル単位のマージが得意なため、ファイルが分かれているだけでコンフリクト率は劇的に下がる。
推奨されるディレクトリ構成
config/
├── base.yaml # 基本設定(変更頻度低)
├── features/ # 機能ごとの分割設定(ここをgit-merge-fileで操作する)
│ ├── auth.yaml
│ └── database.yaml
└── environments/ # 環境依存設定
—
4. チームへの共有化ルール
個人の技術だけでは、チームの生産性は上がらない。以下のルールを`.gitattributes`に記述し、チーム全体でマージ戦略を強制せよ。
`.gitattributes` によるマージ方針の制御
設定ファイルはマージ時に競合しやすいため、独自のドライバーを設定可能
.yaml merge=union
※ `merge=union` を指定すると、コンフリクト時に両方の変更を単純に結合する。設定ファイルであれば、後勝ちで上書きされるよりも、両方の設定が残る方が事故が少ない場合が多い。
—
最後に:職人の思考をコードに宿せ
`git-merge-file`を使いこなすということは、「Gitという巨大なツールに踊らされる」のではなく、「Gitのエンジンを直接操作する」という領域への到達を意味する。
マージが怖いのは、背後で何が起きているかを見通せていないからだ。今日紹介した「外科手術」の手法を身につければ、複雑なコンフリクトも「退屈な事務作業」に変わる。
ツールを使い倒し、コードの歴史を支配せよ。それが、DevOpsの極致だ。