Project Awesome project awesome

lnk

dotfiles manager

Package 642 stars GitHub

lnk

Git-native dotfiles manager. No config files, no templates, no ceremony.

Track dotfiles across machines with one command. Lnk moves files into a Git repo (defaults to ~/.config/lnk; override with LNK_HOME or XDG_CONFIG_HOME), symlinks them back, and stays out of your way.

lnk init -r git@github.com:you/dotfiles.git   # clone & bootstrap
lnk pull                                       # restore symlinks
lnk add ~/.vimrc ~/.bashrc ~/.gitconfig        # track files
lnk add --host work ~/.ssh/config              # per-machine config
lnk push "done"                                # commit & push

Install

curl -sSL https://raw.githubusercontent.com/yarlson/lnk/main/install.sh | bash

Or with Homebrew:

brew install lnk

Or grab a binary from releases, or build from source:

go install github.com/yarlson/lnk@latest

How it works

Before: ~/.vimrc (regular file)
After:  ~/.vimrc → ~/.config/lnk/.vimrc (symlink into git repo)

Common files live at the repo root. Host-specific files go in <hostname>.lnk/ subdirectories. A plain text .lnk file tracks what's managed — one path per line, no special format.

~/.config/lnk/
├── .lnk                 # tracked common files
├── .lnk.work            # tracked work-specific files
├── .vimrc               # common
├── .gitconfig            # common
└── work.lnk/            # host-specific storage
    └── .ssh/config

Usage

Add files

lnk add ~/.vimrc ~/.bashrc                # multiple at once
lnk add --recursive ~/.config/nvim        # each file individually
lnk add --host laptop ~/.ssh/config       # host-specific
lnk add --dry-run ~/.tmux.conf            # preview first

Sync

lnk status                                # what changed (works even without remote)
lnk diff                                  # uncommitted changes
lnk diff --quiet                          # exit code only, no output
lnk diff --colors always                  # force color output (useful in scripts/redirects)
lnk push "updated vim config"             # commit & push
lnk pull                                  # pull & restore symlinks
lnk pull --host work                      # pull host-specific config

status works without a remote configured — it shows local state (dirty/clean, unpushed commits) and guides you to add a remote.

Remove

lnk rm ~/.vimrc                           # moves file back, removes symlink
lnk rm --force ~/.bashrc                  # tracking cleanup only (no file restoration)

--force is for cleanup when the symlink is already gone (e.g., you deleted it manually). It removes the entry from .lnk and the stored file from the repo, but does not restore anything to your home directory. Use normal lnk rm for a full removal with restoration.

List

lnk list                                  # common files
lnk list --host work                      # host-specific
lnk list --all                            # everything

Health checks

lnk doctor --dry-run                      # preview issues
lnk doctor                                # fix broken symlinks & stale entries

When restoring symlinks, if a real file exists at the target location (not a symlink), it will be renamed to <path>.lnk-backup to preserve your data before the symlink is created. Check for .lnk-backup files after running doctor or pull if you expect them.

Bootstrap

Drop a bootstrap.sh in your dotfiles repo. Lnk runs it automatically on lnk init -r <url>.

lnk init -r <url> --no-bootstrap          # skip auto-bootstrap
lnk bootstrap                             # run manually

New machine setup

lnk init -r git@github.com:you/dotfiles.git
lnk pull
lnk pull --host $(hostname)

That's it. Bootstrap runs automatically, symlinks get restored, you're working.

Commands

Command What it does
init [-r url] [--force] [--no-bootstrap] Create or clone a dotfiles repo
add [--host H] [--recursive] [--dry-run] <files> Track files (move to repo + symlink)
rm [--host H] [--force] <file> Untrack file (restore to original location)
list [--host H] [--all] Show tracked files
status Git sync status
diff Uncommitted changes
push [message] Stage, commit, push
pull [--host H] Pull and restore symlinks
doctor [--host H] [--dry-run] Find and fix repo health issues
bootstrap Run bootstrap.sh from repo

Global Options

Available with all commands:

Option Default What it does
--colors auto|always|never auto Control color output (auto: based on terminal detection)
--emoji, --no-emoji enabled Enable/disable emoji in output
--quiet or -q off Suppress all output (useful in scripts, exit code only)

Why lnk over alternatives

lnk chezmoi yadm stow
Config needed None Templates + YAML Git knowledge Stow directory structure
Multi-host Built-in --host flag Templates Manual branches Manual
Bulk ops add takes multiple files One at a time One at a time Package-based
Bootstrap Automatic on clone Separate scripts Separate No
Health checks doctor command No No No
Learning curve Minutes Hours Medium Low

Contributing

git clone https://github.com/yarlson/lnk.git
cd lnk
make check    # fmt, vet, lint, test

License

MIT

Back to Dotfiles