Save my dotfiles!

Gabriel Capella 64590fe102 Sync: 2026-08-01 12:40:41 2 өдөр өмнө
dots 53fb71a496 Sync: 2026-08-01 12:21:58 2 өдөр өмнө
dots.tompot 6526b1d1e3 Sync: 2026-08-01 11:44:54 2 өдөр өмнө
.gitignore 75f7923e52 Fri May 13 22:43:43 BST 2022 4 жил өмнө
.gitmodules 0febe31711 Remove Vundle.vim submodule 3 сар өмнө
README.md c2daf49e55 Sync: 2026-08-01 12:38:32 2 өдөр өмнө
bootstrap 6344f7c8d0 Sync: 2026-08-01 12:30:41 2 өдөр өмнө
groups.jellyfish 2d48e25952 Add multi-host dotfiles support with groups and in-file markers 4 сар өмнө
groups.tompot 2d48e25952 Add multi-host dotfiles support with groups and in-file markers 4 сар өмнө
pkglist 64590fe102 Sync: 2026-08-01 12:40:41 2 өдөр өмнө
pkglist.jellyfish 4fd9a8f59a Sync: 2026-08-01 12:32:21 2 өдөр өмнө
pkglist.tompot 721994bafe Sync: 2026-08-01 12:28:51 2 өдөр өмнө
start c2daf49e55 Sync: 2026-08-01 12:38:32 2 өдөр өмнө
to_sync 220b391405 Sync: 2026-08-01 11:57:59 2 өдөр өмнө

README.md

Dotfiles

Manages dotfiles, packages, and system state across multiple machines, with per-host and per-group overrides.

Quick start

curl https://git.capella.pro/capella/dotfiles/raw/master/start | bash -s -- sync

Or if already installed:

dotsync

Usage

start sync [--machine|--group <name>] [dot_file]
start list
start status
start packages [install|diff|save]

sync also commits and pushes the repo. It is unprivileged and fast; packages needs sudo, so it is deliberately not run as part of sync.

Repository layout

dots/                    # common dotfiles (all hosts)
dots.<hostname>/         # host-specific dotfiles
dots.@<group>/           # group-level dotfiles

to_sync[.<hostname>|.@<group>]    # which dotfiles to deploy
pkglist[.<hostname>|.@<group>]    # which packages to install
groups.<hostname>                 # group membership, one per line

start                    # this tool
bootstrap                # system state that needs root (see below)

Multi-host

Each host is identified by its hostname (uname -n).

File overrides

Resolution order (last wins): common -> groups (alphabetical) -> host.

A host copy of a file replaces the common one entirely, so host overrides must be complete files, not fragments.

Sync lists

to_sync                  # files synced to all hosts
to_sync.<hostname>       # additional files for a specific host
to_sync.@<group>         # additional files for a group

Groups

groups.<hostname>        # one group name per line

Example groups.jellyfish:

wayland

Hosts in the same group share to_sync.@<group>, dots.@<group>/ and pkglist.@<group>.

In-file markers

For files that are mostly shared with a few per-host differences, use markers instead of duplicating the whole file:

# @host jellyfish
set $mod Mod4
# @end

# @host tompot
set $mod Mod1
# @end

# @group wayland
exec waybar
# @end
  • Lines between @host <name> and @end are included only on that host
  • Lines between @group <name> and @end are included for hosts in that group
  • Lines outside any markers are always included
  • The comment prefix (#, //, ;, etc.) is auto-detected
  • Files with markers are processed and written (not symlinked)
  • Files without markers are symlinked as usual

Generated files carry a DO NOT EDIT header naming their source. Edit the file under dots/, not the copy in $HOME.

Adding dotfiles

# Add to common (all hosts):
dotsync sync .config/foo

# Add for this host only:
dotsync sync --machine .config/bar

# Add for a group:
dotsync sync --group wayland .config/baz

Packages

dotsync packages          # install tracked packages missing here
dotsync packages diff     # show drift both ways, change nothing
dotsync packages save     # write this host's packages to pkglist.<hostname>

Package lists are additive, not last-wins: pkglist, pkglist.@<group> and pkglist.<hostname> are unioned. A host list adds to the common one and can never remove from it. This is the opposite of how dotfiles resolve -- overriding makes sense for a config file, not for a package set.

Put a package in pkglist when you want it everywhere, and in pkglist.<hostname> only when it is genuinely specific to that machine (hardware, or a role the other hosts do not have).

Lists record explicitly installed packages only (yay -Qqe), so packages pulled in as dependencies stay out and get resolved automatically. Locally built -debug artifacts are filtered out: makepkg generates them on whichever machine did the build, and they are not installable elsewhere.

packages never removes anything. Dropping an entry from a list makes it show up under "installed but NOT tracked" in diff; uninstall it yourself. A sync command that can silently uninstall is not worth the convenience.

System state

bootstrap covers what dotsync cannot: things outside $HOME that need root.

./bootstrap

It is idempotent -- files are only written when their content differs, and units are skipped when already enabled, or when the package providing them is not installed on this host. Run it after dotsync packages.

Currently it manages:

  • KillUserProcesses=no, as a logind drop-in so package upgrades cannot revert it (the default kills etterminal and takes the whole etserver down)
  • greetd autologin into sway
  • iwd stop timeout
  • enabling the system and user units the desktop needs

It needs a real terminal, since sudo has to prompt. Host differences use a plain case $(uname -n), not @host markers -- those only apply to files deployed into $HOME.