2025-05-24 06:17:52 +03:00
2025-05-24 06:17:52 +03:00

Lnk

Git-native dotfiles management that doesn't suck.

Move your dotfiles to ~/.config/lnk, symlink them back, and use Git like normal. Supports both common configurations and host-specific setups.

lnk init
lnk add ~/.vimrc ~/.bashrc              # Common config
lnk add --host work ~/.ssh/config       # Host-specific config
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 (common config)
lnk add ~/.vimrc ~/.config/nvim ~/.gitconfig

# Add host-specific files
lnk add --host laptop ~/.ssh/config
lnk add --host work ~/.gitconfig

# List managed files
lnk list                    # Common config only
lnk list --host laptop      # Laptop-specific config
lnk list --all              # All configurations

# Check status
lnk status

# Sync changes
lnk push "updated vim config"
lnk pull                    # Pull common config
lnk pull --host laptop      # Pull laptop-specific config

How it works

Common files:
Before: ~/.vimrc (file)
After:  ~/.vimrc -> ~/.config/lnk/.vimrc (symlink)

Host-specific files:
Before: ~/.ssh/config (file)
After:  ~/.ssh/config -> ~/.config/lnk/laptop.lnk/.ssh/config (symlink)

Your files live in ~/.config/lnk (a Git repo). Common files go in the root, host-specific files go in <host>.lnk/ subdirectories. Lnk creates symlinks back to original locations. Edit files normally, use Git normally.

Multihost Support

Lnk supports both common configurations (shared across all machines) and host-specific configurations (unique per machine).

File Organization

~/.config/lnk/
├── .lnk                    # Tracks common files
├── .lnk.laptop             # Tracks laptop-specific files
├── .lnk.work               # Tracks work-specific files
├── .vimrc                  # Common file
├── .gitconfig              # Common file
├── laptop.lnk/             # Laptop-specific storage
│   ├── .ssh/
│   │   └── config
│   └── .tmux.conf
└── work.lnk/               # Work-specific storage
    ├── .ssh/
    │   └── config
    └── .gitconfig

Usage Patterns

# Common config (shared everywhere)
lnk add ~/.vimrc ~/.bashrc ~/.gitconfig

# Host-specific config (unique per machine)
lnk add --host $(hostname) ~/.ssh/config
lnk add --host work ~/.gitconfig

# List configurations
lnk list                    # Common only
lnk list --host work        # Work host only
lnk list --all              # Everything

# Pull configurations
lnk pull                    # Common config
lnk pull --host work        # Work-specific config

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

# Add common config (shared across all machines)
lnk add ~/.bashrc ~/.vimrc ~/.gitconfig

# Add host-specific config
lnk add --host $(hostname) ~/.ssh/config ~/.tmux.conf

lnk push "initial setup"

On a new machine

lnk init -r git@github.com:you/dotfiles.git

# Pull common config
lnk pull

# Pull host-specific config (if it exists)
lnk pull --host $(hostname)

Daily edits

vim ~/.vimrc                    # edit normally
lnk list                        # see common config
lnk list --host $(hostname)     # see host-specific config
lnk list --all                  # see everything
lnk status                      # check what changed
lnk push "new plugins"          # commit & push

Multi-machine workflow

# On your laptop
lnk add --host laptop ~/.ssh/config
lnk add ~/.vimrc                # Common config
lnk push "laptop ssh config"

# On your work machine  
lnk pull                        # Get common config
lnk add --host work ~/.gitconfig
lnk push "work git config"

# Back on laptop
lnk pull                        # Get updates (work config won't affect laptop)

Commands

  • lnk init [-r remote] - Create repo
  • lnk add [--host HOST] <files> - Move files to repo, create symlinks
  • lnk rm [--host HOST] <files> - Move files back, remove symlinks
  • lnk list [--host HOST] [--all] - List files managed by lnk
  • lnk status - Git status + sync info
  • lnk push [msg] - Stage all, commit, push
  • lnk pull [--host HOST] - Pull + restore missing symlinks

Command Options

  • --host HOST - Manage files for specific host (default: common configuration)
  • --all - Show all configurations (common + all hosts) when listing
  • -r, --remote URL - Clone from remote URL when initializing

Technical bits

  • Single binary (~8MB, no deps)
  • Relative symlinks (portable)
  • XDG compliant (~/.config/lnk)
  • Multihost support (common + host-specific configs)
  • Git-native (standard Git repo, no special formats)

Alternatives

Tool Complexity Why choose it
lnk Minimal Just works, no config, Git-native, multihost
chezmoi High Templates, encryption, cross-platform
yadm Medium Git power user, encryption
dotbot Low YAML config, basic features
stow Low Perl, symlink only

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:

License

MIT

Description
🔗 Git-native dotfiles management that doesn't suck.
Readme MIT 294 KiB
Languages
Go 94.9%
Makefile 2.8%
Shell 2.3%