Fixes #2: https://github.com/yarlson/lnk/issues/2 Previously, files with the same basename (e.g., a/config.json and b/config.json) would overwrite each other in the repository, causing data loss. The second file would completely replace the first, and removing files would fail with 'no such file or directory' errors. Changes: - Store files using unique names based on full relative paths (slashes → underscores) - Track full relative paths in .lnk file instead of just basenames - Generate repository names from relative paths to prevent collisions - Update symlink restoration to work with new path-based system - Add comprehensive tests for basename collision scenarios This ensures each file maintains its unique content and can be managed independently, eliminating the data loss issue.
Lnk
Git-native dotfiles management that doesn't suck.
Move your dotfiles to ~/.config/lnk
, symlink them back, and use Git like normal. That's it.
lnk init
lnk add ~/.vimrc ~/.bashrc
lnk push "setup"
Install
# Quick install (recommended)
curl -sSL https://raw.githubusercontent.com/yarlson/lnk/main/install.sh | bash
# Homebrew (macOS/Linux)
brew tap yarlson/lnk
brew install lnk
# Manual download
wget https://github.com/yarlson/lnk/releases/latest/download/lnk-$(uname -s | tr '[:upper:]' '[:lower:]')-amd64
chmod +x lnk-* && sudo mv lnk-* /usr/local/bin/lnk
# From source
git clone https://github.com/yarlson/lnk.git && cd lnk && go build . && sudo mv lnk /usr/local/bin/
Usage
Setup
# Fresh start
lnk init
# With existing repo
lnk init -r git@github.com:user/dotfiles.git
Daily workflow
# Add files/directories
lnk add ~/.vimrc ~/.config/nvim ~/.gitconfig
# Check status
lnk status
# Sync changes
lnk push "updated vim config"
lnk pull
How it works
Before: ~/.vimrc (file)
After: ~/.vimrc -> ~/.config/lnk/.vimrc (symlink)
Your files live in ~/.config/lnk
(a Git repo). Lnk creates symlinks back to original locations. Edit files normally, use Git normally.
Why not just Git?
You could git init ~/.config/lnk
and manually symlink everything. Lnk just automates the tedious parts:
- Moving files safely
- Creating relative symlinks
- Handling conflicts
- Tracking what's managed
Examples
First time setup
lnk init -r git@github.com:you/dotfiles.git
lnk add ~/.bashrc ~/.vimrc ~/.gitconfig
lnk push "initial setup"
On a new machine
lnk init -r git@github.com:you/dotfiles.git
lnk pull # auto-creates symlinks
Daily edits
vim ~/.vimrc # edit normally
lnk status # check what changed
lnk push "new plugins" # commit & push
Commands
lnk init [-r remote]
- Create repolnk add <files>
- Move files to repo, create symlinkslnk rm <files>
- Move files back, remove symlinkslnk status
- Git status + sync infolnk push [msg]
- Stage all, commit, pushlnk pull
- Pull + restore missing symlinks
Technical bits
- Single binary (~8MB, no deps)
- Atomic operations (rollback on failure)
- Relative symlinks (portable)
- XDG compliant (
~/.config/lnk
) - 20 integration tests
Alternatives
Tool | Complexity | Why choose it |
---|---|---|
lnk | Minimal | Just works, no config, Git-native |
chezmoi | High | Templates, encryption, cross-platform |
yadm | Medium | Git power user, encryption |
dotbot | Low | YAML config, basic features |
stow | Low | Perl, symlink only |
FAQ
Q: What if I already have dotfiles in Git?
A: git clone your-repo ~/.config/lnk && lnk add ~/.vimrc
(adopts existing files)
Q: How do I handle machine-specific configs?
A: Git branches, or just don't manage machine-specific files with lnk
Q: Windows support?
A: Symlinks work on Windows 10+, but untested
Q: Production ready?
A: I use it daily. It won't break your files. API might change (pre-1.0).
Contributing
git clone https://github.com/yarlson/lnk.git
cd lnk
make deps # Install golangci-lint
make check # Runs fmt, vet, lint, test
What we use:
- Runtime deps: Only
cobra
(CLI framework) - Test deps:
testify
for assertions - Build pipeline: Standard Makefile with quality checks
Before submitting:
make check # Runs all quality checks + tests
Adding features:
- Put integration tests in
test/integration_test.go
- Use conventional commits:
feat:
,fix:
,docs: