Dotfile manager with git-powered branching
Project description
dot-man
Dotfile manager with git-powered branching
Switch your entire development environment in one command.
Install · Quick Start · Commands · Config · Docs
What is dot-man?
dot-man stores your dotfiles in a git repository and uses branches as configuration profiles. Each branch is a complete, deployable snapshot of your environment.
Your Machine dot-man Repo Any Machine
────────────── ──────────── ───────────
~/.bashrc ──── save ──► branch: main ── deploy ──► ~/.bashrc
~/.config/nvim ──── save ──► branch: work ── deploy ──► ~/.config/nvim
~/.gitconfig ──── save ──► branch: server ~/.gitconfig
Secrets are never committed. API keys, tokens and passwords are automatically detected, encrypted locally in a vault, and replaced with hashes in the repository before any commit.
Features
|
Core
|
Advanced
|
Developer
|
Installation
From PyPI (recommended)
pip install dotman-git
Shell completions are installed automatically on first run.
With pipx (isolated)
pipx install dotman-git
From source
git clone https://github.com/BeshoyEhab/dot-man.git
cd dot-man
pip install .
Verify
dot-man --version
Quick Start
# 1. Initialize — runs an interactive wizard that auto-detects your dotfiles
dot-man init
# 2. Add files manually if needed
dot-man add ~/.bashrc
dot-man add ~/.config/nvim
# 3. Create a "work" profile (branch)
dot-man navigate work
# btw it was "switch" instead of "navigate" untill Bishoy decided to change it to "navigate" for some silly reasons and push that changes so as community help us to make it "switch" again.
# 4. Edit your work-specific configs, then switch back — changes are saved automatically
dot-man navigate main
# 5. See what's changed
dot-man status
dot-man diff
How Branching Works
Each branch is an independent configuration. Switching branches runs three phases automatically:
dot-man navigate work
│
├─► Phase 1: Save — copies your files into the repo and commits
├─► Phase 2: Switch — git checkout work
└─► Phase 3: Deploy — copies repo files back to your home directory
| Branch | Purpose |
|---|---|
main |
Personal daily driver |
work |
Office: proxy, work aliases |
server |
Minimal: headless, no GUI tools |
laptop |
Mobile: battery saving, HiDPI |
Commands
Navigation
| Command | Description |
|---|---|
dot-man navigate <target> |
Switch to branch, tag, or commit |
dot-man navigate work --preview |
Preview what will change |
dot-man navigate work --preview --diff |
Full diff before switching |
dot-man navigate work --no-save |
Discard local changes and switch |
dot-man navigate v1.0 |
Jump to a tag |
dot-man navigate abc1234 |
Checkout a specific commit |
Files & Tracking
| Command | Description |
|---|---|
dot-man init |
Initialize repository with setup wizard |
dot-man add <path> |
Track a file or directory |
dot-man status |
Show tracked files and their state |
dot-man status --secrets |
Highlight files containing secrets |
dot-man diff |
Show uncommitted changes |
dot-man diff --branch main |
Compare current branch to main |
dot-man diff --rich |
Syntax-highlighted diff |
dot-man revert <file> |
Restore file from repo |
dot-man revert <file> -c abc123 |
Restore from specific commit |
dot-man watch |
Auto-save tracked files on change |
dot-man watch --no-commit |
Watch and save without committing |
History & Tags
| Command | Description |
|---|---|
dot-man log |
Show commit history |
dot-man log --diff |
History with diffs |
dot-man log --interactive |
TUI log browser |
dot-man show <commit> |
Full diff for a commit |
dot-man tag create v1.0 |
Create a tag |
dot-man tag list |
List all tags |
dot-man tag switch v1.0 |
Checkout a tag |
dot-man rollback |
Roll back to previous commit |
dot-man rollback -n 3 |
Roll back 3 commits |
dot-man rollback --list |
Show available rollback points |
Security
| Command | Description |
|---|---|
dot-man audit |
Scan repo for secrets |
dot-man audit --strict |
Exit non-zero if any secrets found |
dot-man audit --fix |
Auto-redact detected secrets |
dot-man encrypt encrypt <section> |
Encrypt a section with GPG/AGE |
dot-man encrypt status |
Show encryption status |
Import / Export / Discovery
| Command | Description |
|---|---|
dot-man discover |
Auto-detect existing dotfiles |
dot-man discover --add |
Add detected configs automatically |
dot-man import chezmoi |
Import from chezmoi |
dot-man import yadm |
Import from yadm |
dot-man import stow |
Import from GNU Stow |
dot-man export tar backup.tar.gz |
Export to tar archive |
dot-man export zip dots.zip |
Export to zip |
dot-man export json manifest.json |
Export to JSON manifest |
Sync & Remote
| Command | Description |
|---|---|
dot-man sync |
Push + pull with remote |
dot-man sync --push-only |
Only push |
dot-man sync --pull-only |
Only pull |
dot-man remote set <url> |
Set remote URL |
dot-man setup |
Guided GitHub remote setup |
Diagnostics
| Command | Description |
|---|---|
dot-man doctor |
Run health checks |
dot-man verify |
Validate repo integrity |
dot-man backup create |
Create a manual backup |
dot-man backup restore <id> |
Restore from backup |
Configuration
Configuration lives in ~/.config/dot-man/repo/dot-man.toml and is tracked per branch — different branches can track different files.
TOML (default)
# Simple file tracking
[bashrc]
paths = ["~/.bashrc"]
post_deploy = "shell_reload"
# Directory with exclusions
[nvim]
paths = ["~/.config/nvim"]
exclude = ["*.log", "plugin/packer_compiled.lua"]
post_deploy = "nvim_sync"
# SSH config with secret filtering
[ssh-config]
paths = ["~/.ssh/config"]
secrets_filter = true
update_strategy = "rename_old"
# Hyprland with notification on deploy
[hyprland]
paths = ["~/.config/hypr"]
post_deploy = "hyprland_reload"
YAML (also supported)
bashrc:
paths:
- ~/.bashrc
post_deploy: shell_reload
nvim:
paths:
- ~/.config/nvim
exclude:
- "*.log"
post_deploy: nvim_sync
Hook Aliases
Instead of writing full shell commands, use built-in aliases:
| Alias | Runs |
|---|---|
shell_reload |
source ~/.bashrc || source ~/.zshrc |
nvim_sync |
nvim --headless +PackerSync +qa |
hyprland_reload |
hyprctl reload |
fish_reload |
source ~/.config/fish/config.fish |
tmux_reload |
tmux source-file ~/.tmux.conf |
kitty_reload |
killall -SIGUSR1 kitty |
Update Strategies
| Strategy | Behaviour |
|---|---|
replace |
Overwrite existing files (default) |
rename_old |
Back up existing file before overwriting |
ignore |
Skip if file already exists |
Templates & Inheritance
# Define reusable templates
[templates.linux-desktop]
post_deploy = "notify-send 'Config updated'"
update_strategy = "rename_old"
# Inherit in sections
[hyprland]
paths = ["~/.config/hypr"]
inherits = ["linux-desktop"]
[waybar]
paths = ["~/.config/waybar"]
inherits = ["linux-desktop"]
Environment Variable Expansion
[work-files]
paths = ["$WORK_DIR/config", "~/$USER/.config/app"]
Secret Detection
Before any file enters the repository, dot-man scans it for secrets. Detected values are encrypted locally and replaced with a hash placeholder in the repo.
| Pattern | Severity | Example |
|---|---|---|
| Private keys | 🔴 CRITICAL | -----BEGIN RSA PRIVATE KEY----- |
| AWS credentials | 🔴 CRITICAL | AKIA... |
| GitHub tokens | 🟠 HIGH | ghp_xxxx |
| API keys | 🟠 HIGH | api_key = "sk-..." |
| Passwords | 🟠 HIGH | password = "hunter2" |
| JWT tokens | 🟡 MEDIUM | eyJ... |
repo file: api_key = "***REDACTED:e3b0c44298...***"
vault: { encrypted: "gAAAAABk..." } ← Fernet AES-128
system file: api_key = "sk-abc123..." ← restored on deploy
Run dot-man audit to scan at any time. Use dot-man audit --strict in CI/CD pipelines.
Multi-Machine Profiles
Profiles let you auto-select the right branch based on hostname:
dot-man profile create work-laptop -h work-laptop -h thinkpad
dot-man profile set-branch work-laptop work
dot-man profile detect # auto-switches to the right profile
Template Variables
Use {{VARIABLE}} placeholders in your dotfiles that get substituted on deploy:
dot-man template set EMAIL john@work.com
dot-man template set HOSTNAME work-laptop
Then in your ~/.gitconfig:
[user]
email = {{EMAIL}}
name = John Doe
System variables ({{HOSTNAME}}, {{USER}}, {{SHELL}}, etc.) are auto-populated.
Project Status
| Metric | Value |
|---|---|
| Version | 1.1.0 |
| Python | 3.9+ |
| Platforms | Linux, macOS |
| Test Coverage | 61% |
| Commands | 30+ |
| PyPI | dotman-git |
Development
git clone https://github.com/BeshoyEhab/dot-man.git
cd dot-man
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run full quality gate
black dot_man/ tests/
ruff check dot_man/ tests/
mypy dot_man/ --ignore-missing-imports
pytest tests/ --cov=dot_man --cov-report=term-missing
See CONTRIBUTING.md and DEVELOPMENT.md for full guides.
Roadmap
- 80%+ test coverage
- Full documentation site (mkdocs)
- Symlink mode
-
dot-man watch— auto-sync on file change - Deploy rollback (transaction-style)
- Plugin system
See docs/roadmap.md for the full roadmap.
Contributing
Pull requests are welcome. Please read CONTRIBUTING.md first.
All contributions must pass the pre-push quality checklist: black, ruff, mypy, and all tests.
License
MIT © Bishoy Ehab & ZVAXEROWS
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dotman_git-1.1.1.tar.gz.
File metadata
- Download URL: dotman_git-1.1.1.tar.gz
- Upload date:
- Size: 195.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a9250e82494384794fc762c63c10d7d8b180100ce15840c294b0e3824898883
|
|
| MD5 |
e003e51b4bd6df4424d9bbb3ca514bf6
|
|
| BLAKE2b-256 |
630da925fed70f073709a090fd3ff1b816ac334e8c3da2156ae5da9c02fb818f
|
Provenance
The following attestation bundles were made for dotman_git-1.1.1.tar.gz:
Publisher:
publish.yml on BeshoyEhab/dot-man
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dotman_git-1.1.1.tar.gz -
Subject digest:
3a9250e82494384794fc762c63c10d7d8b180100ce15840c294b0e3824898883 - Sigstore transparency entry: 1565037391
- Sigstore integration time:
-
Permalink:
BeshoyEhab/dot-man@a2d6ad2e774114fa632d5ebf4ded9ceca0717a61 -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/BeshoyEhab
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a2d6ad2e774114fa632d5ebf4ded9ceca0717a61 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dotman_git-1.1.1-py3-none-any.whl.
File metadata
- Download URL: dotman_git-1.1.1-py3-none-any.whl
- Upload date:
- Size: 158.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
538f2cbf44c4ce041532c9c605d7926a24e1694c0e15b1439f6f93820c77fe0d
|
|
| MD5 |
1a04113445ac3272b0b35acfb5ded03d
|
|
| BLAKE2b-256 |
505d6e52af80241708d62f3275e8b18298e4fef896bba74ac2ead1f2d2cbe969
|
Provenance
The following attestation bundles were made for dotman_git-1.1.1-py3-none-any.whl:
Publisher:
publish.yml on BeshoyEhab/dot-man
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dotman_git-1.1.1-py3-none-any.whl -
Subject digest:
538f2cbf44c4ce041532c9c605d7926a24e1694c0e15b1439f6f93820c77fe0d - Sigstore transparency entry: 1565037424
- Sigstore integration time:
-
Permalink:
BeshoyEhab/dot-man@a2d6ad2e774114fa632d5ebf4ded9ceca0717a61 -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/BeshoyEhab
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a2d6ad2e774114fa632d5ebf4ded9ceca0717a61 -
Trigger Event:
push
-
Statement type: