VIMリファレンスマニュアル by Bram Moolenaar
*diff* *vimdiff* *gvimdiff* *diff-mode*
このファイルでは |+diff| 機能 (同じファイルの2つ/3つ/4つのバージョン間の違いを
表示する機能) について解説する。
基本はユーザマニュアルのセクション|08.7|に記載されている。
1. 差分モードを開始する |vimdiff|
2. 差分を眺める |view-diffs|
3. 差分へ移動する |jumpto-diffs|
4. 差分を写す |copy-diffs|
5. 差分モードのオプション |diff-options|
{Vi にはない}
==============================================================================
1. 差分モードを開始する
差分モードで編集を開始するいちばん簡単な方法は"vimdiff"コマンドである。これは
Vimを通常どおり起動して、加えて引数で与えたファイル間の違いを表示する。
vimdiff file1 file2 [file3 [file4]]
これは以下に等しい:
vim -d file1 file2 [file3 [file4]]
"gvimdiff"もしくは"vim -d -g"を使うこともできる。その際はGUIがスタートする。
"viewdiff"もしくは"gviewdiff"を使うこともできる。その際は読込専用モードでス
タートする。
"r"が先頭に付け加われば制限モードになる(|-Z|参照)。
2つ目以降の引数にはディレクトリ名を指定することもできる。その際には第1引数の
ファイル名がそのディレクトリ名に追加され、ファイルを検索するのに利用される。
これは外部コマンドの"diff"が存在する場合にだけ動作する。'diffexpr'参照。
diff はカレントタブページ |tab-page| にローカルである。他のタブページにある
ウィンドウとの差分を見ることはできない。これによって、複数の差分を同時に見るこ
とが可能になっている。それぞれを別々のタブで開けばよい。
Vimが各ファイルについてウィンドウを開く時に起こることは、|-O|引数を使った時に
起こることに似ている。これには垂直分割が使用される。水平分割を行ないたいならば
|-o|引数を追加する:
vimdiff -o file1 file2 [file3 [file4]]
常に水平分割にしたければ 'diffopt' に "horizontal" を含めること。
編集される各ファイルには以下のオプションが設定される:
'diff' on
'scrollbind' on
'cursorbind' on
'scrollopt' "hor" を入れる
'wrap' off
'foldmethod' "diff"
'foldcolumn' 2
これらのオプションはウィンドウローカルに設定される。別のファイルを開いた時に
は、これらはグローバルの値へリセットされる。
このオプションはさらにそのファイルを再読み込みするときモードラインから上書きさ
れることがある。しかし 'diff' がオンのとき、'foldmethod' と 'wrap' はモードラ
インからはセットされない。
表示される差分はバッファ内の違いである。だからファイルを読み込んだ後に変更を行
なえば、その変更分は差分として表示される。全ての変更が即表示に反映されるわけで
はないので、時々":diffupdate"を行なうと良いだろう。
差分モードで起動した時の特別な設定を.vimrcファイルに記すことができる。このよう
にすれば良い:
if &diff
setup for diff mode
else
setup for non-diff mode
endif
setup for diff mode
else
setup for non-diff mode
endif
既にVimを利用している時には、3つの方法で差分モードへ移行することができる。
*E98*
:diffsplit {filename} *:diffs* *:diffsplit*
ファイル{filename}の新しいウィンドウを開く。現在と新しく開く
ウィンドウについて"vimdiff"と同様のオプションをセットする。
'diffexpr'も参照。
*:difft* *:diffthis*
:diffthis 現在のウィンドウを差分ウィンドウの1つにする。これにより
"vimdiff"と同じオプションが設定される。
:diffpatch {patchfile} *E816* *:diffp* *:diffpatch*
{patchfile}内の差分情報を現在のバッファへ適用し、結果を新しく
作成したバッファへ出力する。オプションは"vimdiff"と同様に設定
される。
{patchexpr}の形式は"patch"プログラムか'patchexpr'が取り扱える
形式ならどのようなものでもかまわない。
{patchfile}は現在のファイルに対して適用可能な差分情報だけを含
んでなければならないことに注意。もしも{patchfile}が他のファイ
ル用の差分情報を含んでいた場合は、結果は予想不可能となる。Vim
は現在のディレクトリのファイルが偶発的に書き換えられてしまうの
を避けるためディレクトリを/tmpへ変更する。しかし様々な".rej"
ファイルが作成されてしまう問題は依然としてある。また差分情報内
にファイルが絶対パスとして与えられた場合には、やはり適用されて
しまう。
このコマンドを垂直分割で使うには、|:vertical|を先行させる。例:
:vert diffsplit main.c~
:vert diffpatch /tmp/diff
:vert diffpatch /tmp/diff
常に垂直分割にしたければ 'diffopt' に "vertical" を含めること。
*E96*
'diff'オプションは最大で4つのバッファにまで同時に設定できる。
オプションの値はバッファへ記憶されるので、しばらくの間異なるファイルを編集し、
また同じファイルへ戻って再び差分モードを継続することができる。
*:diffo* *:diffoff*
:diffoff カレントウィンドウの差分モードを終了する。
:diffoff! カレントウィンドウとカレントタブページのカレントタブページのす
べてのウィンドウの差分モードを終了する
コマンド ":diffoff" は関連するオプションをデフォルト値に戻す。
これは差分モードが開始する前の値とは異なるかもしれない。その古い値は記憶され
ていない。
'diff' off
'scrollbind' off
'cursorbind' off
'scrollopt' "hor" を外す
'wrap' on
'foldmethod' "manual"
'foldcolumn' 0
==============================================================================
2. 差分を眺める *view-diffs*
差分ウィンドウには同じテキストが、異なるハイライト方法で表示される。テキストを
スクロールした際には'scrollbind'オプションにより、他のウィンドウも同じようにス
クロールする。垂直分割をしている場合にはテキストは正しく同期する。
テキストの位置は次のような場合に狂っていく:
- 'wrap'が有効で、幾つかの行が折り返され複数行を占めている時
- 折畳が一方のウィンドウでは開かれているが、もう一方では閉じられている
- 'scrollbind'が無効になっている
- テキストが変更された
- 'diffopt'に"filler"が指定されていず、削除・追加された行が配置を狂わせている
'diff'オプションが設定されているウィンドウで編集されている全てのバッファが差分
へ連結される。これは隠し(hidden)バッファにもあてはまる。これを可能にするには初
めに1つのウィンドウでそれらが編集される必要がある。
*:DiffOrig* *diff-original-file*
'diff'はウィンドウローカルのオプションであるから、1つのバッファをあるウィンド
ウでは差分モードで、別のウィンドウでは通常のウィンドウで表示することも可能であ
る。ファイルを読み込んで以来バッファに対して行なった変更を表示することも可能で
ある。だが、Vimは1つのファイルに対して複数のバッファを持つことはできないから、
別のバッファを作る必要がある。
次のコマンドが便利である:
command DiffOrig vert new | set bt=nofile | r ++edit # | 0d_
\ | diffthis | wincmd p | diffthis
(これは|vimrc_example.vim|に書かれている)。":DiffOrig"を実行すると、カレント\ | diffthis | wincmd p | diffthis
バッファと元のファイルの差分を見ることができる。
アンロードされたバッファの差分をとることはできない。隠れバッファの差分をとるこ
とはできる。コマンド ":hide" を使うと、バッファをアンロードせずにウィンドウを
閉じることができる。そのときバッファを差分対象から外したいならば、隠れバッファ
にする前に ":set nodiff" をする。
*:diffu* *:diffupdate*
:diffu[pdate] 差分の強調と折り畳みを更新する。
テキストを変更した時には、Vimは差分情報を最新に保とうと試みる。これの大部分は
挿入と削除をされた行(複数も可)に着目して行なわれる。1行内で行なわれた変更、及び
それよりも複雑な変更に対しては差分情報は更新されない。差分情報を強制的に更新す
るには次のコマンドを使う:
:diffupdate
Vimは片方のウィンドウには存在しないがもう一方には存在する行については補充して
表示する。これらはもう一方のファイルで追加されたかこのファイルで削除された行で
ある。'diffopt'オプションから"filler"を削除するとVimはこのような行の補充は行な
わない。
変更されていないテキストについては折畳を使用して隠される。折畳に使用できる全て
のコマンドについては|folding|を参照。
差分の近辺の折畳に含まれない領域はコンテキストと呼び、その行数を'diffopt'オプ
ションで設定できる。以下の例ではこのコンテキストを3行に設定している:
:set diffopt=filler,context:3
差分は以下の強調グループで強調表示される:
|hl-DiffAdd| DiffAdd 追加(挿入)された行。このバッファに存在する行
は、別のバッファには存在しない。
|hl-DiffChange| DiffChange 変更された行。
|hl-DiffText| DiffText 変更された行の中の変更されたテキスト。Vimは異
なる最初の文字と、最後の文字を発見する(検索は
行末から行なわれる)。その文字の間のテキストが
強調される。これはその間にあるテキストが例え同
じだったとしても強調されることを意味する。ここ
では 'diffopt' の "iwhite" だけが適用される。
|hl-DiffDelete| DiffDelete 削除された行。補充された行についても、実際その
バッファには存在していないことから、このグルー
プが適用される。
==============================================================================
3. 差分へ移動する *jumpto-diffs*
差分へ移動するのに2つのコマンドを使える:
*[c*
[c 前(上方)の変更の先頭へ移動する。
カウントが与えられた場合、その回数繰り返される。
*]c*
]c 次(下方)の変更の先頭へ移動する。
カウントが与えられた場合、その回数繰り返される。
カーソルの動く方向に変更がなかった場合にはエラーになる。
==============================================================================
4. 差分を写す *copy-diffs* *E99* *E100* *E101* *E102* *E103*
*merge*
あるバッファから別のバッファへテキストを複写する2つのコマンドがある。結果的に
ある範囲について2つのバッファの内容は等しくなる。
*:diffg* *:diffget*
:[range]diffg[et] [bufspec]
現在のバッファをもう1つのバッファと同じくなるように変更をす
る。 [bufspec]が与えられた時は、そのバッファが使用される。
[bufspec] がカレントバッファである場合は何も起こらない。
そうでなければ差分モードのバッファが他に1つしかない時にだけ動
作する。
[range]については以下を参照。
*:diffpu* *:diffput* *E793*
:[range]diffpu[t] [bufspec]
もう1つのバッファを現在のバッファと同じくなるように変更する。
":diffget"と同様だが現在のバッファではなく、もう一方のバッファ
が変更を受ける。
[bufspec] が省略され、かつ 'modifiable' がオンで差分モードにあ
るバッファが2個以上あると、このコマンドは失敗する。
[range]については以下を参照。
*do*
do 引数と範囲のない":diffget"と同じ。"o" は "obtain"の意味("dgg"
と区別できないので、"dg" は使えない)。
Note: これはビジュアルモードでは機能しない。
*dp*
dp 引数と範囲のない":diffput"と同じ。
Note: これはビジュアルモードでは機能しない。
[range]が与えられない場合にはカーソルの位置かその上の差分が適用される。[range]
が使われた時にはその範囲だけを適用(put/get)しようと試みる。削除された場合には
必ずしも可能なわけではない。
バッファの最後の行のさらに下方に削除された行があることも考えられる。そのとき
カーソルが最終行にあり、最終行より上に差異がないとき、":diffget"と"do"コマンド
はそれらの行を取得する。
超えた位置の行をもう一方のバッファから取得するには、最終行+1の行番号を指定す
る。次のコマンドはもう一方のバッファから完全な差分情報を受け取る:
:1,$+1diffget
削除された行は画面に表示こそされているが、テキストラインとしては数えられていな
いことに注意。消された範囲にカーソルを移動することはできない。もう一方のバッ
ファから、削除された行を":diffget"で取得するには対象行の下方で行なう必要があ
る。
*E787*
変更を受けるバッファが読み込み専用で、 |FileChangedRO| で引き起こされる自動コ
マンドがバッファを変更するとき、このコマンドは失敗する。
この自動コマンドはバッファを変更してはならない。
引数 [bufspec]にはバッファ番号、バッファ名のパターンもしくはバッファ名の一部を
使用できる。例:
:diffget 差分モードにある別のバッファを使用する
:diffget 3 3番のバッファを使用する。
:diffget v2 差分モードにある"v2"にマッチするバッファを使用
する(例, "file.c.v2")
==============================================================================
5. 差分モードオプション *diff-options*
|'diffopt'|と|'fillchars'|の"diff"項目も参照。
差分を発見する *diff-diffexpr*
'diffexpr'オプションは、2つのファイルを比較し差分を取得する標準的な"diff"プロ
グラム以外の何かを利用する場合に設定する。
'diffexpr'が空ならば、Vimはfile1とfile2間の差分を得るために次のコマンドを使用
する:
diff file1 file2 > outfile
">" は 'shellredir'の値に置き換えられる。
"diff"の出力は通常の"ed"形式の差分でなければならない。コンテキスト差分を使用し
てはいけない。この例はVimが求めるフォーマットを示している:
1a2
> bbb
4d4
< 111
7c7
< GGG
---
> ggg
> bbb
4d4
< 111
7c7
< GGG
---
> ggg
項目"1a2" が 行"bbb"を追加する。
項目"4d4" が 行"111"を削除する。
項目"7c7" が 行"GGG"を 行"ggg" で置き換える。
'diffexpr'が空でなければ、差分ファイルを述べた形式で取得するためにそれを評価実
行する。これらの変数がファイル名として設定される:
v:fname_in 基準となるファイル
v:fname_new 同ファイルの新バージョン
v:fname_out 結果を出力する差分ファイル
その上、'diffexpr' は 'diffopt'オプションの"icase" と "iwhite"についても考慮す
るべきだろう。'diffexpr'は'lines'と'columns'の値を変更できない。
例 (これは'diffexpr'が空の時とほぼ同じように働く):
set diffexpr=MyDiff()
function MyDiff()
let opt = ""
if &diffopt =~ "icase"
let opt = opt . "-i "
endif
if &diffopt =~ "iwhite"
let opt = opt . "-b "
endif
silent execute "!diff -a --binary" . opt . v:fname_in . " " . v:fname_new .
\ " > " . v:fname_out
endfunction
function MyDiff()
let opt = ""
if &diffopt =~ "icase"
let opt = opt . "-i "
endif
if &diffopt =~ "iwhite"
let opt = opt . "-b "
endif
silent execute "!diff -a --binary" . opt . v:fname_in . " " . v:fname_new .
\ " > " . v:fname_out
endfunction
引数の"-a"は強制的にテキストファイルとして比較するために使われる。バイナリでの
比較は使いにくい。引数の"--binary"はファイルをバイナリモードで読み込むために使
われる。DOSでCTRL-Zをテキストの終わりとしないためである。
*E810* *E97*
Vimは差分の出力結果が妥当であるか検証する。妥当でない場合、エラーメッセージを
得るだろう。起こりうるエラーは:
- プログラム"diff"を実行できなかった。
- プログラム"diff"が通常の"ed"スタイルの差分を出力しなかった(上記参照)。
- 'shell'と関連するオプションが正しく設定されていなかった。":!sort"のような
フィルタリングコマンドが正しく動作するか確認すること。
- 'diffexpr'を使っているが動作しなかった。
エラーメッセージがよくわからないときは'verbose'オプションを設定してより多くの
メッセージを見ることができる。
MS-Windows 用の Vim インストーラには diff プログラムが含まれている。もし diff
プログラムを持っていない場合はどこかから diff.exe をダウンロードすること。例え
ば次の場所から入手できる。
http://gnuwin32.sourceforge.net/packages/diffutils.htm.
パッチを使用する *diff-patchexpr*
'patchexpr'オプションは、標準的な"patch"プログラム以外の何かを利用する場合に設
定する。
'patchexpr'が空ならば、Vimは"patch"を次のように呼び出す:
patch -o outfile origfile < patchfile
これはほとんどのバージョンの"patch"で正しく働くだろう。行中間のCRが、改行記号と
して解釈され問題を起こすことはあるかもしれない。
デフォルトが正しく働かないのならば、同様の働きをする式を'patchexpr'に設定す
る。これらの変数がファイル名として設定される。
v:fname_in 基準となるファイル
v:fname_diff パッチファイル
v:fname_out パッチ適用結果を出力するファイル
例 (これは'patchexpr'を空にしたのと同じ働きをする):
set patchexpr=MyPatch()
function MyPatch()
:call system("patch -o " . v:fname_out . " " . v:fname_in .
\ " < " . v:fname_diff)
endfunction
function MyPatch()
:call system("patch -o " . v:fname_out . " " . v:fname_in .
\ " < " . v:fname_diff)
endfunction
利用する"patch"プログラムが望んでいない副作用をしていないことを確認する必要が
ある。例えば消されるべき付加的なファイルが生成されていないか用心する必要があ
る。ファイルにパッチをあてる以上のことは何もすべきではない。
Vimは'patchexpr'を実行する前に"/tmp"か他の一時ディレクトリへ現在のディレク
トリを移動する。これにはカレントディレクトリの別のファイルへ偶然にパッチがあ
たってしまうのを避ける狙いがある。Vimはv:fname_inで始まり".rej" や ".orig"で終
わる名前のファイルを消すこともする。
vim:tw=78:ts=8:ft=help:norl: