Vim で Git diff の出力からカーソル下にある変更箇所へ移動する


2012年 02月 01日

問題

パッチのレビューなどでGitの diff の出力を読む機会はそれなりにあると思います。
その際、 diff で列挙されている内容だけでなく前後のコードも確認するために変更のあったファイルを開くことも多々あるでしょう。

Vimにはこの状況にぴったりのコマンドgfがあります。
gf はカーソル下にあるテキストからファイル名らしき文字列を探してそれを開くというコマンドです。
diff の出力には変更のあったファイルのパスが含まれていますから、
そこへカーソルを移動して gf を使えば良いというわけです。

gf はとても便利なコマンドではあるものの、
上記の操作を何度か行っていると不満が募ってきます。
というのも、以下のような手間があるからです:

  • gf を実行するためにパスの書かれている位置までカーソルを移動しなければならない。
  • gf でファイルを開いた後、レビューしたい場所までカーソルを移動しなければならない。

例えばカレントバッファに以下の内容が含まれているとしましょう
(左端の数字は行番号なので適宜無視してください):

diff --git a/autoload/gf/diff.vim b/autoload/gf/diff.vim
index 469fdb3..b135316 100644
--- a/autoload/gf/diff.vim
+++ b/autoload/gf/diff.vim
@@ -21,7 +22,7 @@
  "     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  "
  " Interface
-function! gf#diff#go_to_hunk(type)
+function! gf#diff#go(type)
    let d = gf#diff#investigate_the_hunk_under_the_cursor()
    if d is 0
      echomsg 'There is no diff hunk to jump.'
@@ -113,7 +114,7 @@ function! gf#diff#investigate_the_hunk_under_the_c
        return 0
      endif
      let [d.from_path, d.to_path] = xs
+  call setpos('.', original_position)
-  call setpos(original_position)

    return d
  endfunction

このとき:

  • 12行目で gf をすると autoload/gf/diff.vim の25行目まで移動する。
  • 16行目で gf をすると autoload/gf/diff.vim の117行目まで移動する。

のような感じで 手作業によるカーソル移動なしに目的の位置へ移動 できればとても便利です。
このように gf の動作を拡張するにはどうすれば良いでしょうか。

解答

vim-gf-diff を使います。
このプラグインをインストールすると gf<C-w>f などのコマンドの動作が以下のように拡張されます:

  • カーソル下にファイル名らしき文字列がある場合:
    そのファイルを開きます(Vimのデフォルトの挙動)。
  • カーソル下にファイル名らしき文字列はないが Git の diff の出力らしきテキストがある場合:
    diff で示されるファイルを開いて該当する変更箇所までカーソルを移動します。

これでレビューのタスクが山積みになっているときでも安心です。
やりましたね。

補足

  • 過去にVimのgfコマンドをgit diff特有の出力でも上手く扱うようにする設定例を紹介しましたが、今回紹介した vim-gf-diff は「変更箇所までカーソルを移動してくれる」「カーソル下にパス名がなくても使える」という点でさらに便利になっています。
  • 今回のように「カーソル周辺のテキスト等を元に適切なファイルを開く」というケースは他にもあると思われるので、vim-gf-diff と同様の拡張が簡単に書けるよう vim-gf-user というライブラリも作りました。こちらも参考にしてください。
  • vim-gf-diff を使う場合は vim-gf-user も合わせてインストールしてください(vim-gf-diff が vim-gf-user を利用して作られているため)。
  • 次回は Emacs 編です。