Winstow is a Windows-native symlink farm manager inspired by GNU Stow. It helps you manage your dotfiles, configuration files, and software packages by creating symbolic links from a central stow directory to a target directory (typically your home directory).
Key Features:
Windows-Native: Built specifically for Windows with proper symlink support.
GNU Stow Compatible: Familiar interface if you've used GNU Stow.
Directory Folding: Intelligent directory symlinking reduces the number of links needed.
Conflict Resolution: Offers --adopt and --override options to handle existing files during stow or restow operations.
Pattern Matching: Use --ignore and --defer for flexible file management, allowing you to skip certain files or defer conflicts.
Configuration File Support: Set defaults using a .winstowrc configuration file.
Small & Fast: A single ~600KB binary ensures quick performance.
Safe Operations: Includes dry-run mode to preview changes before applying them.
Audience & Benefit:
Ideal for Windows users managing dotfiles, configuration files, or software packages. Winstow enables efficient organization and management of files without cluttering your target directory. It allows you to update configurations easily and provides safe operations with conflict resolution options, ensuring that file management remains predictable and controlled.
Winstow can be installed via winget when it becomes available through package managers like Scoop or WinGet.
README
Winstow
Winstow is a Windows-native symlink farm manager inspired by GNU Stow. It helps you manage your dotfiles, configuration files, and software packages by creating symbolic links from a central stow directory to a target directory (typically your home directory).
Disclaimer
I created Winstow to replicate my GNU Stow dotfile management workflow from Linux on Windows - keeping all my configuration files in a single git repository and symlinking them as needed.
⚠️ Note: Winstow is currently in active development and may be unstable. The API is subject to change without prior notice. Please use it with caution and make backups of your files before using it.
I'm still learning Rust, so the code may not be the most idiomatic or efficient. Suggestions for improvement are welcome.
⚠️ Winstow is not a 1:1 port of GNU Stow and does not guarantee identical range of functionality or behavior.
Why Winstow?
✅ Windows-Native: Built specifically for Windows with proper symlink support
✅ GNU Stow Compatible: Familiar interface if you've used GNU Stow
✅ Directory Folding: Intelligent directory symlinking reduces link count
✅ Conflict Resolution: --adopt and --override for handling existing files
✅ Pattern Matching: --ignore and --defer for flexible file management
✅ Configuration Files: Set defaults with .winstowrc
✅ Small & Fast: Single ~600KB binary
✅ Safe: Dry-run mode to preview changes before applying
Prerequisites
To create symbolic links on Windows, you need one of the following:
# Clone the repository
git clone https://github.com/MathiasCodes/winstow.git
cd winstow
# Build release binary
cargo build --release
# Binary will be at target/release/winstow.exe
Skip files matching pattern if they already exist in target (stow/restow only)
-h
--help
Show help message
-V
--version
Show version
Examples
Managing Dotfiles
PowerShell:
# Set up your stow directory
mkdir $env:USERPROFILE\Dotfiles
cd $env:USERPROFILE\Dotfiles
mkdir Git
mkdir Git-Bash
# Move your dotfiles into the packages
move $env:USERPROFILE\.gitconfig Git\
move $env:USERPROFILE\.bashrc Git-Bash\
move $env:USERPROFILE\.inputrc Git-Bash\
# Stow the packages
winstow -d $env:USERPROFILE\Dotfiles -t $env:USERPROFILE Git
winstow -d $env:USERPROFILE\Dotfiles -t $env:USERPROFILE Git-Bash
# Now .gitconfig, .bashrc, and .inputrc are symlinks to your Dotfiles packages
Git Bash:
# Set up your stow directory
mkdir -p $USERPROFILE/Dotfiles
cd $USERPROFILE/Dotfiles
mkdir Git
mkdir Git-Bash
# Move your dotfiles into the packages
mv $USERPROFILE/.gitconfig Git/
mv $USERPROFILE/.bashrc Git-Bash/
mv $USERPROFILE/.inputrc Git-Bash/
# Stow the packages
winstow -d $USERPROFILE/Dotfiles -t $USERPROFILE Git
winstow -d $USERPROFILE/Dotfiles -t $USERPROFILE Git-Bash
# Now .gitconfig, .bashrc, and .inputrc are symlinks to your Dotfiles packages
Handling Conflicts
# If files already exist in target, you'll get an error
winstow mypackage
# Error: Conflict: C:\Users\You\.gitconfig already exists
# Option 1: Adopt the existing file into the package
winstow --adopt mypackage
# Moves .gitconfig into mypackage/, then creates symlink
# Option 2: Override (remove) the existing file
winstow --override mypackage
# Removes .gitconfig, then creates symlink (destructive!)
Using Ignore and Defer Patterns
# Ignore backup files and OS metadata (always skip these)
winstow --ignore "*.bak" --ignore ".DS_Store" --ignore "Thumbs.db" mypackage
# Ignore entire directories
winstow --ignore "node_modules" mypackage
# Defer allows another package to manage shared files
# If .bashrc already exists, skip it; otherwise, stow it
winstow --defer ".bashrc" package-a
# Later, package-b can manage .bashrc
winstow package-b # This will stow .bashrc from package-b
--defer: Skip files matching the pattern only if they already exist in the target directory (useful for shared configuration files managed by different packages)
Restowing After Updates
PowerShell:
# After updating your dotfiles repository
cd $env:USERPROFILE\Dotfiles
git pull
# Refresh symlinks
winstow -R -d $env:USERPROFILE\Dotfiles -t $env:USERPROFILE Git
Git Bash:
# After updating your dotfiles repository
cd $USERPROFILE/Dotfiles
git pull
# Refresh symlinks
winstow -R -d $USERPROFILE/Dotfiles -t $USERPROFILE Git
Dry-Run Mode
PowerShell:
# See what would happen without making changes
winstow -n -v Git
# Output:
# === DRY RUN MODE - No changes will be made ===
# [DRY RUN] Create file link: .gitconfig -> ..\Dotfiles\Git\.gitconfig
# Would stow 1 package(s)
Git Bash:
# See what would happen without making changes
winstow -n -v Git
# Output:
# === DRY RUN MODE - No changes will be made ===
# [DRY RUN] Create file link: .gitconfig -> ..\Dotfiles\Git\.gitconfig
# Would stow 1 package(s)
Configuration File
Create a .winstowrc file in one of these locations:
Problem: Dry-run output doesn't match actual execution
Note: Dry-run simulates operations but doesn't account for all dynamic conditions. Always make sure you have a backup of your files.
Development
Building
# Development build
cargo build
# Release build (optimized)
cargo build --release
# Run tests
cargo test
# Run tests including ignored ones (requires Developer Mode)
cargo test -- --ignored
All tests use temporary directories and should be safe to run:
# All tests (unit + integration)
cargo test
# Just integration tests
cargo test --test integration_tests
# Test with output
cargo test -- --nocapture
# Tests requiring symlink creation (needs Developer Mode)
cargo test -- --ignored