vimdiffを使用してgitマージの競合を解決するにはどうすればよいですか?


159

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

ここに画像の説明を入力してください


3
参照してくださいこのページを。それが「正しい」という意味である場合、コードの現在の状態は左上にあります。
romainl 2013

@romainlそれを読んでもまだ混乱しています、ショートカットとは何ですか?どのファイルをメインブランチとして使用するかをどのように選択しますか?
Cool Guy Yo


参照してください:これは
skelliam

回答:


142

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

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

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


4
簡単な質問vimに保存するにはどうすればよいですか?
Cool Guy Yo

6
:xまたは:w:x終了も)プラス 'return'。
ジョナサンレフラー2013

4
Anders:の使い方に慣れていない場合に使用できる他のマージツールがありますvim
chepner 2013

3
@ AndersKitson、Mac OS Xを使用しているため、FileMergeは完璧で無料で、XCodeが付属しています。
romainl 2013

8
なぜ反対票か。事実に誤りがある場合は、修正するか、少なくとも指摘してください。
chepner 2013

91

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


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


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

  • 下のバッファに移動します(マージ結果): Ctrl-W j
  • j/で次の差分に移動しkます。または、より良い方法として、] cおよび[ cを使用して、次の差分と前の差分にそれぞれ移動します。
  • 使用z oあなたがより多くの文脈を見たい場合は、それを開くために倍にしながら
  • @chepnerの回答に従って、各差分について、ローカル、リモート、またはベースバージョンからコードを取得するか、コードを編集して、必要に応じてやり直すことができます。
    • ローカルバージョンから取得するには、次を使用します。 :diffget LO
    • リモートから: :diffget RE
    • ベースから: :diffget BA
    • または、コードを自分で編集する場合は、まずlocal / remote / baseからバージョンを取得してから、挿入モードに移動して残りを編集します
  • 完了したら、マージ結果を保存し、すべてのウィンドウを終了します :wqa
  • 通常、gitはマージが行われたことを検出し、マージコミットを作成します

コピー貼り付けまたはカスタムショートカットなしに、ローカルとリモートの両方の競合ハンクを追加することはできないようです:https : //vi.stackexchange.com/questions/10534/is-there-a-way-to-take-both- when add -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


10
これはx1000倍に投票され、より良い回答として受け入れられるはずです。
Andrey Portnoy

次の競合にすばやくジャンプするには、===を検索してください。"/ ==="を実行して入力
Apit John Ismail

を使用して複数の一致が見つかった場合は、この投稿(stackoverflow.com/questions/51520705/…)を参照してください:diffget
ジェイソン

7

vimdiffを置き換える究極のマージツール

これは一種の口癖ですが、vimdiffを試した後、ビマーとして収束することになりました。

マージの競合を解決するには、ほとんどの場合、次のことを確認する必要があります。

  • リモート
  • 地元
  • 2つの差分:
    • diff BASE REMOTE
    • diff BASE LOCAL

次に、両方を組み合わせてみます。

vimdiffは画面にBASE、LOCAL、REMOTEを表示しますが、

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

右、左、右、左を何度も見て、他に必要な2つのdiffを明確に表示する方法がわかりません。

さらに、LOCALとREMOTEはすでにgit merge競合マーカーに表示されているので、それらを再度表示するツールからはそれほど多くは得られません。

したがって、代わりに、私が欠落していた差分を実際に表示する独自の小さな「difftool」を作成しました。

〜/ bin / cirosantilli-mergetool

#!/usr/bin/env bash
BASE="$1"
LOCAL="$2"
REMOTE="$3"
diff --color -u "$BASE" "$LOCAL"
diff --color -u "$BASE" "$REMOTE"
exit 1

GitHubアップストリーム

そして、それをインストールします:

git config --global mergetool.cirosantilli-mergetool.cmd 'cirosantilli-mergetool $BASE $LOCAL $REMOTE'
git config --global mergetool.cirosantilli-mergetool.trustExitCode true
# If you want this to become your default mergetool.
#git config --global merge.tool 'cirosantilli-mergetool'

今、あなたがするとき:

git mergetool -t cirosantilli-mergetool

それは私がターミナルで欲しい2つのdiffを示しています、例えばそれに沿って何か:

--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_LOCAL_15560.py       2019-12-27 13:46:41.979021479 +0000
@@ -994,7 +994,7 @@                                                              

     def setupBootLoader(self, cur_sys, loc):
         if not cur_sys.boot_loader:                           
-            cur_sys.boot_loader = [ loc('boot_emm.arm64'), loc('boot_emm.arm') ]
+            cur_sys.boot_loader = [ loc('boot.arm64'), loc('boot.arm') ]
         cur_sys.atags_addr = 0x8000000                  
         cur_sys.load_offset = 0x80000000                    

@@ -1054,7 +1054,7 @@                                           
             ]                                                     

     def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = [ loc('boot_emm_v2.arm64') ]
+        cur_sys.boot_loader = [ loc('boot_v2.arm64') ]
         super(VExpress_GEM5_V2_Base,self).setupBootLoader(
                 cur_sys, loc)                             

--- ./src/dev/arm/RealView_BASE_15560.py        2019-12-27 13:46:41.967021591 +0000
+++ ./src/dev/arm/RealView_REMOTE_15560.py      2019-12-27 13:46:41.991021366 +0000
@@ -610,10 +610,10 @@           
     def attachIO(self, *args, **kwargs):              
         self._attach_io(self._off_chip_devices(), *args, **kwargs)

-    def setupBootLoader(self, cur_sys, loc):
-        cur_sys.boot_loader = loc('boot.arm') 
-        cur_sys.atags_addr = 0x100                           
-        cur_sys.load_offset = 0       
+    def setupBootLoader(self, cur_sys, boot_loader, atags_addr, load_offset):
+        cur_sys.boot_loader = boot_loader      
+        cur_sys.atags_addr = atags_addr     
+        cur_sys.load_offset = load_offset

これで、ターミナルにダンプされた2つの差分を確認できます。

  • RealView_BASE_15560.pyRealView_LOCAL_15560.py
  • RealView_BASE_15560.pyRealView_REMOTE_15560.py

差分が大きい場合は、自分のtmux超能力で検索します。

はい、vimdiffが提供するいくつかのショートカットは失われますが、一般的に競合を解決するには両方のバージョンからの注意深いコピー貼り付けが必要です。これは、通常のvimセッション内でgit競合マーカーを使用して問題なく実行できます。

vimdiff実行中のファイルの監視と比較

私が座ってで完璧なセットアップを自動化する前にcirosantilli-mergetool、これが私が必要とする2つの差分を取得するために行っていたことです。

git mergetool実行中にvimdiff、たとえばという名前のファイルに競合がある場合main.py、gitは次のように名前が付けられた各バージョンのファイルを生成します。

main_BASE_1367.py
main_LOCAL_1367.py
main_REMOTE_1367.py

同じディレクトリにあるmain.py場所1367:で述べたように、gitのmergetoolのPIDがあるので、「ランダム」の整数gitのマージ競合では、生成されたBACKUP、BASE、LOCAL、REMOTEおよびファイルは何ですか?

したがって、必要なdiffを確認するには、最初にで生成されたファイルを見つけ、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>

競合を直接見つけます。

git imerge

たぶん、最良のオプションは、単にはvimdiffを使用してあきらめて、定期的にvimに依存することです+ gitのimergeで言及された:どのように私はGitが原因の競合をコミットするかを調べることができますか?vimdiffの学習曲線は面倒で、私たちが最も必要とする機能を実行しないからです。


1
賛成。9年前にstackoverflow.com/a/3052118/6309でそのことを述べたと思います。(回答の最後の部分を参照)
VonC

@VonCはい、私はあなたがこれに勝ったと思います!XD
Ciro Santilli郝海东冠状病六四事件法轮功
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.