When deleting files from Emacs, the default behavior is to delete them permanently. If you already use gtrash from the command line to move files into Trash, it is natural to want Emacs deletions to behave the same way.
This note summarizes how to configure Emacs so that local file deletions use gtrash, while keeping the default behavior for remote (TRAMP) files.
The description assumes Emacs 30.1 or later.
File deletion and Trash in Emacs #
In Emacs, the behavior of file deletion depends on configuration.
When the variable delete-by-moving-to-trash is non-nil, Emacs does not delete files permanently.
Instead, it attempts to move them into the Trash.
Internally, Emacs does this by calling move-file-to-trash, which decides how the file (or directory) should be moved to Trash.
Why define system-move-file-to-trash to use gtrash
#
Emacs provides an extension point for customizing how files are moved to Trash.
That extension point is system-move-file-to-trash.
When delete-by-moving-to-trash is enabled, Emacs calls move-file-to-trash during file deletion.
This function follows a simple policy:
- If
system-move-file-to-trashis defined, Emacs calls it - Otherwise, Emacs falls back to its built-in Trash handling
By defining system-move-file-to-trash, it is therefore possible to:
- Keep Emacs deletion flow unchanged
- Replace only the underlying Trash implementation
When gtrash is used, implementing system-move-file-to-trash to invoke gtrash put allows all local Emacs deletions to use the same Trash mechanism as the command line.
Note: do not use gtrash for TRAMP files #
gtrash is a command that runs on the local machine. If it is used for deleting files accessed via TRAMP, the deleted files end up in the local Trash, which is almost always undesirable.
By default, Emacs deletes remote (TRAMP) files permanently, without using Trash. This default behavior is intentional and should be preserved.
When using gtrash from Emacs, it is safest to keep the following split:
- Local files are moved to Trash
- Remote (TRAMP) files are deleted permanently
About remote-file-name-inhibit-delete-by-moving-to-trash
#
Starting with Emacs 30.1, the variable remote-file-name-inhibit-delete-by-moving-to-trash controls how remote files are deleted.
When this variable is non-nil, remote files:
- Are never moved to Trash
- Ignore the setting of
delete-by-moving-to-trash - Are deleted permanently, following Emacs’ default behavior
The key point is that this variable overrides delete-by-moving-to-trash for remote files.
This makes it possible to use Trash for local files while keeping permanent deletion for remote files, without adding special-case logic in user code.
When using a local command such as gtrash, enabling this variable also prevents accidental mixing of remote deletions into the local Trash.
In this setup:
- The policy of whether Trash is used is handled by Emacs
- The implementation of local Trash handling is delegated to gtrash
Configuration #
Trash policy #
;; Move deleted files to trash (local only)
(setopt delete-by-moving-to-trash t
remote-file-name-inhibit-delete-by-moving-to-trash t)With this configuration:
- Local files are moved to Trash
- Remote (TRAMP) files are deleted permanently (Emacs default)
gtrash backend #
(when (executable-find "gtrash")
(defun system-move-file-to-trash (filename)
"Move FILENAME to trash using `gtrash put`."
(let ((exit-code
(call-process "gtrash" nil nil nil "put" filename)))
(unless (zerop exit-code)
(error "gtrash put failed for %s" filename))
t)))This function intentionally:
- Does not check for TRAMP paths
- Assumes it is only called for local files
It is treated as a local Trash backend and nothing more.
Observed behavior #
With the above configuration, deletion behaves as follows:
| Target | Behavior |
|---|---|
| Local file | gtrash → local Trash |
| Local directory | gtrash → local Trash |
| TRAMP file | Permanent deletion (Emacs default) |
| TRAMP directory | Permanent deletion (Emacs default) |
| Dired | Same behavior depending on local or TRAMP target |
Summary #
- Emacs can use gtrash for Trash-based deletion
system-move-file-to-trashis the extension point for replacing the Trash backend- gtrash should be treated as a local-only backend
- Remote (TRAMP) files should follow Emacs’ default permanent deletion
- On Emacs 30.1 and later, this configuration is simple and robust
This approach keeps Emacs’ deletion semantics intact while unifying the local Trash implementation with gtrash.