Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 

Repository files navigation

packer

A lightweight shell tool to back up and restore your macOS development environment — dotfiles and Homebrew packages — with support for layered profiles.

Why

Setting up a new Mac means reinstalling apps, copying config files, and remembering what you had. Packer solves this with a single command to snapshot your setup and another to restore it. Profiles let you separate personal configs from work-specific ones and selectively apply what you need.

How It Works

Packer uses a copy-based sync strategy. backup copies files from your home directory into the data repo. restore copies them back. No symlinks, no magic — just rsync.

The tool itself (packer script) is separate from your data (~/.packer-data/), so you can version-control them independently.

Architecture

<tool-repo>/                 # Tool repo — just the script
└── packer

~/.packer-data/                   # Data repo — your configs and Brewfiles
├── base/                    # Shared across all machines
│   ├── packer.conf          # List of dotfile paths to track
│   ├── Brewfile             # Homebrew packages
│   └── dotfiles/            # Backed-up config files
│       ├── .zshrc
│       ├── .gitconfig
│       ├── .config/nvim/
│       └── ...
├── work/                    # Company-specific overrides
│   ├── packer.conf
│   ├── Brewfile
│   └── dotfiles/
└── personal/                # Personal machine extras
    ├── packer.conf
    ├── Brewfile
    └── dotfiles/

Quick Start

# 1. Clone or copy the packer script somewhere in your PATH
cp packer /usr/local/bin/  # or add the repo directory to PATH

# 2. Create your first profile
packer init base

# 3. Add dotfiles to track
packer add base .zshrc
packer add base .gitconfig
packer add base .config/nvim
packer add base .ssh/config

# 4. Back up everything
packer backup

# 5. Version-control your data
cd ~/.packer-data && git init && git add -A && git commit -m "Initial backup"

Restoring on a New Machine

# 1. Install Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 2. Clone your data repo
git clone <your-repo-url> ~/.packer-data

# 3. Get the packer script (from your tool repo or copy it)
# 4. Restore
packer restore base          # shared configs + brew packages
packer restore dots work     # overlay work-specific dotfiles

Commands

Backup

packer backup                    # Back up all profiles (dotfiles + Brewfile)
packer backup dots               # All profiles, dotfiles only
packer backup brew               # All profiles, Brewfile only
packer backup base               # Just the base profile
packer backup dots work          # Just work profile dotfiles

Restore

packer restore                   # Restore all profiles (alphabetical order)
packer restore base work         # Restore base, then overlay work
packer restore dots base         # Dotfiles only from base
packer restore brew work         # Install only work's Brewfile packages

When restoring multiple profiles, they are applied in the order specified. Later profiles overwrite earlier ones for overlapping files. This is the layering mechanism — put shared configs in base, machine-specific overrides in work or personal.

Before any restore, packer automatically snapshots your current live files so you can roll back if needed (see Snapshots & Rollback).

Diff

packer diff                      # Show all changes across all profiles
packer diff base                 # Changes in base profile only

Shows a colorized unified diff between backed-up files and their live counterparts in ~.

List

packer list                      # List all tracked paths across all profiles
packer list work                 # List only work profile paths

Shows each tracked path and whether it exists in ~ (HOME) and in the repo (REPO).

Profiles

packer profiles                  # List all profiles with summary
packer init <name>               # Create a new empty profile

Snapshots & Rollback

Every restore dots automatically saves a timestamped snapshot of your current live files to ~/.packer-data/.snapshots/ before overwriting anything.

packer snapshots                 # List all saved snapshots
packer rollback                  # Roll back to the most recent snapshot
packer rollback 20260401-153012  # Roll back to a specific snapshot
packer -n rollback               # Preview what rollback would do

Add / Remove

packer add <profile> <path>      # Start tracking a path
packer remove <profile> <path>   # Stop tracking a path

Paths can be absolute, relative to ~, or use ~ notation:

packer add base .config/ghostty
packer add work ~/.ssh/config
packer add work /Users/$USER/.stCommitMsg

Flags

Flag Description
-f, --force Skip confirmation prompts (useful in scripts)
-n, --dry-run Preview what would happen without making changes
--data-dir <path> Override data directory (default: ~/.packer-data)

The data directory can also be set via the PACKER_DATA_DIR environment variable.

Profile Config Format

Each profile's packer.conf is a simple text file — one path per line, relative to $HOME. Comments start with #.

# Shell
.zshrc
.zprofile
.zshenv

# Git
.gitconfig
.gitignore_global

# Editors
.config/nvim
.config/helix

# Terminals
.config/ghostty
.config/wezterm

Layering Strategy

The recommended setup for a work machine:

Profile Contains
base Editor configs, terminal configs, shell configs, general CLI tools
work Company-specific git config, SSH config, internal brew taps, VPN tools

For a personal machine:

Profile Contains
base Same shared configs
personal Personal git config, personal SSH keys config, hobby project tools

Restore only what you need:

# Work laptop
packer restore base work

# Personal laptop
packer restore base personal

Brewfile Management

Brewfiles are manually curated — packer will not silently overwrite them. This prevents accidental loss of a carefully split Brewfile when running packer backup.

Initial setup

When a profile has no Brewfile yet, packer backup brew generates one by dumping all installed packages. You then edit it to keep only what belongs to that profile.

packer init work
packer backup brew work       # Creates work/Brewfile with full system dump
# Edit ~/.packer-data/work/Brewfile to keep only work-specific packages

If you need to regenerate a Brewfile from scratch (overwrites existing):

packer brew-dump base         # Prompts before overwriting
packer -f brew-dump base      # Force overwrite without prompt

Finding untracked packages

After installing new packages, use brew-diff to see what's not in any Brewfile:

packer brew-diff
# Output:
#   brew "newpackage"
#   cask "newapp"
# Add these to the appropriate profile's Brewfile

Typical split

base/Brewfile — tools you use everywhere:

brew "fzf"
brew "ripgrep"
brew "neovim"
brew "starship"
cask "ghostty"

work/Brewfile — company-specific:

tap "company/internal"
brew "company-cli"
cask "company-vpn"

Dependencies

  • bash (v3.2+ — ships with macOS)
  • rsync (ships with macOS)
  • diff (ships with macOS)
  • brew + brew bundle (for Homebrew sync)

No other dependencies. No Python, no Ruby, no Node.

Tips

  • Run packer -n restore base work before an actual restore to preview what will change
  • Use packer diff after making config changes to see what's drifted since last backup
  • Keep ~/.packer-data as a git repo — commit after each packer backup to maintain history
  • Add alias packer="/path/to/packer" to your .zshrc for convenience
  • .DS_Store files are automatically excluded from all operations

About

A lightweight shell tool to back up and restore your macOS development environment — dotfiles and Homebrew packages — with support for layered profiles.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages