I'm currently working on refactoring the borg help patterns docs. I was wondering: What's the true --pattern equivalent of --exclude?
Testing with Borg 1.4.4.
According to the current docs (reinforced multiple times), the --exclude option matches - exclude patterns (fm: style, but let's ignore that for now). However, this doesn't seem to be true: In practice it looks more like --exclude matches ! no-recurse exclude patterns.
The main difference between - and ! is that if a directory is excluded with !, it isn't traversed by Borg, i.e., the directory's contents are effectively also excluded. This means that if I use a pattern style that doesn't implicitly also match a directory's contents, i.e. pf: or re:, Borg should exclude the matched directory, but not its contents. This is exactly what I'm seeing with --pattern and -, but not what I see with --exclude. With --exclude directory contents are always excluded, too.
Take the following test setup:
$ borg create repo::archive data
$ borg list repo::archive
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:25 data
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:07 data/foo
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:29:48 data/foo/bar
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:29:53 data/foo/bar/baz
-rw-r--r-- daniel daniel 3 Sun, 2026-05-17 23:29:53 data/foo/bar/baz/42
-rw-r--r-- daniel daniel 4 Sun, 2026-05-17 23:30:00 data/foo/bla
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:12 data/foo/Hello
-rw-r--r-- daniel daniel 6 Sun, 2026-05-17 23:30:12 data/foo/Hello/World
-rw-r--r-- daniel daniel 6 Sun, 2026-05-17 23:30:25 data/blubb
Let's try a pf: exclusion pattern with --pattern:
$ borg create --pattern='- pf:data/foo/bar' repo::archive1 data
$ borg list repo::archive1
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:25 data
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:07 data/foo
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:29:53 data/foo/bar/baz
-rw-r--r-- daniel daniel 3 Sun, 2026-05-17 23:29:53 data/foo/bar/baz/42
-rw-r--r-- daniel daniel 4 Sun, 2026-05-17 23:30:00 data/foo/bla
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:12 data/foo/Hello
-rw-r--r-- daniel daniel 6 Sun, 2026-05-17 23:30:12 data/foo/Hello/World
-rw-r--r-- daniel daniel 6 Sun, 2026-05-17 23:30:25 data/blubb
As expected, data/foo/bar is excluded, but the directory's contents (data/foo/bar/baz and data/foo/bar/baz/42) are not.
Let's try the supposedly same pf: exclusion pattern with --exclude instead:
$ borg create --exclude='pf:data/foo/bar' repo::archive2 data
$ borg list repo::archive2
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:25 data
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:07 data/foo
-rw-r--r-- daniel daniel 4 Sun, 2026-05-17 23:30:00 data/foo/bla
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:12 data/foo/Hello
-rw-r--r-- daniel daniel 6 Sun, 2026-05-17 23:30:12 data/foo/Hello/World
-rw-r--r-- daniel daniel 6 Sun, 2026-05-17 23:30:25 data/blubb
The directory's contents are also excluded!
This better matches the behaviour of no-recurse exclusion patterns with --pattern:
$ borg create --pattern='! pf:data/foo/bar' repo::archive3 data
$ borg list repo::archive3
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:25 data
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:07 data/foo
-rw-r--r-- daniel daniel 4 Sun, 2026-05-17 23:30:00 data/foo/bla
drwxr-xr-x daniel daniel 0 Sun, 2026-05-17 23:30:12 data/foo/Hello
-rw-r--r-- daniel daniel 6 Sun, 2026-05-17 23:30:12 data/foo/Hello/World
-rw-r--r-- daniel daniel 6 Sun, 2026-05-17 23:30:25 data/blubb
This has many implications, like that there's no difference between pp: and pf: patterns with --exclude. It also doesn't matter that with fm: and sh: patterns Borg will effectively append a * when the pattern ends with a /. The challenges with re: patterns are also wildly different between --exclude and --pattern then.
What am I missing? Is --exclude truly expected to behave like no-recurse exclusions, meaning that the docs are wrong? Or is this a bug and --exclude should actually behave like plain - exclusions?
I'm currently working on refactoring the
borg help patternsdocs. I was wondering: What's the true--patternequivalent of--exclude?Testing with Borg 1.4.4.
According to the current docs (reinforced multiple times), the
--excludeoption matches-exclude patterns (fm:style, but let's ignore that for now). However, this doesn't seem to be true: In practice it looks more like--excludematches!no-recurse exclude patterns.The main difference between
-and!is that if a directory is excluded with!, it isn't traversed by Borg, i.e., the directory's contents are effectively also excluded. This means that if I use a pattern style that doesn't implicitly also match a directory's contents, i.e.pf:orre:, Borg should exclude the matched directory, but not its contents. This is exactly what I'm seeing with--patternand-, but not what I see with--exclude. With--excludedirectory contents are always excluded, too.Take the following test setup:
Let's try a
pf:exclusion pattern with--pattern:As expected,
data/foo/baris excluded, but the directory's contents (data/foo/bar/bazanddata/foo/bar/baz/42) are not.Let's try the supposedly same
pf:exclusion pattern with--excludeinstead:The directory's contents are also excluded!
This better matches the behaviour of no-recurse exclusion patterns with
--pattern:This has many implications, like that there's no difference between
pp:andpf:patterns with--exclude. It also doesn't matter that withfm:andsh:patterns Borg will effectively append a*when the pattern ends with a/. The challenges withre:patterns are also wildly different between--excludeand--patternthen.What am I missing? Is
--excludetruly expected to behave like no-recurse exclusions, meaning that the docs are wrong? Or is this a bug and--excludeshould actually behave like plain-exclusions?