A single-binary, minimalist, ultra-fast Git hooks manager for every platform.
Samoyed keeps Git hook management small, transparent, and safe. It ships as one Rust binary plus a POSIX wrapper script, so developers can install it quickly, version it with their repositories, and stay in control of what runs on commit.
- Single binary — Zero runtime dependencies. One Rust executable embeds everything.
- Transparent — All code in one file (
src/main.rs). No hidden complexity. - Cross-platform — Works on Linux, macOS, and Windows (WSL). POSIX wrapper ensures consistency.
- Developer-friendly —
SAMOYED=0to bypass,SAMOYED=2to debug. Simple escape hatches when you need them. - 80% smaller — 0.2.x radically simplifies the code from 6000+ lines across 23 modules to ~1000 lines of code in one file.
Get started in under a minute:
# Install Samoyed
curl -fsSL https://raw.githubusercontent.com/nutthead/samoyed/main/install.sh | bash
# Navigate to your Git repository
cd your-project
# Initialize hooks
samoyed init
# Edit the starter pre-commit hook
$EDITOR .samoyed/pre-commit
# Test it
git commit --allow-empty -m "test hooks"The fastest way to install Samoyed is with a single command:
curl -fsSL https://raw.githubusercontent.com/nutthead/samoyed/main/install.sh | bashThis downloads the latest pre-built binary for your platform, verifies its checksum, and places it in ~/.local/bin. To customize the installation directory:
curl -fsSL https://raw.githubusercontent.com/nutthead/samoyed/main/install.sh | INSTALL_DIR=~/bin bashIf you prefer to inspect the installer before running it:
curl -fsSL https://raw.githubusercontent.com/nutthead/samoyed/main/install.sh -o install.sh
less install.sh
bash install.shIf you have Rust installed, use cargo install:
cargo install samoyedClone the repository and build locally:
git clone https://github.com/nutthead/samoyed.git
cd samoyed
cargo install --path .Windows users should install via WSL (Windows Subsystem for Linux) and follow the Linux installation instructions above, or use cargo install samoyed in a native Windows terminal with the Rust toolchain installed.
To remove Samoyed:
curl -fsSL https://raw.githubusercontent.com/nutthead/samoyed/main/uninstall.sh | bashOr manually:
rm ~/.local/bin/samoyed
# Remove PATH entry from your shell config if added by the installerInside your Git repository, run:
samoyed init [samoyed-dirname]The samoyed-dirname defaults to .samoyed and must reside within the repository. On success, Samoyed creates:
.samoyed/
├── _/ # Hook wrappers (git-ignored)
│ ├── pre-commit
│ ├── commit-msg
│ ├── pre-push
│ ├── ... (all 14 hooks)
│ └── samoyed # POSIX wrapper script
├── pre-commit # Your editable hook (starter template)
└── .gitignore # Ignores the _/ directory
Git's core.hooksPath is configured to point to .samoyed/_/, routing all hook events through the wrapper.
The starter pre-commit script includes helpful comments. Edit it to add project-specific checks:
#!/bin/sh
# .samoyed/pre-commit
# Example: Format Rust code before commit
if ! cargo fmt --check; then
echo "Running cargo fmt..."
cargo fmt
git add --update '*.rs'
fi
# Example: Run linter
cargo clippy -- -D warnings
# Example: Ensure tests pass
cargo test --allMake it executable and commit it to version control:
chmod +x .samoyed/pre-commit
git add .samoyed/
git commit -m "Add pre-commit hook for Rust formatting and tests"Now every commit will automatically run these checks.
Bypass all hooks when you need to commit without running checks:
SAMOYED=0 git commit -m "emergency fix"Enable debug mode to see exactly what the wrapper is doing:
SAMOYED=2 git commit -m "debug this hook"This runs the wrapper with set -x, printing each command as it executes.
Bypass during initialization to prepare hooks without activating them:
SAMOYED=0 samoyed initSamoyed sources an optional initialization script at ${XDG_CONFIG_HOME:-$HOME/.config}/samoyed/init.sh before running any hook. Use this for environment setup shared across all hooks:
# ~/.config/samoyed/init.sh
# Load secrets
export DATABASE_URL="$(cat ~/.secrets/db_url)"
# Set project defaults
export RUST_BACKTRACE=1
# Skip hooks in CI (optional)
if [ -n "$CI" ]; then
exit 0
fiBecause hooks are standard shell scripts, customize them directly in .samoyed/<hook>:
# .samoyed/pre-push - runs before git push
# Ensure main branch is never pushed directly
branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
if [ "$branch" = "main" ]; then
echo "Direct pushes to main are forbidden"
exit 1
fi
# Run full test suite before pushing
cargo test --all --releaseSamoyed was built to strip Git hook tooling down to the essentials:
- One file of Rust code (
src/main.rs) manages CLI parsing, repository safety checks, and file generation. - One POSIX shell wrapper (
assets/samoyed) bootstraps every Git hook and keeps behaviour consistent across macOS, Linux, and Windows (via WSL or compatible shells). - Zero runtime dependencies. The compiled binary embeds the wrapper---
assets/samoyed---withinclude_bytes!, so distributing Samoyed is as simple as copying the executable.
In 0.2.x, Samoyed doubles down on clarity: the samoyed init command seeds every Git hook, wires them through the shared wrapper, and leaves a template pre-commit script ready for teams to adapt. Environment variables such as SAMOYED=0 (bypass) and SAMOYED=2 (debug) give developers predictable escape hatches without extra plugins.
This represents a fundamental architectural simplification from version 0.1.17, which scattered functionality across 23 separate Rust modules totaling nearly 6,000 lines of code. The current single-file implementation achieves the same functionality* in just about 1000 lines of code---an ~80% reduction in code size. By consolidating everything into src/main.rs, the codebase becomes dramatically easier to understand, debug, and maintain, while eliminating the cognitive overhead of navigating complex module hierarchies and cross-file dependencies.
*Support for samoyed.toml is removed in version 0.2.0. However I will re-introduce a well-thought-out option for configuring hooks "declaratively" in a future release.
Clone the repository and work inside a Nix shell (nix develop) or your local Rust toolchain.
Core commands:
cargo check # Fast type checks
cargo fmt # Format Rust code
cargo build --release # Build the optimised binary used in production
cargo test # Run unit testsIntegration tests live under tests/integration. Each script provisions a disposable repository via mktemp; run them individually, optionally preserving the workspace for inspection:
cd tests/integration
./01_default.sh # Run a single scenario
./08_samoyed_0.sh --keep # Keep the temporary repo after the test exitsIssues and pull requests are welcome. Before submitting a change, please ensure:
cargo fmt,cargo check, andcargo testpass locally.- Relevant integration scripts succeed.
- Commit messages follow Conventional Commit style (
feat:,fix:,chore:, …).