$linuxjunkies
>

Manage Dotfiles with yadm

Manage, version, and sync your dotfiles across machines using yadm — covering bare repo setup, OS-specific alternates, classes, GPG encryption, and bootstrap scripts.

BeginnerUbuntuDebianFedoraArch8 min readUpdated June 7, 2026

Before you start

  • Git installed and a basic understanding of git add, commit, and push
  • An SSH key or HTTPS credentials configured for your Git host
  • A GPG key in your keyring if you plan to use yadm encrypt
  • sudo or root access to install the yadm package

Dotfiles.bashrc, .vimrc, .config/drift out of sync the moment you touch a second machine. yadm (Yet Another Dotfiles Manager) solves this without moving your files into a separate directory or forcing symlinks. Under the hood it is a thin wrapper around a bare Git repository rooted in your home directory, so every Git command you already know works exactly the same way.

Install yadm

yadm is packaged in all major distro repositories. Pick your package manager:

# Debian / Ubuntu
sudo apt install yadm
# Fedora
sudo dnf install yadm
# Arch Linux
sudo pacman -S yadm

Confirm the install:

yadm --version

Initialize a Bare Repository

yadm stores its Git objects in ~/.local/share/yadm/repo.git — a bare repo — and treats $HOME as the work tree. You never see a .git folder cluttering your home directory.

yadm init

Now add files exactly as you would with Git:

yadm add ~/.bashrc ~/.vimrc ~/.config/starship.toml
yadm commit -m "Initial dotfiles commit"

Check what is tracked at any time:

yadm status

Push to a Remote

Create an empty repository on GitHub, GitLab, or any Git host, then add it as a remote. Keep it private unless you are certain no secrets are in any tracked file.

yadm remote add origin [email protected]:youruser/dotfiles.git
yadm push -u origin main

Clone Dotfiles on a New Machine

On a fresh system, one command replaces your existing dotfiles with the tracked versions and checks out the work tree into $HOME:

yadm clone [email protected]:youruser/dotfiles.git

If local files already exist and conflict, yadm will warn you rather than silently overwrite. Review conflicts with yadm status, then resolve them the normal Git way (yadm checkout -- <file> to accept the remote version).

Alternate Files: OS- and Host-Specific Configs

A single .bashrc rarely works identically on macOS, Arch, and Ubuntu. yadm solves this with alternates: you commit multiple versions of a file with a naming suffix, and yadm symlinks the correct one at bootstrap time.

The suffix format is:

filename##OS.distro,hostname.mymachine,class.Work

Conditions are matched in order of specificity. A concrete example — two .bashrc variants, one for Arch and one for Ubuntu:

cp ~/.bashrc "$HOME/.bashrc##os.Linux,distro.Arch"
cp ~/.bashrc "$HOME/.bashrc##os.Linux,distro.Ubuntu"
yadm add "$HOME/.bashrc##os.Linux,distro.Arch" "$HOME/.bashrc##os.Linux,distro.Ubuntu"
yadm commit -m "Add distro-specific bashrc alternates"

After cloning or whenever you run yadm alt, yadm evaluates the current system and creates a symlink named ~/.bashrc pointing at the best match:

yadm alt

Available condition tokens include os, distro, hostname, user, and class. Check the full list in the man page (man yadm).

Custom Classes

Classes let you tag a machine with an arbitrary label — Work, Personal, Server — and activate matching alternates. Set the class in yadm's local config (this setting is not committed to the repo):

yadm config local.class Work

Then commit a class-specific file:

cp ~/.gitconfig "$HOME/.gitconfig##class.Work"
yadm add "$HOME/.gitconfig##class.Work"
yadm commit -m "Work gitconfig with corporate email"
yadm alt

The ##class.Work variant is linked only on machines where the class is set to Work. All others fall through to a plain ~/.gitconfig if one is tracked.

Encrypt Secrets with yadm encrypt

SSH keys, API tokens, and similar secrets should not live in plain text in a Git repository. yadm integrates with GPG to encrypt files before committing them.

Step 1 — List files to encrypt

Create (or edit) ~/.config/yadm/encrypt. Each line is a glob relative to $HOME:

cat >> ~/.config/yadm/encrypt << 'EOF'
.ssh/id_ed25519
.ssh/id_ed25519.pub
.netrc
EOF

Step 2 — Encrypt and commit

You need a GPG key already in your keyring. yadm will prompt for which key to use if you have more than one:

yadm encrypt

This creates ~/.local/share/yadm/archive — a GPG-encrypted tar archive. Add that archive to the repo:

yadm add ~/.local/share/yadm/archive
yadm add ~/.config/yadm/encrypt
yadm commit -m "Add encrypted secrets archive"

Step 3 — Decrypt on a new machine

After cloning, import your GPG private key, then:

yadm decrypt

The files listed in encrypt are restored to their original paths with their original permissions.

Bootstrap Script

yadm can run a script automatically after yadm clone. Place an executable script at ~/.config/yadm/bootstrap and commit it. Typical uses: install packages, set up symlinks, run yadm alt.

cat > ~/.config/yadm/bootstrap << 'EOF'
#!/usr/bin/env bash
set -e
yadm alt
# Install packages on Debian/Ubuntu
if command -v apt &>/dev/null; then
  sudo apt install -y neovim starship tmux
fi
EOF
chmod +x ~/.config/yadm/bootstrap
yadm add ~/.config/yadm/bootstrap
yadm commit -m "Add bootstrap script"

The script fires automatically on clone. Run it manually any time with yadm bootstrap.

Day-to-Day Workflow

Once set up, working with yadm feels identical to Git:

# Stage a newly edited config
yadm add ~/.config/nvim/init.lua
yadm commit -m "Neovim: enable relative line numbers"
yadm push

# Pull updates on another machine
yadm pull

Verify Everything Is Working

A quick sanity check after setup or cloning:

# List all tracked files
yadm list -a

# Confirm alternates resolved correctly
ls -la ~/.bashrc

# Check the repo log
yadm log --oneline -5

Troubleshooting

  • Alternates not switching: Run yadm alt explicitly. Check that your condition tokens match exactly — distro.Ubuntu is case-sensitive. Verify with yadm introspect distro.
  • Decrypt fails with "no secret key": Import your GPG private key (gpg --import private.asc) before running yadm decrypt.
  • Clone leaves conflicting files: yadm will not overwrite existing files without confirmation. Use yadm checkout -- <file> to accept the repo version, or delete the local file first.
  • SSH key permissions wrong after decrypt: yadm restores permissions stored in the archive. If they are wrong, run chmod 600 ~/.ssh/id_ed25519 and re-encrypt.
  • Changes to encrypt not taking effect: Always run yadm encrypt again after editing the encrypt file, then commit the new archive.
tested on:Ubuntu 24.04Fedora 40Arch rollingDebian 12

Frequently asked questions

Do I have to move my dotfiles into a special folder?
No. yadm tracks files in place inside $HOME using a bare Git repository. Your files stay exactly where they are; no symlink farm or separate directory is needed.
Is it safe to push my dotfiles to a public GitHub repo?
Only if you are certain no file contains secrets. Keep the repository private by default, and use yadm encrypt for anything sensitive such as SSH keys or API tokens.
How do alternates differ from templating?
Alternates let you commit completely separate file variants selected by a condition; yadm symlinks the winner. Templates (using Jinja2 syntax inside a ##template file) generate a single file by substituting variables at runtime. Both solve OS-specific configs — alternates are simpler, templates are more flexible for small differences.
Can I use yadm alongside an existing bare Git dotfiles setup?
yadm is itself a bare Git repo wrapper, so you can import an existing bare repo by pointing yadm at it or by cloning it with yadm clone. All existing commits and history are preserved.
What happens if yadm alt is not run after cloning?
The alternate source files exist in $HOME but the symlinks are not created or updated. Your config may use a stale or missing symlink. Always run yadm alt (or include it in your bootstrap script) immediately after cloning.

Related guides