Git の difftool と mergetool コマンドが Neovim を使うように設定してみた
Git の difftool と mergetool は -t オプションで vimdiff を指定すれば Vim の vimdiff を使ってくれますが, Vim ではなく Neovim を使ってくれるようにコマンドラインを設定してみました.
ファイルを見比べたり, マージコンフリクトを解決する時に git difftool -t vimdiff
や git mergetool -t vimdiff
とそれぞれ -t
オプションで vidiff
と指定すれば, Vim の vimdiff
コマンドを使ってくれます.
ただ僕は, 今 Neovim を使っているということもあり, Neovim で vimdiff
と同じことがしたいと思い, どうすればいいのか調べてみまして, 実際に git difftool
と git mergetool
が Neovim を使ってくれるように設定することができましたので, 同じようにそれらのコマンドで Neovim を使ってみたいという方は, 一例として参考にしていただければと思います.
設定方法
次のコマンドで ~/.gitconfig
を開いて:
git config --global --edit
次の変数を設定します:
[diff]
tool = nvimdiff
[difftool "nvimdiff"]
cmd = "nvim -R -d -c \"wincmd l\" -d \"$LOCAL\" \"$REMOTE\""
[mergetool "nvimdiff"]
cmd = "nvim -d -c \"4wincmd w | wincmd J\" \"$LOCAL\" \"$BASE\" \"$REMOTE\" \"$MERGED\""
これで設定完了です.
あとは変更を保存すれば, 変更が適用されるので, git difftool
, git mergetool
コマンドで Neovim を起動してくれるようになります.
設定の説明
カスタム diff ツールの場合
diff.tool
の値を nvimdiff
にして, カスタム diff ツールとして設定しています.
カスタム diff ツールを設定すると, それに対応する difftool.nvimdiff.cmd
の値を設定する必要があるので, シェルコマンドを設定しています.
シェルコマンドの内容は nvim
でまず Neovim の実行ファイルを実行し, -R
オプションで読み取り専用モードにし, -d
オプションで diff モードにし, -c
オプションでコマンドを実行するようにし, そのコマンド内容の wincmd l
で Neovim で $LOCAL
と $REMOTE
の 2 つのファイルを 2 つのウィンドウを縦に並べるように開いた後に, ウィンドウのフォーカスを右に 1 つ移動させます.
カスタムマージツールの場合
merge.tool
の値を nvimdiff
にして, カスタムマージツールとして設定しています.
カスタムマージツールを設定すると, それに対応する mergetool.nvimdiff.cmd
の値を設定する必要があるので, シェルコマンドを設定してします.
シェルコマンドの内容は nvim
でまず Neovim の実行ファイルを実行し, -d
オプションで diff モードにし, -c
オプションでコマンドを実行するようにし, そのコマンド内容の 4wincmd w | wincmd J
で Neovim で $LOCAL
, $BASE
, $REMOTE
, $MERGED
という 4 つのファイルを 4 つのウィンドウを縦に並べるように開いた後に, まず 4 番目のウィンドウ ($MERGED
) にフォーカスを移動させ, そのウィンドウを画面下半分に持ってくるように配置転換させます.
実際に使ってみる
git difftool
の場合
一例として, ワーキングディレクトリの example.txt
を変更した後に git difftool
を実行した直後は次のようになります:
git mergetool
の場合
一例として, master
ブランチに hotfix
ブランチをマージさせて, マージコンフリクトが発生した直後に git mergetool
を実行した直後は次のようになります:
まとめ
今回の設定を調べるにあたって, Git (v2.18.0
) のリポジトリの mergetools/vimdiff
ファイルの中身を拝見させていただいたところ:
https://github.com/git/git/blob/v2.18.0/mergetools/vimdiff
次のようなコードを確認できました:
# 1
"$merge_tool_path" -R -f -d \
-c 'wincmd l' -c 'cd $GIT_PREFIX' "$LOCAL" "$REMOTE"
# 2
"$merge_tool_path" -f -d -c '4wincmd w | wincmd J' \
"$LOCAL" "$BASE" "$REMOTE" "$MERGED"
この上記のコードを参考にさせていただいて, 今回の設定をすることができました.
ただ, 元のファイルを見ていただくとわかるのですが, merge.tool
が vimdiff
の場合, そちらのコードはマージコンフリクトが発生した際に, ベースのファイルが存在しない場合, 3 つのウィンドウを開くような処理も実装されているのですが, 今回の merge.nvimdiff.cmd
のコードはもしベースのファイルが存在しない場合でも 4 つのウィンドウを開いてしまいます.
ただ Git でマージする場合, git checkout --orphan <branch>
で作ったブランチを git merge --allow-unrelated-histories <branch>
でマージしない限り, 通常 3-way マージになるかと思いますので, そんなに大きな問題はないと思われます.
なので今回の設定でもそれなりに実用性があるかと思いますので, 一例として参考にしていただけたらなと思います.
ただ一番いいのは difftool.nvimdiff.cmd
や mergetool.nvimdiff.cmd
など設定することなく, diff.tool
や merge.tool
の値を nvimdiff
などと設定するだけで, Git が Neovim を diff モードで起動するように実装してくれれば, それに越したことはないのでしょう
参考資料
- https://git-scm.com/docs/git-difftool
- https://git-scm.com/docs/git-mergetool
- https://git-scm.com/docs/git-config#git-config-difftool
- https://git-scm.com/docs/git-config#git-config-difftoollttoolgtcmd
- https://git-scm.com/docs/git-config#git-config-mergetool
- https://git-scm.com/docs/git-config#git-config-mergetoollttoolgtcmd
関連記事
git merge オプションの --ff, --no-ff, --ff-only の違い2018.08.15
前のブランチをチェックアウトするのに git checkout の引数としてダッシュを使えるよ2018.08.18
Git でより良いコミットメッセージを書く方法2018.06.13
Git でローカルとリモート両方のブランチを削除する方法2018.08.13
git push コマンドの -f オプションと + サインの違い2018.08.11