web-dev-qa-db-ja.com

vimdiffを使用してgit mergeコンフリクトを解決するにはどうすればよいですか?

Gitでマスターにブランチをマージしたところ、Automatic merge failed; fix conflicts and then commit the result.になったので、git mergetoolを実行し、以下の画像でvimdiffを開きました。 vimdiffの使用方法がわかりません。ここの各パネルの意味と、マージの競合を修正するにはどうすればよいですか?

enter image description here

134
Cool Guy Yo

4つのバッファはすべて、同じファイルの異なるビューを提供します。左上のバッファ(LOCAL)は、ターゲットブランチでのファイルの外観(マージ先)です。右上のバッファ(REMOTE)は、ソースブランチ(マージ元)でのファイルの外観です。中間バッファー(BASE)は、2つの共通の祖先です(したがって、左右のバージョンが互いにどのように分岐したかを比較できます)。

次の点で誤解される可能性があります。マージの競合の原因は、両方のファイルがBASE以降にファイルの同じ部分を変更したことです。 LOCALは引用符をdoubleからsingleに変更し、REMOTEは同じ変更を加えましたが、背景値も色からURLに変更しました。 (マージは、LOCALへのすべての変更がREMOTEにも存在することに気付くほどスマートではないと思います。LOCALがREMOTEと同じ場所でBASEから変更を加えたことを知っているだけです)。

いずれにせよ、一番下のバッファには実際に編集できるファイルが含まれています。これは作業ディレクトリにあるファイルです。好きなように変更できます。 vimは、トップビューのそれぞれとの違いを示しています。トップビューは、自動マージでは処理できなかった領域です。リモートの変更が必要ない場合は、ローカルから変更をプルします。ローカルの変更よりも必要な場合は、リモートから変更をプルします。 REMOTEとLOCALの両方が間違っていると思われる場合は、BASEからプルします。より良いアイデアがあれば、まったく違うことをしてください!最終的に、ここで行う変更は、実際にコミットされるものです。

124
chepner

@chepnerの答えは素晴らしいです。質問の「マージの競合を修正するにはどうすればよいか」という部分に詳細を追加したいと思います。この場合にvimdiffを実際に使用する方法を調べると、以下になります。


まず、「すべてを中止する」オプションに対処する-「vimdiff」を使用せずにマージを中止する場合:を押します Esc、次に:qa!と入力してヒット Enter。 ( Vimエディターを終了するにはどうすればよいですか? も参照)。 Gitは、マージが完了したかどうかを尋ねます。nで返信します。


Vimdiffを使用する場合の便利なショートカットを次に示します。これは、Vimの基本(ナビゲーションと挿入/通常モード)を知っていることを前提としています。

  • 下のバッファに移動します(結果をマージします): Ctrl-Wj
  • 次の差分に移動します j/k;または、より良い、使用 ]c そして [c それぞれ次と前の差分に移動します
  • つかいます zo より多くのコンテキストを表示したい場合は、折り目を開いて開きます
  • @chepnerの答えによると、各diffに対して、ローカルバージョン、リモートバージョン、またはベースバージョンからコードを取得するか、適切に表示されるように編集してやり直すことができます
    • ローカルバージョンから取得するには、:diffget LOを使用します
    • リモートから::diffget RE
    • ベースから::diffget BA
    • または、自分でコードを編集する場合は、最初にローカル/リモート/ベースからバージョンを取得してから、挿入モードに移動して残りを編集します
  • 完了したら、マージ結果を保存し、すべてのウィンドウを終了します:wqa
  • 通常、gitはマージが行われたことを検出し、マージコミットを作成します

コピーペーストまたはカスタムショートカットなしでローカルおよびリモートの競合ハンクを追加することはできないようです: https://vi.stackexchange.com/questions/10534/is-there-a -way-to-take-both-when-using-vim-as-merge-tool これは、add addが一般的な競合タイプであるため残念です。

Vimdiffが起動するたびにEnterキーを押すように要求しないようにするには、.vimrcに追加します。

set shortmess=Ot

https://vi.stackexchange.com/questions/771/how-can-i-suppress-the-press-enter-Prompt-when-opening-files-inで言及されているように-diff-mode

他のvimdiffショートカットをインターネットで検索できます。私はこれが便利だとわかりました: https://Gist.github.com/hyamamoto/7783966

54
Timur

vim -dを使用して(BASEとLOCAL)と(BASEとREMOTE)を比較する方法

マージの競合を解決するとき、最も重要なことの1つは次のとおりです。

  • 新しいコミットがベースコミットをどのように変更したか
  • 既存のコミットがベースコミットをどのように変更したか

次に、両方を一緒にしようとします。

vimdiffはBASE、LOCAL、REMOTEのすべてを並べて表示するのに適していますが、BASEからの2つの個別の差分を明確に見ることはできません。

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+

これを解決するために、git mergetoolvimdiffを実行しているときに、たとえばmain.pyという名前のファイルに競合がある場合、gitは次の名前の各バージョンのファイルを生成することに気付きました。

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

main.pyと同じディレクトリにあり、1367はgit mergetoolのPIDです。したがって、次のように「ランダムな」整数です。 git merge conflictでは、BACKUP、BASE、LOCAL、REMOTE生成されますか?

だから、私が欲しい差分を見るために、最初にgit statusで生成されたファイルを見つけ、次に新しいターミナルを開いて、気にするファイルのペアの間でvimdiffを実行します:

vim -d main_BASE_1367.py main_LOCAL_1367.py
vim -d main_BASE_1367.py main_REMOTE_1367.py

git mergetoolとともに、この情報はA LOTが迅速に何が起こっているかを把握するのに役立ちます!

また、mergetoolの実行中であっても、ファイルを開くことができます。

vim main.py

エディタウィンドウを大きくすれば簡単になると思われる場合は、直接編集してください。

これらすべてのファイルを自動的に開くために、さらに自動化できると思いますが、私はまだそこに挑戦していません。

衝突をマージするために直接ジャンプする

]cはvimdiff内の次のdiffポイントにジャンプしますが、マージの競合が常に存在するとは限りません。

これを支援するために、私は~/.vimrcにあります:

# Git Merge conflict
nnoremap <leader>gm /\v^\<\<\<\<\<\<\< \|\=\=\=\=\=\=\=$\|\>\>\>\>\>\>\> /<cr>

競合を直接見つけます。