ForceBackups

By default, Emacs creates a backup only when you save the first time. This is incompatible with most people’s basic editing behavior of leaving Emacs and its buffers open all the time and constantly making changes and writing them to disk. Here we describe how to make Emacs do a backup on every save, not just the first.

By default, Emacs never backs up versioned files. Since we’re going to be backing up intermediate copies, we want to backup versioned files too, since we don’t commit on every save:

  (setq vc-make-backup-files t)

Next, we configure Emacs to handle multiple backups:

  (setq version-control t ;; Use version numbers for backups.
        kept-new-versions 10 ;; Number of newest versions to keep.
        kept-old-versions 0 ;; Number of oldest versions to keep.
        delete-old-versions t ;; Don't ask to delete excess backup versions.
        backup-by-copying t) ;; Copy all files, don't rename them.
  
  ;; If you want to avoid 'backup-by-copying', you can instead use
  ;;
  ;; (setq backup-by-copying-when-linked t)
  ;;
  ;; but that makes the second, "per save" backup below not run, since
  ;; buffers with no backing file on disk are not backed up, and
  ;; renaming removes the backing file.  The "per session" backup will
  ;; happen in any case, you'll just have less consistent numbering of
  ;; per-save backups (i.e. only the second and subsequent save will
  ;; result in per-save backups).
  
  ;; If you want to avoid backing up some files, e.g. large files,
  ;; then try setting 'backup-enable-predicate'.  You'll want to
  ;; extend 'normal-backup-enable-predicate', which already avoids
  ;; things like backing up files in '/tmp'.

Finally, we tell emacs to make a backup on each save, not just the first, by unsetting ‘buffer-backed-up’. We make two kinds of backups: per-session backups, once on the first save of each emacs session, and per-save backups, once on every save. The backups go in different places and Emacs creates the backup dirs automatically if they don’t exist:

  ;; Default and per-save backups go here:
  (setq backup-directory-alist '(("" . "~/.emacs.d/backup/per-save")))
  (defun force-backup-of-buffer ()
    ;; Make a special "per session" backup at the first save of each
    ;; emacs session.
    (when (not buffer-backed-up)
      ;; Override the default parameters for per-session backups.
      (let ((backup-directory-alist '(("" . "~/.emacs.d/backup/per-session")))
            (kept-new-versions 3))
        (backup-buffer)))
    ;; Make a "per save" backup on each save.  The first save results in
    ;; both a per-session and a per-save backup, to keep the numbering
    ;; of per-save backups consistent.
    (let ((buffer-backed-up nil))
      (backup-buffer)))
  (add-hook 'before-save-hook  'force-backup-of-buffer)

See also BackupEachSave which is probably similar but has more features and is maybe more stable.

The (old) above function

  (defun force-backup-of-buffer ()
    (let ((buffer-backed-up nil))
      (backup-buffer)))

doesn’t preserve file permissions. As an alternative, how about simply:

  (defun force-backup-of-buffer ()
    (setq buffer-backed-up nil))

Keeping the N new and N old versions of the file is kind of brain dead. Here’s a simulation in Emacs Lisp of 8 saves using lists, showing what backups are available after each save when N is 2.

  (let ((saves (number-sequence 1 8))
        (backups '()))
    (while (car saves)
      (setq backups (cons (car saves) backups))
      (pp backups)
      (unless (< (length backups) (+ kept-old-versions kept-new-versions))
        (setq backups
              (append (butlast backups (- (1+ (length backups)) kept-new-versions))
                      (last backups kept-old-versions))))
      (setq saves (cdr saves))))
  =>
  (1)
  (2 1)
  (3 2 1)
  (4 3 2 1)
  (5 4 2 1)
  (6 5 2 1)
  (7 6 2 1)
  (8 7 2 1)

CategoryFiles