3

OS XでEmacs(23.3.1)を使用しています。EmacsのVC機能を使用せずに、ターミナルからgitコマンドを発行しています。ファイルが変更されたときに更新するようにEmacsを設定しています。これは、.emacsファイルの次の行で有効になっています。

(custom-set-variables
 ...
 '(auto-revert-interval 1)
 ... 
)
(global-auto-revert-mode 1)

これはいつも私が期待したように機能しました。プルすると、Emacsバッファーは、バッファーを終了してそれぞれを新たにロードしたかのように、マージまたは競合で更新されます。

最近、(git-pullを使用して)単にプルするのではなく、リベース(git-fetchを呼び出してからgit-rebaseを呼び出す)を開始しました。問題が実際にgit-rebaseに関係しているかどうかはわかりませんが、確かにそうではありませんでした。その前に問題に気づき、今すぐ実行してください。

だからここに問題があります:私はファイルを更新し、変更をコミットしgit commit -am "..."、実行しgit fetch origin、そして実行しますgit rebase origin/master(時にはインタラクティブモードでコミットを一緒に押しつぶします)。リモートアップデートを取得したので、ファイルをもう少し編集してみると、最近の変更がすべて失われたように見えます。それが最初に起こったとき、私は非常に怒って、ファイルが完全に無傷であり、Emacsが変更前のファイルのバージョンに何らかの形で戻っただけであることに気付くまで、変更を失ったためにリベースアルゴリズムを呪いましたコミットしたばかりです。バッファを閉じてファイルを再度ロードすることでいつでも問題を解決できますが、これは毎回行うのが非常に面倒です。

誰かが問題が何であるかを知っていますか?

4

5 に答える 5

3

私は のオリジナルの作者ですがautorevert、かなり長い間使用していないため、記憶をかなり深く掘り下げる必要があります。

verify-visited-file-modtimeこれは、バッファをリフレッシュする必要があるかどうかをチェックするために使用を自動復帰させる Emacs コア関数の問題に要約されると思います。

これは、いくつかの理由で発生する可能性があります。

  • これは競合状態である可能性があり、Emacs は完全に書き込まれる前にファイルを読み取りますが、バッファーの modtime を終了時刻に設定します。(これが発生した場合、Emacs はバッファを途中まで自動復帰させましたが、ファイルの最終バージョンを復帰させるための新しい自動復帰はトリガーされません。)

  • ファイルの 2 つのバリアントのタイム スタンプが同じである場合、Emacs は違いを認識しません。

Lisp側でこれを適切に機能させるためにできることはほとんどないと思います(ブルートフォースソリューションに解決することなく)。Emacs は、開かれてバッファに読み込まれたファイルのフィンガープリントをアトミックに取得する必要があり、これはコアからのみ実行できます (これは私の領域外のものです)。また、一部のファイル システムではタイムスタンプの精度が 1 秒よりも高くないため、タイムスタンプを使用してファイルが変更されたかどうかを検出することは本質的に困難です。

于 2011-06-29T10:29:11.637 に答える
2

前述のように競合状態です。「git pull --rebase」は、コミットを再生するときに同じファイルを複数回変更する場合があります。以下の場合はゲームオーバーです。

  1. gitはファイル「foo」を変更します
  2. 自動復帰が開始され、「foo」がリロードされます
  3. git は、同じ秒内にファイル「foo」を再度変更します

UNIX のファイル時刻には 2 番目の解像度があるため、emacs が 2 番目の変更が発生したことを通知する方法はありません。最近、その方法で多くの変更を失ったことに気付いたので、emacs で問題に対処することにしました。次のようにemacsコードにパッチを当てました。ファイルが変更された時刻が現在のシステム時刻と同じである場合、次の間隔まで自動復帰を延期します。

;;
;; Fix the auto-revert-handler so that if the system time is the
;; same as the new modified time for a file, skip it on this
;; iteration. This should fix race conditions when a file is changed
;; multiple times within the same second.
;; 

(defun file-change-too-close-for-comfort ()
  (let* ((file-time-raw (nth 5 (file-attributes (buffer-file-name))))
         (file-time (+ (lsh (nth 0 file-time-raw) 16) (nth 1 file-time-raw)))
         (current-time (+ (lsh (nth 0 (current-time)) 16) (nth 1 (current-time)))))
    (and (eq current-time file-time)
         (message "%s: postpone revert" (buffer-name))
         t)))


(defun auto-revert-handler ()
  "Revert current buffer, if appropriate.
This is an internal function used by Auto-Revert Mode."
  (when (or auto-revert-tail-mode (not (buffer-modified-p)))
    (let* ((buffer (current-buffer)) size
           (revert
            (or (and buffer-file-name
                     (file-readable-p buffer-file-name)
                     (if auto-revert-tail-mode
                         ;; Tramp caches the file attributes.  Setting
                         ;; `tramp-cache-inhibit' forces Tramp to
                         ;; reread the values.
                         (let ((tramp-cache-inhibit-cache t))
                           (/= auto-revert-tail-pos
                               (setq size
                                     (nth 7 (file-attributes
                                             buffer-file-name)))))
                       (and (not (file-remote-p buffer-file-name))
                            (not (verify-visited-file-modtime buffer))
                            (not (file-change-too-close-for-comfort)))))
                (and (or auto-revert-mode
                         global-auto-revert-non-file-buffers)
                     revert-buffer-function
                     (boundp 'buffer-stale-function)
                     (functionp buffer-stale-function)
                     (funcall buffer-stale-function t))))
           eob eoblist)
      (when revert
        (when (and auto-revert-verbose
                   (not (eq revert 'fast)))
          (message "Reverting buffer `%s'." (buffer-name)))
        ;; If point (or a window point) is at the end of the buffer,
        ;; we want to keep it at the end after reverting.  This allows
        ;; to tail a file.
        (when buffer-file-name
          (setq eob (eobp))
          (walk-windows
           #'(lambda (window)
               (and (eq (window-buffer window) buffer)
                    (= (window-point window) (point-max))
                    (push window eoblist)))
           'no-mini t))
        (if auto-revert-tail-mode
            (auto-revert-tail-handler size)
          ;; Bind buffer-read-only in case user has done C-x C-q,
          ;; so as not to forget that.  This gives undesirable results
          ;; when the file's mode changes, but that is less common.
          (let ((buffer-read-only buffer-read-only))
            (revert-buffer 'ignore-auto 'dont-ask 'preserve-modes)))
        (when buffer-file-name
          (when eob (goto-char (point-max)))
          (dolist (window eoblist)
            (set-window-point window (point-max)))))
      ;; `preserve-modes' avoids changing the (minor) modes.  But we
      ;; do want to reset the mode for VC, so we do it manually.
      (when (or revert auto-revert-check-vc-info)
        (vc-find-file-hook)))))
于 2012-05-29T09:16:56.283 に答える
1

ファイルへの複数の変更が立て続けに行われるタイミングの問題である可能性があります。それは常に発生しますか、それともランダムですか?

また、に設定auto-revert-check-vc-infoするとt役立つ場合があります(emacsでvcと互換性のあるgitモードを使用していると仮定します)。

これまでのすべての回答で言及されているように、これはおそらくタイミングの問題です。直観に反するように思えるかもしれませんが、自動復帰間隔をより長く設定すると問題が解決する可能性があります (したがって、バッファが復帰されたときに最終状態に戻る可能性が高くなります)。

于 2011-06-28T19:40:00.717 に答える
1

auto-revert-modeファイルの変更日のみに基づいて元に戻すかどうかを決定します。私の推測では、リベース プロセス中に git がリベース ファイルの変更日を操作し、auto-revert-modeすべての変更が表示されなくなっているのです。

考えられる解決策には、touchリベース後にファイルを ing する (いや!)、auto-revert-handlerファイル サイズの変更をチェックする関数の代替バージョンを作成する、またはかなり素晴らしい emacs git インターフェイスであるmagit内でリベースすることが含まれます。

于 2011-06-29T09:52:17.743 に答える