I can access all the changes in the undo-tree during emacs --daemon session. But when it session is killed and new emacs --daemon is started undo-tree-visualize is shown clean.


(defun my-save-all ()
       (let ((message-log-max nil)
             (inhibit-message t))
         (save-some-buffers t)))

(defun save-all ()
  (bk-kill-buffers "magit: ebloc-broker")
  (bk-kill-buffers "__init__.py")
  (bk-kill-buffers "*helm"))

(define-key ctl-x-map "\C-s" 'save-all)

(global-undo-tree-mode 1)
(setq undo-tree-auto-save-history t)
(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))

I have observe that undo-tree history is saved under ~/.emacs.d/undo as hidden files but they won't loaded when new emacs ---daemon is started.

simple scenario:

$ (&>/dev/null emacs --daemon -nw &)
$ command emacsclient -tqu doo.py 
# - make changes check `undo-tree-visualize`
# - kill `emacs —daemon`

# restart `emacs daemon`
$ (&>/dev/null emacs --daemon -nw &)
$ command emacsclient -tqu doo.py 
# apply: M-x undo-tree-visualize

# The undo-tree is empty

[Q] Is there anyway to force emacs daemon to load the already saved unto-tree history for the opened file.

  • I am unable to reproduce the issue using Emacs 26.1 in the terminal on OSX 10.6.8. The command line option --fg-daemon seems to do nothing for me, so I used --daemon instead. STEP #1: /path/to/emacs --daemon -nw STEP #2: Open a new tab in the terminal and run the command: /path/to/emacsclient -tqu doo.py, then type in random text into the buffer and then M-x save-buffer STEP #3: Close the terminal entirely including both tabs. Open the Activity Monitor and quit the daemon, which in my case had a process name of Emacs-x86_64-10_10. .... continued below
    – lawlist
    Commented Aug 6, 2021 at 2:44
  • ... continued from comment above... STEP #4: Repeat steps #1 and #2 above, and then M-x undo-tree-visualize and I see the history created when the buffer was saved in step #1 above. STEP #5: I inspect ~/.emacs.d/undo/ and see a file named .!Users!HOME!doo.py.~undo-tree~
    – lawlist
    Commented Aug 6, 2021 at 2:46
  • Perhaps you expect Emacs to save the undo-tree history file without saving the buffer? If so, then that is the issue; i.e., the history file is created when saving the buffer. The history file is read when the buffer is opened, provided a history file already exists. There are also checks to match the history file with a SHA code embedded in the history file based upon the buffer contents ..., as well as the file name. [FYI: There is a bug in the master undo-tree repository that I've never reported, which affects a narrowed buffer being saved -- the SHA is of the narrowed buffer only.]
    – lawlist
    Commented Aug 6, 2021 at 5:08
  • Ah --fg-daemon was for macOS side I am using --daemon for linux as well, updated the question for clearity. Interestingly I can see file !Users!HOME!doo.py.~undo-tree~ and it is kept updated, file but it is not read when daemon is restarted, like the tree starts with a single root node (X) no matter what :( Please see my updated question for how I save my buffers, not sure would it affect anything.
    – alper
    Commented Aug 6, 2021 at 9:56
  • Example save file: gist.github.com/avatar-lavventura/… but it does not properly read from the new emacs daemon session :(
    – alper
    Commented Aug 6, 2021 at 10:02

1 Answer 1


I forget to add following piece of code async-undo-tree-save-history () at below, which was the main cause of the error. Since I wrote my own save () function after-save-hook hook (add-hook 'after-save-hook #'async-undo-tree-save-history) does not properly save the undo-tree history.

I have commented following section:

(with-eval-after-load "undo-tree"
  (remove-hook 'write-file-functions #'undo-tree-save-history-from-hook)
  (add-hook 'after-save-hook #'async-undo-tree-save-history))

and updated my init.el file as follows:

(defun save-all ()
  (async-undo-tree-save-history)  ;; <== added here

((file-name (buffer-file-name)))
     `(lambda ()
        (if (stringp ,file-name)
            (list 'ok
                  (list :output (with-output-to-string
                                  (require 'undo-tree)
                                  (find-file ,file-name)
                        :messages (with-current-buffer "*Messages*"
          (list 'err
                (list :output "File name must be string"
                      :messages (with-current-buffer "*Messages*"
     `(lambda (result)
        (let ((outcome (car result))
              (messages (plist-get (cadr result) :messages))
              (output (plist-get (cadr result) :output))
              (inhibit-message t))
            ((eq 'ok outcome)
             "undo-tree history saved asynchronously for %s%s%s")
            ((eq 'err outcome)
             "error saving undo-tree history asynchronously for %s%s%s")
             "unexpected result from asynchronous undo-tree history save %s%s%s"))
           (if (string= "" output)
             (format "\noutput:\n%s" output))
           (if (string= "" messages)
             (format "\nmessages:\n%s" messages))))))

(with-eval-after-load "undo-tree"   (remove-hook 'write-file-functions
#'undo-tree-save-history-from-hook)   (add-hook 'after-save-hook #'async-undo-tree-save-history)) ```

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.