Vimのundoとredo 元に戻すuとやり直すCtrl-r
ファイルを一度閉じて開き直したら、さっきまでのundo履歴が消えていて元に戻せませんでした。アンドゥ(undo)とリドゥ(redo)そのものは誰でもすぐ使えますが、履歴を永続化する設定は意外と知られていません。
目次(10項目)
| キー | これだけ覚える |
|---|---|
| u | 1つundo |
| Ctrl-r | 1つredo |
| U | 直近1行をまとめて元に戻す |
| g- / g+ | 時系列で1つ前 / 後の変更状態へ |
基本のundo/redo
u " 1つundo
3u " 3つ分まとめてundo
Ctrl-r " redo
3Ctrl-r " 3つ分まとめてredo
数字を前置きすれば、その回数分をまとめてundo/redoできます。ノーマルモードでもビジュアルモードでも同じキーで動きます。
let name = "vim";
let count = 42;
let name = "vim"; let count = 1;
1をciwで42に書き換えたあとuを押すと、直前の書き換えだけが取り消されて元の値に戻ります。Ctrl-rを押せばもう一度42に戻せます。
もう1つ、行単位の特殊なundoとしてUがあります。これは直近に変更された1行の内容を、変更前の状態にまとめて戻すコマンドで、複数回の1手ずつのundoとは挙動が異なります。ノーマルモードとビジュアルモードでこのUの意味が変わる点は別記事で扱っています。
ファイルを閉じると履歴が消える
デフォルトでは、undo履歴はそのセッション(Vimを起動してから閉じるまで)の間しか保持されません。一度ファイルを閉じて開き直すと、履歴はリセットされてしまいます。
永続的なundo履歴を有効にする
set undofile
set undodir=~/.vim/undodir
undofileを有効にすると、undo履歴がディスク上のファイルとして保存され、Vimを再起動してファイルを開き直しても続きからundoできるようになります。undodirで保存先のディレクトリを指定できますが、ディレクトリ自体は事前に作成しておく必要がある点に注意してください。存在しないディレクトリを指定すると保存に失敗します。
変更履歴を確認しながら戻る
何回undoすればよいか分からないときは、g-で1つ前の変更状態へ、g+で1つ後の変更状態へ移動できます。u/Ctrl-rとの違いは、分岐したundoツリーがある場合の扱いです。一度undoしてから新しい変更を加えると、undo木は枝分かれします。
| コマンド | たどる対象 |
|---|---|
| g- / g+ | 実際に操作した時系列の順序 |
| u / Ctrl-r | 現在の枝(ブランチ)の中だけ |
複雑な編集をしたあとに「さっきの状態」を正確に取り戻したいときはg-を試すと便利です。
:undolist。枝分かれした履歴が並ぶ保持する履歴の量を調整する
set undolevels=1000
undolevelsでundoできる回数の上限を設定できます。デフォルトは1000で、通常の作業であれば困ることはまずありません。履歴を確認したい場合は:undolistを実行すると、現在保持されている変更の一覧を確認できます。
set undofileとundodirの設定を忘れずに行ってください。ディレクトリの事前作成だけは忘れやすいので注意してください。
数日前に消した内容を復元したくなり、ファイルを開き直したら履歴が残っていないことに気づいたのがundofileを導入したきっかけでした。設定してからは「あの時のあの変更、消さなければよかった」という後悔をしなくて済むようになりました。ディレクトリを作り忘れて最初は保存されておらず、少し戸惑いました。
undofile を使うときの注意
undofile を有効にすると、編集したファイルごとに履歴ファイルが作られます。undodir を指定しないと元のファイルと同じ場所に散らばるので、必ず1か所にまとめてください。
set undofile
set undodir=~/.vim/undo// " 末尾のスラッシュ2つが要点
末尾の // は、履歴ファイルの名前にフルパスを含めるという指定です。これが無いと、別のディレクトリにある同名のファイル同士で履歴が衝突します。ディレクトリはあらかじめ作っておく必要があります。
履歴ファイルには編集前の内容が入るので、秘密情報を含むファイルでは残したくないことがあります。その場合は拡張子やパスで対象を絞ってください。
時系列で戻る
u と Ctrl-r は履歴の枝をたどるので、戻したあとに別の編集をすると、消えたほうの枝には戻れません。時刻でたどるキーなら、枝に関係なく行き来できます。
g- " 時系列で1つ前の状態へ
g+ " 時系列で1つ後の状態へ
:earlier 10m " 10分前の状態へ
:earlier 1f " 前回保存した時点へ
:later 5m " 5分後の状態へ
「戻しすぎたあとに打ってしまって、さっきの内容が消えた」と思ったときは、たいてい g- で戻せます。:earlier 1f は保存した時点まで一気に戻せるので、実験して失敗したときの脱出口として覚えておくと役に立ちます。
取り消しの単位を自分で区切る
挿入モードで打った内容は、Esc を押すまでが1つの変更です。長い文章を一息に打つと、u 1回で全部消えます。
途中に区切りを入れたいなら、挿入モードのまま Ctrl-g u と押すと、そこで取り消しの単位が切れます。改行やスペースを打つたびに区切るよう割り当てておく人もいます。
inoremap <CR> <C-g>u<CR>
inoremap <Space> <C-g>u<Space>
文章を書く用途では効きますが、コードを書く用途では細かすぎて戻すのが面倒になります。ファイルタイプごとに設定を分けるのが現実的です。
まとめ
基本操作はu/Ctrl-rだけで十分ですが、undofileを設定しておくとファイルを閉じた後でも過去の変更を取り消せるようになります。地味ですが一度設定しておく価値の高い項目です。なおundofileとよく混同されるのがセッションですが、セッションファイルにundo履歴は入りません。レイアウトを復元してもundoは空の状態から始まります。
ここで扱ったキーは、ブラウザ上で動くVim道場の消して、元に戻すでそのまま試せます。インストールもログインも要りません。