Vimのセッション保存と復元(:mksession / :source / sessionoptions)
複数のファイルを開いてウインドウを分割し、やっと作業しやすい配置になったところで一度Vimを終了すると、次に開いたときは真っ白な1枚のウインドウからやり直しになります。この「配置ごと保存して丸ごと戻す」を実現するのがセッション機能です。:mksessionで今の状態をファイルに書き出し、vim -Sや:sourceで読み込むだけなので覚えることは少ないのですが、「何が保存されるか」の境界線を誤解している人が多い機能でもあります。
目次(8項目)
| コマンド | これだけ覚える |
|---|---|
:mksession {ファイル名} | 今の状態をセッションファイルに保存 |
:mksession! | 既存のセッションファイルを上書き保存 |
vim -S {ファイル名} | 起動と同時にセッションを復元 |
:source {ファイル名} | 起動中のVimにセッションを読み込む |
セッションで保存される状態
セッションが保存するのは、ファイルの中身そのものではなく「どのファイルをどう並べて開いていたか」というVimの画面構成です。具体的には、開いていたファイルのパス、ウインドウの分割状態と各ウインドウの大きさ、タブの並び、カレントウインドウやカーソル位置、カレントディレクトリなどが対象になります。手元のVim 9.1で3つのファイルを開いて水平分割・垂直分割・タブを組み合わせた状態から:mksessionを実行し、Vimを完全に終了してからvim -Sで開き直したところ、分割の形とタブの構成、各ウインドウに表示されているファイルまで元の状態と完全に一致しました。
1つのファイルの中で「前回開いていた場所に戻る」だけなら:oldfilesで十分ですが、セッションはファイル単位ではなく画面全体のレイアウトを対象にする点が異なります。プロジェクトを切り替えるたびに毎回同じウインドウ構成を作り直している人ほど、セッションのほうが恩恵が大きくなります。
保存する::mksessionと:mksession!
:mksession {ファイル名}を実行すると、指定した名前でセッションファイルが作成されます。ファイル名を省略すると、カレントディレクトリにSession.vimという名前で保存されます。
:mksession
:mksession my-project.vim
同名のファイルが既に存在する場合、:mksessionだけではエラーになって上書きされません。実際に既存のSession.vimがある状態で:mksession Session.vimを試すとE189のエラーが出て内容は変更されず、末尾に!を付けた:mksession!にすると確認なしで上書きされることを確認しました。作業を進めるたびに同じファイル名で保存し直したい場合は、!を付ける運用にしておくと毎回のエラーで手が止まりません。
復元する:vim -Sと:source
保存したセッションを開き直す方法は2つあります。シェルから新しくVimを起動するときは-Sオプションにセッションファイルを渡します。すでにVimを起動している状態で読み込みたいときは:sourceコマンドを使います。
vim -S Session.vim
:source Session.vim
$ ls Session.vim main.py test.py $
vim -S Session.vim┌─ main.py ─┬─ test.py ─┐ │ │ │ └───────────┴───────────┘
Vimを終了した直後はシェルのプロンプトが1行あるだけですが、vim -Sでセッションファイルを渡すと、終了前に組んでいた垂直分割の配置がそのまま復元されます。:sourceで読み込む場合は、すでに開いているウインドウを土台にしてセッションの内容が積み重なる形で復元されるため、何も開いていない状態のVimで読み込むほうが元の配置を素直に再現できます。
sessionoptionsで保存内容を制御する
実際に何を保存するかは'sessionoptions'(省略形'ssop')オプションで決まります。手元のVim 9.1で確認した既定値は次のとおりです。
:set sessionoptions?
sessionoptions=blank,buffers,curdir,folds,help,options,tabpages,winsize,terminal
コンマ区切りの各単語が保存対象を1つずつ表しており、set sessionoptions+=単語で追加、set sessionoptions-=単語で除外できます。全単語の意味と、既定で有効かどうかを一つずつ実機で確認しながら整理しました。
| 単語 | 保存・復元する内容 | 既定 |
|---|---|---|
blank | ファイルを開いていない空のウインドウ | 有効 |
buffers | ウインドウに表示されていない隠れたバッファも含めて保存 | 有効 |
curdir | カレントディレクトリ(cdで復元) | 有効 |
folds | 手動で作った折り畳みと開閉状態 | 有効 |
globals | 大文字で始まり小文字を含むグローバル変数(文字列・数値のみ) | 無効 |
help | ヘルプウインドウ | 有効 |
localoptions | ウインドウ・バッファごとのローカル設定とマッピング | 無効 |
options | グローバル設定や、ローカル設定の全体既定値、マッピング | 有効 |
resize | Vim全体の行数・列数('lines'/'columns') | 無効 |
sesdir | セッションファイルのある場所をカレントディレクトリにする | 無効 |
skiprtp | 'runtimepath'/'packpath'を保存対象から除く | 無効 |
slash | パスの区切りをスラッシュに統一(Windows用) | 無効 |
tabpages | 全タブページ(外すと今のタブだけ保存) | 有効 |
terminal | ターミナルウインドウ(実行コマンドも復元) | 有効 |
unix | 改行コードをUnix形式(LF)に統一 | 無効 |
winpos | Vimウインドウ自体の画面上の位置 | 無効 |
winsize | 各ウインドウのサイズ比率 | 有効 |
特に誤解しやすいのがoptionsとglobalsです。前者は既定で有効なので普段は意識しませんが、これを外すとset numberなどバッファごとの設定が復元されず、開いた瞬間は素のVimと同じ見た目になります。後者は既定で無効なので、プラグインが独自に持つグローバル変数を引き継ぎたい場合は明示的に追加が必要です。実際にlet g:MyVar = "hello"を設定してから既定のまま:mksessionすると、生成されたSession.vimにはMyVarへの言及が一切なく、set sessionoptions+=globalsを付けて保存し直すとlet MyVar = "hello"という行が追加されることを確認しました。buffersとfoldsも同様で、buffersを外すと画面に表示されていない隠れたバッファはbadd行から消え、foldsを外すと復元後に折り畳みがすべて開いた状態になります。curdirとsesdirは同時に使うものではなく、どちらもファイルパスの基準をどこに置くかを決める設定なので、両方入れると挙動が競合します。
セッションに保存されないもの
ここが最も誤解されやすいところです。セッションはあくまで「画面のレイアウト」を保存するだけで、バッファの中身や作業の履歴そのものは対象外になります。実際に、a.txtを開いて末尾に1行書き足した状態(保存前)でレジスタに文字列を入れてから:mksessionし、Vimを完全に終了してからセッションを読み込み直す検証をしました。
- 未保存の変更:書き足した1行は復元後のバッファに存在せず、ディスク上のファイル内容がそのまま読み込まれました。
- undo履歴:復元直後に
undotree()で確認したところseq_lastは0で、undoできる操作が何も無い状態でした。 - レジスタの内容:セッション保存前に
@aへ入れておいた文字列は、復元後に空文字列になっていました(viminfoを使わない設定で確認)。 - コマンド履歴・検索履歴:セッションファイルには含まれず、こちらも別の仕組みで管理されています。
- マーク:ファイル内に付けたマーク(
ma等)も、セッション自体には保存されません。
つまりセッションを読み込んで最初に目にする画面は「終了時のウインドウ配置」であって「終了時の作業状態」ではありません。書き途中の変更を残したまま:mksessionした直後に、うっかり:qa!で保存せずに終了すると、レイアウトだけ戻って中身の変更は消えたままになるので注意が必要です。
viminfo/shadaとの違い
「終了しても情報が残る」という点でセッションとよく混同されるのがviminfo(Neovimではshada)です。役割はきれいに分かれていて、セッションは「今開いているウインドウ構成」というその場限りの状態を1ファイルにスナップショットするのに対し、viminfo/shadaはレジスタやマークなど「Vimを使い続ける中でずっと積み重なる情報」をバックグラウンドで自動的に更新し続けます。
| 保存される情報 | Session.vim | viminfo / shada |
|---|---|---|
| 開いているファイル・ウインドウ配置 | 保存する | 保存しない |
| レジスタの内容 | 保存しない | 保存する |
| ファイル内のマーク | 保存しない | 保存する |
| コマンド・検索履歴 | 保存しない | 保存する |
| :oldfiles用のファイル履歴 | 保存しない | 保存する |
| 更新のタイミング | 手動で:mksessionしたときだけ | 終了時などに自動更新 |
実務上は「プロジェクト単位の画面配置」はセッション、「使い続けるほど便利になる横断的な情報」はviminfo/shadaと役割分担していると考えると混乱しません。どちらか片方だけを使う運用よりも、両方を併用してそれぞれの強みを活かす方が実用的です。
実用的な運用
個人的にはプロジェクトのルートディレクトリにSession.vimを置き、作業を中断するときに:mksession!で上書き保存する運用に落ち着いています。次にそのディレクトリへcdしてからvim -S Session.vimを打つだけで、分割していたウインドウやタブが全部戻ってくるので、複数プロジェクトを掛け持ちしているときの「あの配置どうだったか」を思い出す手間が減りました。
1点だけ注意しているのが、Session.vimを.gitignoreに入れておくことです。curdirが既定で有効なため、セッションファイルには自分の環境の絶対パスがそのまま書き込まれます。これをリポジトリにコミットしてしまうと、他の人の環境やCIで開いたときにパスが存在せずエラーになりますし、自分のホームディレクトリ名のような情報が意図せず公開されてしまう可能性もあります。チームで共有したい場合は絶対パスではなく相対パスで運用できるようsesdirの利用を検討するか、そもそもセッションは個人の作業環境に紐づくものと割り切って共有しない、のどちらかが安全です。
まとめ
:mksessionで保存してvim -Sで開き直すだけで、開いていたファイルとウインドウ・タブの配置はそのまま戻ってきます。ただし保存されるのはあくまで画面のレイアウトで、未保存の変更やundo履歴、レジスタの中身までは戻らない点は覚えておく必要があります。sessionoptionsで保存範囲を細かく調整できるので、まずは既定値のまま試して、必要に応じてglobalsやresizeを足していくのが無理のない使い方です。