FSVS-GROUPS(5)

πŸ“¦
version 1.2.12 Β· 2 versions
, in debian trixie, ubuntu noble, ubuntu questing, ubuntu resolute, ubuntu stonking

πŸŽ€ NAME πŸŽ€

okay bestie, welcome to FSVS-GROUPS(5) β€” the group definitions page from fsvs ✨ and it's genuinely a bop, no cap.

So like β€” using grouping patterns: patterns are what you use to define groups for new entries. And a group can do two things: it can make fsvs ignore the entries you point at, or it can automatically set properties for you when the entry gets taken onto the entry list. (The original literally says that sentence twice, so you know it's important πŸ’–.)

The way this works: the auto-props get assigned the moment the entry lands on the internal list β€” so that's when you run add, prop-set or prop-del, and obviously commit too. And if you wanna override the auto-props for some new entry? Just use the property commands. periodt. πŸ’…


πŸ¦‹ Overview πŸ¦‹

When fsvs walks through your working copy, it's on the hunt for new entries (meaning: stuff that isn't versioned yet πŸ‘€). Every single new entry gets tested against the grouping patterns you defined β€” and it tests them in the given order! If a pattern matches, boom, that entry gets assigned the corresponding group and no further matching happens. First match wins, that's the whole vibe.

Also peep: entry statii.

Predefined group 1: 'ignore'

If an entry gets a group named 'ignore' assigned to it, it will not be considered for versioning at all.

This is the only group name that's truly special. the moment. πŸ‘‘

Predefined group 2: 'take'

This group mostly just says "no further matching, we're done here" β€” so any ignore patterns that come after it don't get tested.

Basically the 'take' group is just an ordinary group like all the other ones; it's only special because it's predefined and you get a cute short-hand notation for it. 🫢


πŸ’– Why should I ignore files? πŸ’–

Ignore patterns are for ignoring certain directory entries where versioning just... makes no sense, bestie. Like, if you're versioning an entire machine's installation, you do not care about storing the contents of /proc (see man 5 proc), or maybe β€” security reasons β€” you do not want /etc/shadow, /etc/sshd/ssh_host_*key, and/or other password- or key-containing files sitting in your repo. 😭

Ignore patterns let you define exactly which directory entries (files, subdirectories, devices, symlinks, etc.) should be taken, respectively ignored. that's it, that's the power.


πŸŽ€ Why should I assign groups? πŸŽ€

Grouping patterns are basically the fsvs equivalent of subversion's auto-props feature β€” it lets you automatically define properties for new entries, or ignore them, depending on whatever criteria you want.

For example: maybe you want encryption for the files in your users' .ssh directory, so they're protected against unauthorized access in the repository, and you want to completely ignore the private key files. Main character security move. πŸ”₯

Grouping patterns:

group:ignore,/home/*/.ssh/id*
group:encrypt,/home/*/.ssh/**

And the $FSVS_CONF/groups/encrypt file would have a definition for the fsvs:commit-pipe (see the special properties).


🌸 Syntax of group files 🌸

A group definition file looks like this:

  • Whitespace at the beginning and the end of the line is ignored.
  • Empty lines, and lines where the first non-whitespace character is '#' (comments), are ignored.
  • It can have either the keywords ignore or take; if neither is specified, the group ignore has ignore as default (surprise, surprise!), and all others use take.
  • An arbitrary (small) number of lines with the syntax auto-prop property-name property-value can be given; property-name may not include whitespace, as there's no parsing of any quote characters yet.

An example:

# This is a comment
  # This is another

auto-props    fsvs:commit-pipe    gpg -er admin@my.net

# End of definition

πŸ”₯ Specification of groups and patterns πŸ”₯

While an ignore pattern just needs the pattern itself (in one of the formats below), there are some modifiers you can additionally specify:

[group:{name},][dir-only,][insens|nocase,][take,][mode:A:C,]pattern

These are listed in the section Modifiers below.

These kinds of ignore patterns are available:


✨ Shell-like patterns ✨

These must start with ./, just like a base-directory-relative path. ?, * as well as character classes [a-z] have their usual meaning, and ** is a wildcard for directory levels.

You can use a backslash \ outside of character classes to match some common special characters literally β€” e.g. \* within a pattern will match a literal asterisk character within a file or directory name. Within character classes all characters except ] are treated literally. If a literal ] should be included in a character class, it can be placed as the first character or also be escaped using a backslash.

Example for / as the base-directory:

./[oa]pt
./sys
./proc/*
./home/**~

This would ignore files and directories called apt or opt in the root directory (and files below, in the case of a directory), the directory /sys and everything below it, the contents of /proc (but take the directory itself, so that upon restore it gets created as a mountpoint 🫢), and all entries matching *~ in and below /home.

Note: The patterns are anchored at the beginning and the end. So a pattern ./sys will match only a file or directory named sys. If you want to exclude a directories' files, but not the directory itself, use something like ./dir/* or ./dir/**.

If you're deep within your working copy and you'd like to ignore some files with a WC-relative ignore pattern, you might like to use the rel-ignore command. iykyk πŸ’…


🌈 Absolute shell patterns 🌈

There is another way to specify shell patterns β€” using absolute paths. The syntax is similar to normal shell patterns; but instead of the ./ prefix the full path, starting with /, is used.

/etc/**.dpkg-old
/etc/**.dpkg-bak
/**.bak
/**~

The advantage of using full paths is that a later dump and load in another working copy (eg. when moving from versioning /etc to /) does simply work; the patterns don't have to be modified. iconic, honestly. ✨

Internally this simply tries to remove the working copy base directory at the start of the patterns (on loading); then they are processed as usual.

If a pattern does not match the wc base, and neither has the wild-wildcard prefix /**, a warning is issued. ⚠️

πŸ¦‹ PCRE-patterns πŸ¦‹

PCRE stands for Perl Compatible Regular Expressions; you can read about them with man pcre2 (if the manpages are installed), and/or perldoc perlre (if perldoc is installed).

If both fail for you, just google it. πŸ™ˆ

These patterns have the form PCRE:{pattern}, with PCRE in uppercase.

An example:

PCRE:./home/.*~

This one achieves exactly the same as ./home/**~.

Another example:

PCRE:./home/[a-s]

This would match /home/anthony, /home/guest, /home/somebody and so on, but would not match /home/theodore. πŸ’€

One more:

PCRE:./.*(.(tmp|bak|sik|old|dpkg-120

Note that the pathnames start with ./, just like above, and that the patterns are anchored at the beginning. To additionally anchor at the end you could use a $ at the end.


πŸ’… Ignoring all files on a device πŸ’…

Another form to discern what is needed and what not is possible with DEVICE:[<|<=|>|>=]major[:minor].

This takes advantage of the major and minor device numbers of inodes (see man 1 stat and man 2 stat).

The rule is as follows:

  • Directories have their parent matched against the given string.
  • All other entries have their own device matched.

This is because mount-points (ie. directories where other filesystems get attached) show the device of the mounted device, but should be versioned (as they are needed after restore); all entries (and all binding mounts) below should not. makes sense, right?

The possible options <= or >= define a less-or-equal-than respective bigger-or-equal-than relationship, to ignore a set of device classes.

Examples:

tDEVICE:3
./*
(yes, the original really does have that stray t there β€” copying it exactly, don't come for me πŸ™ˆ)

This patterns would define that all filesystems on IDE-devices (with major number 3) are taken, and all other files are ignored.

DEVICE:0

This would ignore all filesystems with major number 0 β€” in linux these are the virtual filesystems (proc, sysfs, devpts, etc.; see /proc/filesystems, the lines with nodev).

Mind NFS and smb-mounts, check if you're using md, lvm and/or device-mapper! 😭

Note: The values are parsed with strtoul(), so you can use decimal, hexadecimal (by prepending '0x', like '0x102') and octal ('0', like '0777') notation.

πŸ“ Ignoring a single file, by inode πŸ“

At last, another form to ignore entries is to specify them via the device they are on and their inode:

INODE:major:minor:inode

This can be used if a file can be hardlinked to many places, but only one copy should be stored. Then one path can be marked as to take, and other instances can get ignored.

Note: That's probably a bad example. There should be a better mechanism for handling hardlinks, but that needs some help from subversion. πŸ’€

Modifiers ✨

okay so all of these patterns can have one or more of these modifiers stuck in front of them, with (currently) optional , as separators β€” and not all combinations make sense, bestie. πŸ’… For patterns with the m (mode match) or d (dironly) modifiers the filename pattern gets optional; so you don't have to give an all-match wildcard pattern (./**) for these cases. Periodt.

take: Take pattern πŸŽ€

This modifier is just a short-hand for assigning the group take. Iconic.

ignore: Ignore pattern 🚫

This modifier is just a short-hand for assigning the group ignore. Bye.

insens or nocase: Case insensitive 🌸

With this modifier you can force the match to be case-insensitive; this can be useful if other machines use eg. samba to access files, and you cannot be sure about them leaving .BAK or .bak behind. No cap.

dironly: Match only directories πŸ“

This is useful if you have a directory tree in which only certain files should be taken; see below. (iykyk)

mode: Match entries' mode πŸ”

This expects a specification of two octal values in the form m:and_value:compare_value, like m:04:00; the bits set in and_value get isolated from the entries' mode, and compared against compare_value.

As an example: the file has mode 0750; a specification of

  • m:0700:0700 matches,
  • m:0700:0500 doesn't; and
  • m:0007:0000 matches, but
  • m:0007:0007 doesn't.

A real-world example: m:0007:0000 would match all entries that have no right bits set for 'others', and could be used to exclude private files (like /etc/shadow). (Alternatively, the others-read bit could be used: m:0004:0000.) πŸ’€

FSVS will reject invalid specifications, ie. when bits in compare_value are set that are cleared in and_value: these patterns can never match. An example would be m:0700:0007. πŸ’€

Examples 🌈

take,dironly,./var/vmail/**
take,./var/vmail/**/.*.sieve
./var/vmail/**

This would take all .*.sieve files (or directories) below /var/vmail, in all depths, and all directories there; but no other files.

If your files are at a certain depth, and you don't want all other directories taken, too, you can specify that exactly:

take,dironly,./var/vmail/*
take,dironly,./var/vmail/*/*
take,./var/vmail/*/*/.*.sieve
./var/vmail/**
mode:04:0
take,./etc/
./**

This would take all files from /etc, but ignoring the files that are not world-readable (other-read bit cleared); this way only 'public' files would get taken. Obsessed.

Author πŸ’–

Generated automatically by Doxygen for fsvs from the source code.


And the cute sign-off: this whole vibe came from fsvs, version trunk:2424, dated 11 Mar 2010, and it's literally FSVS - Group definitions(5) β€” slay, bye bestie! πŸ¦‹βœ¨

πŸ“¦ where this page comes from