Skip to content

yarlson/lnk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

46 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Lnk

Git-native dotfiles management that doesn't suck.

Lnk makes managing your dotfiles straightforward, no tedious setups, no complex configurations. Just tell Lnk what files you want tracked, and it’ll automatically move them into a tidy Git repository under ~/.config/lnk. It then creates clean, portable symlinks back to their original locations. Easy.

Why bother with Lnk instead of plain old Git or other dotfile managers? Unlike traditional methods, Lnk automates the boring parts: safely relocating files, handling host-specific setups, and even running your custom bootstrap scripts automatically. This means fewer manual steps and less chance of accidentally overwriting something important.

With Lnk, your dotfiles setup stays organized and effortlessly portable, letting you spend more time doing real work, not wrestling with configuration files.

lnk init -r git@github.com:user/dotfiles.git  # Clones & runs bootstrap automatically
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 (runs bootstrap automatically)
lnk init -r git@github.com:user/dotfiles.git

# Skip automatic bootstrap
lnk init -r git@github.com:user/dotfiles.git --no-bootstrap

# Run bootstrap script manually
lnk bootstrap

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.

Bootstrap Support

Lnk automatically runs bootstrap scripts when cloning dotfiles repositories, making it easy to set up your development environment. Just add a bootstrap.sh file to your dotfiles repo.

Examples

Simple bootstrap script:

#!/bin/bash
# bootstrap.sh
echo "Setting up development environment..."

# Install Homebrew (macOS)
if ! command -v brew &> /dev/null; then
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi

# Install packages
brew install git vim tmux

echo "βœ… Setup complete!"

Usage:

# Automatic bootstrap on clone
lnk init -r git@github.com:you/dotfiles.git
# β†’ Clones repo and runs bootstrap script automatically

# Skip bootstrap if needed
lnk init -r git@github.com:you/dotfiles.git --no-bootstrap

# Run bootstrap manually later
lnk bootstrap

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

# Clone dotfiles and run bootstrap automatically
lnk init -r git@github.com:you/dotfiles.git
# β†’ Downloads dependencies, installs packages, configures environment

# 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

# Bootstrap runs automatically
lnk init -r git@github.com:you/dotfiles.git
# β†’ Sets up environment, installs dependencies

# Pull common config
lnk pull

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

# Or run bootstrap manually if needed
lnk bootstrap

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] [--no-bootstrap] - Create repo (runs bootstrap automatically)
  • 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
  • lnk bootstrap - Run bootstrap script manually

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
  • --no-bootstrap - Skip automatic execution of bootstrap script after cloning

Technical bits

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

Alternatives

Tool Complexity Why choose it
lnk Minimal Just works, no config, Git-native, multihost, bootstrap
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