Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/deploy.yml → .github/workflows/link.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ on:
- main
pull_request:
jobs:
deploy:
link:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.9"
- name: Deploy
run: make deploy
- name: Verify symlinks exist (re-deploy should fail)
run: "! make deploy"
- name: Link
run: make link
- name: Verify symlinks exist (re-link should fail)
run: "! make link"
- name: Unlink
run: make unlink
- name: Verify unlink (deploy again should succeed)
run: make deploy
- name: Verify unlink (link again should succeed)
run: make link
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ else
NIX_SWITCH_CMD := sudo nixos-rebuild switch --flake .\#nixos
endif

.PHONY: build switch update gc brew brew-base brew-gui brew-himkt deploy unlink
.PHONY: build switch update gc brew brew-base brew-gui brew-himkt link unlink

# Nix targets (platform-aware)
build:
Expand Down Expand Up @@ -37,9 +37,9 @@ brew-gui:
brew-himkt:
brew bundle --verbose --file=$(PWD)/brew/config.d/himkt/Brewfile

deploy:
python3 bin/deploy.py --dry-run
python3 bin/deploy.py
link:
python3 bin/link.py --dry-run
python3 bin/link.py

unlink:
python3 bin/deploy.py --unlink
python3 bin/link.py --unlink
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Unified Nix-based configuration for macOS (nix-darwin) and NixOS.
```
dotfiles/
├── flake.nix # Unified flake (NixOS + nix-darwin)
├── Makefile # Build and deploy targets
├── bin/ # deploy.py — working-tree symlink deployer
├── Makefile # Build and link targets
├── bin/ # link.py — creates working-tree symlinks
├── nix/ # All Nix-managed system + Home Manager config
│ ├── hosts/
│ │ ├── nixos/ # NixOS system configuration
Expand Down Expand Up @@ -43,9 +43,9 @@ dotfiles/
```
make switch
```
4. Deploy dotfiles as working-tree symlinks:
4. Link dotfiles as working-tree symlinks:
```
make deploy
make link
```
5. Install Homebrew packages:
```
Expand All @@ -60,14 +60,14 @@ dotfiles/
```
make switch
```
3. Deploy dotfiles as working-tree symlinks:
3. Link dotfiles as working-tree symlinks:
```
make deploy
make link
```

> **Dotfiles deployment.** `make switch` manages packages and system settings only. Configuration files (git, mise, nvim, tmux, uv, ghostty, sheldon, zsh, and `~/.claude`) are deployed separately by `make deploy`, which symlinks them directly to the working tree so edits take effect immediately without a rebuild.
> **Dotfiles linking.** `make switch` manages packages and system settings only. Configuration files (git, mise, nvim, tmux, uv, ghostty, sheldon, zsh, and `~/.claude`) are linked separately by `make link`, which symlinks them directly to the working tree so edits take effect immediately without a rebuild.
>
> **Migrating an existing machine.** If these files were previously managed by Home Manager (symlinks into `/nix/store`), run `make switch` first — Home Manager removes the old store symlinks on activation — then `make deploy`. `deploy` is strict: it aborts if a destination already exists. Resolve any reported conflicts and re-run. Use `make unlink` to remove the symlinks.
> **Migrating an existing machine.** If these files were previously managed by Home Manager (symlinks into `/nix/store`), run `make switch` first — Home Manager removes the old store symlinks on activation — then `make link`. `link` is strict: it aborts if a destination already exists. Resolve any reported conflicts and re-run. Use `make unlink` to remove the symlinks.
Comment on lines +68 to +70

## Makefile Targets

Expand All @@ -77,8 +77,8 @@ All Nix targets automatically detect the platform (macOS / NixOS) and run the ap
|--------|-------------|
| `build` | Build system configuration (dry run) |
| `switch` | Apply system + Home Manager configuration |
| `deploy` | Deploy dotfiles as working-tree symlinks (run after `switch`) |
| `unlink` | Remove the dotfile symlinks created by `deploy` |
| `link` | Link dotfiles as working-tree symlinks (run after `switch`) |
| `unlink` | Remove the dotfile symlinks created by `link` |
| `update` | Update flake inputs |
| `gc` | Delete old generations (keep last 7) and run garbage collection |
| `brew-install` | Install Homebrew |
Comment on lines +80 to 84
Expand Down
12 changes: 6 additions & 6 deletions bin/deploy.py → bin/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import sys
from pathlib import Path

DEPLOY_MAP = [
LINK_MAP = [
("claude", ".claude"),
("git", ".config/git"),
("ghostty", ".config/ghostty"),
Expand All @@ -26,7 +26,7 @@ def get_repo_root() -> Path:

def expand_map(repo_root: Path, home: Path) -> list[tuple[Path, Path]]:
pairs = []
for source, dest in DEPLOY_MAP:
for source, dest in LINK_MAP:
src = repo_root / source
if src.is_dir():
for dirpath, _, filenames in os.walk(src):
Expand Down Expand Up @@ -54,12 +54,12 @@ def preflight_check(pairs: list[tuple[Path, Path]]) -> list[str]:
return conflicts


def deploy(pairs: list[tuple[Path, Path]], dry_run: bool) -> None:
def link(pairs: list[tuple[Path, Path]], dry_run: bool) -> None:
for src, dest in pairs:
print(f"LINK {dest} -> {src}")

if conflicts := preflight_check(pairs):
print("\nERROR: Cannot deploy. The following conflicts were found:\n")
print("\nERROR: Cannot link. The following conflicts were found:\n")
print("\n".join(conflicts))
sys.exit("\nResolve these conflicts manually, then re-run.")

Expand Down Expand Up @@ -94,7 +94,7 @@ def unlink(pairs: list[tuple[Path, Path]], home: Path, dry_run: bool) -> None:


def main() -> None:
parser = argparse.ArgumentParser(description="Deploy dotfiles via symlinks into the working tree.")
parser = argparse.ArgumentParser(description="Link dotfiles via symlinks into the working tree.")
parser.add_argument("--unlink", action="store_true", help="Remove symlinks created by this script")
parser.add_argument("--dry-run", action="store_true", help="Show what would be done without making changes")
args = parser.parse_args()
Expand All @@ -106,7 +106,7 @@ def main() -> None:
if args.unlink:
unlink(pairs, home, args.dry_run)
else:
deploy(pairs, args.dry_run)
link(pairs, args.dry_run)


if __name__ == "__main__":
Expand Down