Vimでファイル間の差分を表示する(vimdiff / :diffsplit)
2つの設定ファイルのどこが違うのか目で追うのは時間がかかります。Vimには標準でdiff機能が組み込まれており、外部コマンドを使わなくても差分箇所を色分け表示しながら比較できます。
目次(10項目)
| 操作 | これだけ覚える |
|---|---|
vimdiff f1 f2 | 2ファイルを比較しながら開く |
:diffsplit file | 開いているファイルと比較する |
| [c / ]c | 前 / 次の差分箇所へ移動 |
:diffoff | 差分表示を終了 |
ターミナルから直接比較する
vimdiff ファイル1 ファイル2
gvimdiff ファイル1 ファイル2
最大4ファイルまで同時に比較できます。次のコマンドでも同じ動作になります。
vim -d ファイル1 ファイル2
nvim -d ファイル1 ファイル2
デフォルトでは垂直分割(左右並び)で開かれます。分割方向を水平にしたい場合は-oオプションを付けます。
vim -o ファイル1 ファイル2
vimdiff file1 file2が最短です。分割方向を変えたいなら-oを追加します。
vimdiff old.conf new.conf の画面。変更行に色が付き、片方にしかない行は横線で示されるVimを開いた状態から比較する
すでに1つのファイルを開いている状態で、別のファイルと比較したいこともあります。
:diffsplit 比較対象ファイルパス
:diffs 比較対象ファイルパス
今開いているバッファと指定したファイルを、水平分割で比較表示します。左右に並べたい場合はverticalを前置します。
:vertical diffsplit 比較対象ファイルパス
:vert diffs 比較対象ファイルパス
差分箇所を移動する
[c " 前(上)の差分箇所へ移動
]c " 次(下)の差分箇所へ移動
ファイルが長い場合、スクロールで探すより]cで差分箇所だけを飛び移ったほうが速くなります。差分をマージしながら確認する作業では、この2つのキーを軸に進めることになります。実際にマージする方法(:diffget/:diffput)は別記事で詳しく扱います。
差分モードを終了する
:diffoff
比較が終わったら、このコマンドで通常の表示に戻せます。全ウインドウの差分表示を一括で解除したい場合は:diffoff!を使います。
diffモードで見やすくする設定
差分表示中は、対応する行の折りたたみが自動的に行われます。変更のない部分をまとめて畳んでくれるので、変更箇所だけに集中しやすくなります。この自動折りたたみが不要な場合は、次の設定でオフにできます。
set diffopt-=foldcolumn
また、空白の違いだけを無視して比較したい場合はdiffoptにiwhiteを追加します。インデントスタイルが混在しているファイル同士を比較するときに、余計な差分に惑わされずに済みます。
set diffopt+=iwhite
設定ファイルを書き換える前に、バックアップとの差分をvimdiffで確認する習慣をつけてから、意図しない変更に気づかず保存してしまう事故がなくなりました。ターミナルでdiffコマンドの出力を目で追うより、色分け表示で該当箇所へ直接ジャンプできるほうが圧倒的に速いと感じます。
差分を反対側へ取り込む
差分を眺めるだけでなく、その場で寄せることもできます。カーソルのあるウィンドウを基準に、do で相手側の内容を取り込み、dp で自分の内容を相手側へ送ります。
do " diff obtain:相手の変更を取り込む
dp " diff put:自分の変更を相手へ送る
]c で次の差分へ飛び、必要なら do、という繰り返しで2つのファイルを寄せていけます。3つ以上のファイルを開いているときは、どちらへ送るかが決まらないので範囲を指定する必要があります。取り込んだあとに u で戻せます。
差分の出方を diffopt で調整する
インデントだけを直したファイルを比べると、全行が差分として出てしまいます。空白の違いを無視する指定を入れると、意味のある変更だけが残ります。
set diffopt+=iwhite " 空白の量の違いを無視する
set diffopt+=internal,algorithm:histogram
2行目は差分の計算方法を変える指定です。既定の方法より、行の移動やまとまった変更を人間に近い形でまとめてくれます。差分がばらばらに出て読みにくいと感じたら、この指定を試してみてください。
全行が差分になるとき
中身は同じはずなのに全行が違うと表示される場合、まず疑うのは改行コードです。片方がCRLF、もう片方がLFだと、Vimは全行が異なると判定します。
:set ff? " それぞれのウィンドウで確認する
:e ++ff=unix " 揃えて開き直す
文字コードが違う場合も同じことが起きます。どちらもfileformatとfileencodingを揃えてから比べ直せば解決します。差分を見る前に、両方のウィンドウで :set ff? fenc? を打つ癖を付けておくと早く気づけます。
まとめ
ファイル間の差分確認はvimdiff、Vimを開いた状態からなら:diffsplitを使います。[c/]cで差分箇所を移動しながら確認すれば、外部ツールなしで十分な比較作業ができます。すでに開いているウィンドウ同士を後から比べたくなったら、それぞれのウィンドウで:diffthisを実行すると差分表示に切り替わります。戻すときは:diffoffで、そのタブの差分表示をまとめて解除したい場合は:diffoff!です(:help :diffoff)。差分を見つけたあと、片側の内容をもう片側へ取り込む操作はdiffモードでのマージにまとめています。差分モードに入るとfoldmethodがdiffに切り替わり、変わっていない行は自動で折りたたまれます(:help diff)。畳まれた部分を読みたくなったときは折りたたみの開閉がそのまま効きます。