lnk

April 25, 2026 · View on GitHub

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

CommandWhat 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
statusGit sync status
diffUncommitted changes
push [message]Stage, commit, push
pull [--host H]Pull and restore symlinks
doctor [--host H] [--dry-run]Find and fix repo health issues
bootstrapRun bootstrap.sh from repo

Global Options

Available with all commands:

OptionDefaultWhat it does
--colors auto|always|neverautoControl color output (auto: based on terminal detection)
--emoji, --no-emojienabledEnable/disable emoji in output
--quiet or -qoffSuppress all output (useful in scripts, exit code only)

Why lnk over alternatives

lnkchezmoiyadmstow
Config neededNoneTemplates + YAMLGit knowledgeStow directory structure
Multi-hostBuilt-in --host flagTemplatesManual branchesManual
Bulk opsadd takes multiple filesOne at a timeOne at a timePackage-based
BootstrapAutomatic on cloneSeparate scriptsSeparateNo
Health checksdoctor commandNoNoNo
Learning curveMinutesHoursMediumLow

Contributing

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

License

MIT