タイトル: Gitで「MERGING」の状態
SEOタイトル: Git MERGING 状態の解消方法完全ガイド
| この記事の要点 |
|
MERGING 状態とは
git merge 実行中に、Git が自動マージできないコンフリクトを検出すると、リポジトリは「マージ作業中」を示すMERGING 状態になります。シェルプロンプト (zsh の git-prompt 等) に (main|MERGING) と表示されるのはこの状態です。
$ git merge feature
Auto-merging src/app.php
CONFLICT (content): Merge conflict in src/app.php
Automatic merge failed; fix conflicts and then commit the result.
# プロンプトが MERGING に
(main|MERGING) $
MERGING 状態の判定
# 状態確認
git status
# On branch main
# You have unmerged paths.
# (fix conflicts and run "git commit")
# (use "git merge --abort" to abort the merge)
#
# Unmerged paths:
# (use "git add ..." to mark resolution)
# both modified: src/app.php
# 内部ファイルの存在
ls .git/MERGE_HEAD .git/MERGE_MSG
# .git/MERGE_HEAD ← これがあれば MERGING 中
# .git/MERGE_MSG ← マージコミット用メッセージのドラフト
取りうる 3 つの選択肢
| 選択肢 | コマンド | 結果 |
|---|---|---|
| ① 競合解決して完了 | 編集 → git add → git commit | マージコミット作成 (推奨) |
| ② マージを取り消す | git merge --abort | マージ前の状態に戻る (安全) |
| ③ マージを強制完了 (空マージ) | git commit --allow-empty 等 | 非推奨。状況限定 |
選択肢①: 競合解決 → コミット
競合した箇所は次のようなマーカーで示されます:
<<<<<<< HEAD
echo "main branch version";
=======
echo "feature branch version";
>>>>>>> feature
これを「どちらか」または「両方」を残す形に編集します。Git は中身を解釈しないので、自分でロジック的に正しい形を選ぶ必要があります。
# 1. 衝突ファイルを編集してマーカー (<<<, ===, >>>) を消す
$EDITOR src/app.php
# 2. 解決済みとしてステージ
git add src/app.php
# 全衝突解決を一括ステージ
git add .
# 3. マージコミット作成
git commit
# (エディタが開いて、MERGE_MSG の内容で確定)
# メッセージを指定
git commit -m "Merge branch 'feature' into main"
# 状態確認
git status
# nothing to commit, working tree clean
# (main) ← MERGING が消える
衝突解決の支援ツール
# 衝突中のファイル一覧
git diff --name-only --diff-filter=U
# src/app.php
# 各ファイルの衝突箇所
git diff
# GUI マージツール
git mergetool
# vimdiff / kdiff3 / VS Code 等が起動
# VS Code を mergetool に
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
「相手側」「自分側」をまるごと採用
# ours (現在のブランチ側を採用)
git checkout --ours src/app.php
# theirs (マージ元側を採用)
git checkout --theirs src/app.php
# ステージして完了
git add src/app.php
git commit
選択肢②: マージを取り消す
これが一番安全な「やり直し」手段です。マージ前の HEAD に戻り、作業ツリーも復元されます:
git merge --abort
# 確認
git status
# On branch main
# nothing to commit, working tree clean
# (Git 2.11 以降推奨。古い Git では git reset --merge と同等)
--abort 前に行った未コミットのローカル変更も復元される点が安全。ただし、マージ衝突中に手動編集した内容は失われます (それは想定通り)。
選択肢③: 強制的に完了 / 強制的にリセット
状況により以下も使われますが、未コミット変更の喪失に注意:
# 全衝突を未解決のまま、現在の状態でマージコミットを作る (危険)
git commit -am "WIP merge"
# マージ作業中の状態を完全に破棄して直前の HEAD へ
git reset --merge
# 直前の HEAD (ORIG_HEAD) へハードリセット
git reset --hard ORIG_HEAD
# git reset --hard は未コミット変更を消すので注意
# git stash で退避してから実行することも検討
git merge --continue (Git 2.12+)
競合解決 → git add 済の状態で、コミットを完了するには:
git merge --continue
# = git commit (MERGE_MSG をテンプレに)
関連状態: REBASING / CHERRY-PICKING / BISECTING
MERGING と同様に、Git は各操作中の状態をマーカーファイルで管理しています:
| 状態 | マーカー | 進める | 取り消す |
|---|---|---|---|
| MERGING | .git/MERGE_HEAD | git merge --continue | git merge --abort |
| REBASING | .git/rebase-merge/ or rebase-apply/ | git rebase --continue | git rebase --abort |
| CHERRY-PICKING | .git/CHERRY_PICK_HEAD | git cherry-pick --continue | git cherry-pick --abort |
| REVERTING | .git/REVERT_HEAD | git revert --continue | git revert --abort |
| BISECTING | .git/BISECT_LOG | git bisect good/bad | git bisect reset |
よくあるシナリオ
1. git pull で MERGING になった
git pull
# Auto-merging ...
# CONFLICT ...
# 解決
$EDITOR conflicting-file
git add .
git commit
# やり直したい
git merge --abort
git pull --rebase # rebase 方式で取り込み直し
2. MERGING を放置したまま別ブランチに行きたい
# ❌ 直接 checkout は怒られる
git checkout other-branch
# error: you need to resolve your current index first
# 正しい順序
git merge --abort
git checkout other-branch
# どうしても変更を取っておきたい場合
git stash --include-untracked
git merge --abort
git stash pop
3. MERGE_HEAD が残ったまま再起動 → 状態が分からない
# 内部ファイルから判断
ls .git/MERGE_HEAD .git/MERGE_MSG .git/CHERRY_PICK_HEAD .git/REBASE_HEAD 2>/dev/null
# MERGING 中なのが判明したら
git merge --abort
FAQ
Q: git merge --abort しても MERGING が消えない
A: Git のバージョンが古い可能性。git reset --merge または git reset --hard ORIG_HEAD で代用。
Q: マージコミットを残したくない
A: git merge --abort してから git pull --rebase あるいは git rebase target-branch。マージコミットの代わりに線形履歴になります。
Q: 衝突ファイルがバイナリ (画像など)
A: テキストマーカーは入らない。git checkout --ours/--theirs でどちらか丸ごと採用 → git add。