【Emacs】
auto-revert-mode と非ファイル
バッファの相性問題

  • Emacsではglobal-auto-revert-modeを使うと、AIエージェントやSSH越しの編集でファイルが変更されたとき、バッファを自動的に更新できます。
  • ただしglobal-auto-revert-non-file-bufferstにすると、*Buffer List*のdマークが自動更新のタイミングで消えてしまいます。
  • この問題を避けるには、non-file-buffersnilのままにするか、Buffer-menu-mode-hook*Buffer List*だけ自動更新から除外します。
(global-auto-revert-mode 1)
(setq auto-revert-remote-files t)
(setq global-auto-revert-non-file-buffers nil)Code language: Lisp (lisp)

関連記事

1. 導入のきっかけ:AIエージェントとの協働

Codex CLIやClaude Codeなど、AIエージェントを使ってコードを書かせることが増えました。
大抵は、細かなコード編集は「お任せ」するようになっているのですが、CSSや設定ファイルなどを自分でもEmacsでコードを開きながら、直接編集をすることもあります。
この設定ファイルをエージェントも変更しているときに、Emacs のバッファには反映されない、とちぐはぐな状態になってしまいます。

外部でのファイル変更に Emacs 側は気づかないまま古い内容を表示し続けてしまうと混乱のもとで、この問題を解決するのが global-auto-revert-mode です。

ディスク上のファイルが変更されたとき、確認ダイアログなしに自動でバッファを更新してくれます。

(global-auto-revert-mode 1)
(setq auto-revert-remote-files t)  ; リモートファイルも対象にするCode language: Lisp (lisp)

auto-revert-remote-filest にしておかないと、SSH 越しのファイルは自動更新の対象外になります。
リモート作業が主目的なら、この設定はセットで必要です。

2. 落とし穴:non-file-buffers を t にするとどうなるか

ファイル以外のバッファについても、自動更新の対象にできます。

(setq global-auto-revert-non-file-buffers t)Code language: Lisp (lisp)

たとえば、Dired のディレクトリ一覧がすぐ更新される、という点は便利です。
ファイルを外部から追加・削除したとき、g を押さなくても反映されます。

ただし、問題もあります。
DiredやBuffer Listなどの一覧は、 d を押すと削除マークがつき、x で実行する、という手順で閉じます。

global-auto-revert-non-file-bufferst の場合、*Buffer List* なども自動更新の対象になります。
すると、数秒ごとに一覧が再生成されるため、d でつけたマークがそのタイミングで消えてしまうのです。
x を実行する前に更新が走り、マーク操作が無効になる、ということです。

3. 対処法

3.1. シンプルな解決策:nil に戻す

最も単純な方法は、global-auto-revert-non-file-buffersnil のままにしておくことです。

(setq global-auto-revert-non-file-buffers nil)Code language: Lisp (lisp)

ファイルバッファだけが自動更新の対象になります。
Dired の自動更新は失いますが、*Buffer List* の d マーク問題も起きなくなります。
AIエージェントとの協働やリモートファイルの同期が目的なら、これで十分です。

3.2. *Buffer List* だけ除外する

Dired の自動更新は残しつつ、*Buffer List* だけ除外したい場合は、Buffer-menu-mode-hookauto-revert-mode を無効にします。

(setq global-auto-revert-non-file-buffers t)

(add-hook 'Buffer-menu-mode-hook
          (lambda ()
            (auto-revert-mode -1)))Code language: Lisp (lisp)

*Buffer List*Buffer-menu-mode で動いているため、このフックで個別に止められます。

3.3. モードごとに個別対応する

非ファイルバッファの自動更新が不要なモードが複数ある場合は、それぞれフックで止めていくやり方が細かく制御できます。

;; 検索結果一覧
(add-hook 'occur-mode-hook
          (lambda ()
            (auto-revert-mode -1)))

;; コンパイル結果
(add-hook 'compilation-mode-hook
          (lambda ()
            (auto-revert-mode -1)))

;; Diredも止めたい場合
(add-hook 'dired-mode-hook
          (lambda ()
            (auto-revert-mode -1)))Code language: Lisp (lisp)

Dired については判断が分かれます。
外部プロセスがディレクトリを変更したとき即座に反映されると便利な場面もあるため、自分の作業スタイルに合わせて決めるのがよいです。

4. 設定の方針

AIエージェントとの協働やリモートファイル編集を目的に global-auto-revert-mode を導入するなら、まず次の構成から始めるのをお勧めします。

(global-auto-revert-mode 1)
(setq auto-revert-remote-files t)
(setq global-auto-revert-non-file-buffers nil)Code language: Lisp (lisp)

non-file-buffersnil にしておき、必要になったモードだけフックで個別に有効化していく方向が、予期しない副作用を避けやすいです。

自動更新の便利さと、インタラクティブな操作の安定性は、バッファの種類によってトレードオフがあります。
ファイルバッファは積極的に同期して、マークやカーソル位置を保つ必要がある特殊バッファは自動更新から外す、という切り分けが現実的な落とし所になります。