Personal configuration for zsh, bash, git, ssh, Emacs and iTerm2, used on macOS and Linux.
| Module | Links into $HOME |
|---|---|
zsh |
.zprofile, .zshrc, .zlogout |
bash |
.bash_profile, .bashrc, .bash_logout |
zsh/bash (shared) |
.profile, .aliases, .inputrc, .condarc |
git |
.gitconfig, .gitmessage |
ssh |
.ssh/config |
emacs |
.emacs.d |
iterm2 (macOS) |
Library/Application Support/iTerm2/DynamicProfiles/dotfiles.json, .config/iterm2/themes |
Every module also links the checkout itself as ~/.dotfiles; the shell, git and Emacs files refer to that path.
git clone https://github.com/Zaryob/dotfiles.git
cd dotfiles
sh install.sh --dry-run zsh bash git ssh emacs
sh install.sh --apply zsh bash git ssh emacsThe installer defaults to a dry run and only creates symbolic links. It installs no packages and runs no network commands.
Existing files are moved to ~/.dotfiles-backups/<UTC timestamp>-<pid>/ before being replaced. Files from older setups that would interfere are moved there too, with no replacement: .gitbin, .config/git/ignore, .emacs, .emacs.el, .spacemacs, .spacemacs.env. Existing .zshenv settings are preserved so non-interactive shells keep their environment. Nothing is deleted. To undo, remove the link and move the saved file back.
Before switching an existing machine, merge its private SSH host definitions into ~/.ssh/config.local, and retain machine-specific Git and shell settings in the local files below. Backups preserve the old files, but only these local files keep their settings active after installation.
To try the result in isolation, pass --target /some/empty/dir.
sh install.sh --dry-run zsh bash iterm2
sh install.sh --apply zsh bash iterm2iTerm2 gains Dotfiles Zsh Night/Day and Dotfiles Bash Night/Day login
profiles with matching dark/light themes. Select them in iTerm2's Profiles menu.
Use iterm-profile day / iterm-profile night to switch the current tab,
or iterm-profile for a selector.
Existing profiles are retained. Native .itermcolors presets can also be
imported into other profiles; see iTerm2 setup.
In either shell, use prompt for an interactive selector, prompt simple for
one line, or prompt extended for two lines. The choice is remembered across
Bash/Zsh sessions; prompt --session simple changes only the current session.
Both layouts show ! unstaged, + staged, ? untracked, ✖ conflicts,
↓ commits to pull and ↑ commits to push. Counts use cached upstream refs
without accessing the network. See prompt options and examples.
macOS (Homebrew):
brew install git gnupg emacs llvm cmake ninja fzf ripgrepDebian/Ubuntu:
sudo apt install zsh git gnupg emacs clangd cmake ninja-build lldb gdb fzf ripgrep build-essentialLanguage servers for Emacs:
- Python:
pipx install basedpyright - Rust:
rustup component add rust-analyzer
Emacs 31 builds tree-sitter grammars on first use and asks first. This needs git and a C compiler. Emacs 30 (for example Debian stable) can't do this automatically: run M-x dotfiles-install-grammars once and restart. Until then, files open in the classic modes.
shell/env.shis shared by sh, bash and zsh. It sets up Homebrew (/opt/homebrew,/usr/localor Linuxbrew), cargo, the Android SDK,~/.local/bin, the git commands below, andEDITOR(emacsclient, falling back to vim).shell/functions.shholds the Docker shortcuts, Git/Conda utilities andconda_init.conda_initloads~/miniconda3,~/miniforge3,~/anaconda3or a Homebrew cask install, whichever exists.shell/prompt.shis the shared Bash/Zsh renderer, Git status helper and persistentpromptselector.shell/iterm2.shswitches the current tab's iTerm2 profile withiterm-profile.terminal/iterm2/contains Night/Day color palettes, native themes and Bash/Zsh login profiles.git/commands/addsgit browse,git license,git getb,git statsand more. Their man pages are ingit/share/man.editors/emacs/containsearly-init.el,init.elandlisp/init-*.el:- completion: vertico, orderless, marginalia, consult, corfu
- languages: eglot with tree-sitter modes for C/C++, Python and Rust
- C++: clangd, CMake targets, CTest, snippets and Dape debugging; see the C++ workflow and keys
- git: magit, diff-hl
- projects: Projectile and Treemacs, with an
M-mleader menu and a Magit branch/commit graph; see the project and Git keys - Packages, grammars and caches are written next to the configuration and ignored by git.
Bash and zsh load a shared docker() function with Git-style subcommand shortcuts:
| Shortcut | Expands to |
|---|---|
docker cu |
docker compose up -d |
docker cub |
docker compose up -d --build |
docker cd |
docker compose down |
docker cl |
docker compose logs -f --tail=100 |
docker ce |
docker compose exec |
docker cr |
docker compose run --rm |
Arguments after the shortcut are passed through, so docker cl api follows the
api service logs and docker ce api sh opens a shell in that service. Leading
Docker options are preserved: docker --context remote cu api runs
docker --context remote compose up -d api. Short forms such as -cremote and
grouped options such as -Dc remote also work.
Native commands, leading help/version flags and unrecognized leading options are
forwarded unchanged. Use command docker to bypass the shortcuts. They apply
to interactive Bash and zsh sessions; they require Docker with Compose installed.
These files are read if they exist and are never tracked:
| File | Used for |
|---|---|
~/.zshrc.local, ~/.bashrc.local |
extra shell settings |
~/.gitconfig.local |
for example gpg.program or a work identity |
~/.ssh/config.local |
private hosts (read before the shared settings) |
~/.emacs.d/local.el |
extra Emacs settings |
- Install the
emacsmodule. It moves~/.emacs.d,~/.spacemacsand~/.spacemacs.envinto the backup directory. - Install the
zshmodule, then open a new terminal. oh-my-zsh is no longer loaded. Once you are happy with the new setup, delete~/.oh-my-zshyourself. - Old completion dumps (
~/.zcompdump*) can be deleted. The new one lives in~/.cache/zsh/.
sh tests/install_test.sh
sh tests/docker_test.sh
sh tests/prompt_test.sh
python3 tests/prompt_pty_test.py
python3 tests/iterm2_test.py
python3 tests/iterm_profile_test.py
sh tests/emacs_test.sh
sh tests/emacs_cpp_test.sh
sh tests/emacs_project_test.sh
sh tests/emacs_build_test.shThe installer test runs against a temporary directory and never touches $HOME.
The Docker test checks argument forwarding and exit statuses in Bash and zsh
using a temporary fake executable; it requires no Docker installation or daemon.
The Emacs tests use isolated configuration state and require Emacs 30+.
The C++ integration checks also use temporary CMake projects and require CMake
and a C++ compiler.
The project suite also needs the configured Emacs packages installed; it uses
temporary projects and a temporary branching Git repository.