如前所述,这是一种竞争条件。“git pull --rebase”可能会在重放您的提交时多次修改同一个文件。如果出现以下情况,则游戏结束:
- git更改文件“foo”
- 自动恢复启动并重新加载“foo”
- git 在同一秒内再次更改文件“foo”
由于 unix 文件时间具有第二个分辨率,因此 emacs 无法判断发生了第二个更改。我最近注意到我以这种方式丢失了许多更改,因此我决定尝试解决 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)))))