Confused by --exclude-file behavior

Hello,

I have been using the --iexclude-file flag to tell restic to ignore the usual temporary files and folders. But for some folders, I want to exclude everything except specific sub-folders, like in Backup public ssh keys but do not backup private ssh keys - #3 by uli and as described in the docs :

# excludes.txt
.steam/*
!.steam/steam/steamapps/compatdata/*
!.steam/steam/userdata/*
Games/*
!Games/**/Documents/*
!Games/**/Saved Games/*
.local/share/flatpak/*
!.local/share/flatpak/overrides

But, when I check the snapshots, I have empty .steam and Games folders, while .local/share/flatpak/overrides isn’t and contains files. I have tried swapping the exclude and include lines, adding extra * to includes and removing the * at the end of excludes do not create empty folders.

I run backups using the following command:

restic backup $HOME \
  --exclude-caches \
  --iexclude-file excludes.txt
Version
$ restic version
restic 0.18.0 compiled with go1.25rc2 X:nodwarf5 on linux/amd64

I had a similar issue. I include /Users/tom/Library/* but exclude some other Library sub directories, for example: !/Users/tom/Library/Preferences . I attemtped to include a subdirectory of !/Users/tom/Library/Preferences but it would always be empty. I gave up and add a pre-flight script that copies the desired sub-directory into a another included path directory as the solution.

Did you try removing the /* from the end of the add backs? I notices in the example they did not have them.

If I do for example

# excludes.txt
.steam/
!.steam/steam/steamapps/compatdata/*
!.steam/steam/userdata/*
Games/
!Games/**/Documents/*
!Games/**/Saved Games/*
.local/share/flatpak/
!.local/share/flatpak/overrides

the directories .steam, Games and .local/share/flatpak are not even present in the snapshot.

I get the same behaviour with

# excludes.txt
.steam/
!.steam/steam/steamapps/compatdata/
!.steam/steam/userdata/
Games/
!Games/**/Documents/
!Games/**/Saved Games/
.local/share/flatpak/
!.local/share/flatpak/overrides

Hm, I wonder if it is necessary to include the subfolder specifically (e.g. .steam/steam). You’ve done that with .local/share/flatpak/overrides and reported that is working as expected.

Essentially I wonder if this would work:

# excludes.txt
.steam/*
!.steam/steam
.steam/steam/*
!.steam/steam/steamapps/compatdata
!.steam/steam/userdata
...

The above reads to me as excluding all files/folders under .steam/ then specifically including the .steam/steam folder, before excluding all of its subdirectories/files, before specifically including the two subdirectories you want to keep again.

It did work with these directories for example

.local/share/docker/*
!.local/share/docker/volumes/
.local/share/containers/*
!.local/share/containers/storage/
.local/share/containers/storage/*
!.local/share/containers/storage/volumes/

yet, when I try backup-ing my Steam directory in .local/share/Steam (the location of Steam differs from one machine to another…) it does not create the directory in the backup

.local/share/Steam/*
!.local/share/Steam/steamapps
.local/share/Steam/steamapps/*
!.local/share/Steam/steamapps/compatdata
!.local/share/Steam/steamapps/compatdata/*
!.local/share/Steam/userdata
!.local/share/Steam/userdata/*

In your last example that’s not working, I think these lines are the problematic ones:

!.local/share/Steam/steamapps/compatdata/*
!.local/share/Steam/userdata/*

You shouldn’t need those. You don’t have them in the example that’s working.

@axeleroy try follow the example in the documentation:

$HOME/*
!$HOME/Documents

so your exclude file changes from:

# excludes.txt
.steam/*
!.steam/steam/steamapps/compatdata/*
!.steam/steam/userdata/*
Games/*
!Games/**/Documents/*
!Games/**/Saved Games/*
.local/share/flatpak/*
!.local/share/flatpak/overrides

into

# excludes.txt
.steam/*
!.steam/steam/steamapps/compatdata
!.steam/steam/userdata
Games/*
!Games/**/Documents
!Games/**/Saved Games
.local/share/flatpak/*
!.local/share/flatpak/overrides

So the first exclude item DOES have the /* but the following ignore exclude items do NOT have these trailing items

EDIT : “once a directory is excluded, it is not possible to include files inside the directory.” I did a local trial and found that include/ignore lines deeper than direct subfolder level are failing. The confirms the first post of TS.

Yeah I think you’ve found the final piece of the puzzle there. Namely, it’s not enough to just specify the final full depth directory, you’ve got to include/exclude every directory above it…

I did eventually get a working excludes file, after some wrangling:

# excludes
.local/share/Steam/*
!.local/share/Steam/userdata
!.local/share/Steam/steamapps
.local/share/Steam/steamapps/*
!.local/share/Steam/steamapps/compatdata

My backup command was:
restic -r repo1 backup --iexclude-file excludes ~/.local/share/Steam

Put together, the above gives me this in the snapshot (output truncated for brevity):

❯ restic -r repo1 ls latest
snapshot 1383740a of [/home/user/.local/share/Steam] at 2025-12-06 11:31:25.518948 +0000 UTC by user@server.local filtered by []:
/home
/home/user
/home/user/.local
/home/user/.local/share
/home/user/.local/share/Steam
/home/user/.local/share/Steam/steamapps
/home/user/.local/share/Steam/steamapps/compatdata
/home/user/.local/share/Steam/steamapps/compatdata/1580130
...
/home/user/.local/share/Steam/userdata
/home/user/.local/share/Steam/userdata/12345678
...

Which I think is what @axeleroy was after, at least when it comes to including only parts of the steam directory.

As an aside, this lead to me realising my own excludes file has never actually worked correctly, so I guess I now need to go and fix that. .gitignore syntax gives me a headache… :sweat_smile:

Edit: I realise we didn’t really address the ‘Games’ portion of the question.
I believe the below setup accomplishes the desired behaviour:

# excludes
Games/*/*
!Games/*/Documents
!Games/*/Saved Games
❯ restic -r repo1 backup --iexclude-file excludes ~/tmp/Games
...
❯ restic -r repo1 ls latest
...
snapshot 5bde9039 of [/home/user/tmp/Games] at 2025-12-06 11:48:22.782524349 +0000 UTC by user@server.local filtered by []:
/home
/home/user
/home/user/tmp
/home/user/tmp/Games
/home/user/tmp/Games/bar
/home/user/tmp/Games/bar/Documents
/home/user/tmp/Games/bar/Documents/afile
/home/user/tmp/Games/bar/Saved Games
/home/user/tmp/Games/bar/Saved Games/afile
/home/user/tmp/Games/foo
/home/user/tmp/Games/foo/Documents
/home/user/tmp/Games/foo/Documents/afile
/home/user/tmp/Games/foo/Saved Games
/home/user/tmp/Games/foo/Saved Games/afile

What seemed to have fixed the issue was prefixing every ignores with $HOME in addition to the excluding/re-including directories trick, as my restic backup command is restic backup $HOME --exclude-caches --iexclude-file excludes.txt

In the end, my excludes.txt looks something like that:

$HOME/**/bin
$HOME/.nvm
[...]
$HOME/.local/share/Steam/*
!$HOME/.local/share/Steam/steamapps
$HOME/.local/share/Steam/steamapps/*
!$HOME/.local/share/Steam/steamapps/compatdata
!$HOME/.local/share/Steam/steamapps/compatdata/*
!$HOME/.local/share/Steam/userdata
!$HOME/.local/share/Steam/userdata/*
[...]