Yar Kravtsov f96bfb6ce0 fix: prevent file loss when multiple files have same basename
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.
2025-05-24 18:10:20 +03:00
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. 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 repo
  • lnk add <files> - Move files to repo, create symlinks
  • lnk rm <files> - Move files back, remove symlinks
  • lnk status - Git status + sync info
  • lnk push [msg] - Stage all, commit, push
  • lnk 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:

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%