git Provider
Wraps the real git CLI so hams git … behaves exactly like plain git for every subcommand,
with two exceptions that hams records into a Hamsfile: hams git config keys and hams git clone targets. Every other verb (status, pull, push, log, …) passes through unchanged.
Platforms: macOS, Linux
Usage
hams git config — global git config
# Set a value (and record it to the Hamsfile)
hams git config --global user.name "Your Name"
hams git config --global user.email "[email protected]"
# See what's managed
hams git config list
# Unset (drops from Hamsfile, clears on the machine)
hams git config remove rerere.autoUpdatehams git clone — pinned local clones
# Add: clone a remote repo to a local path (matches plain `git clone`)
hams git clone https://github.com/zthxxx/dotfiles ~/Projects/dotfiles
# See what's managed
hams git clone list
# Remove (stops managing; leaves the local files alone)
hams git clone remove urn:hams:git-clone:dotfilesEverything else — plain git, just prefixed
hams git status # → git status
hams git pull # → git pull
hams git log --oneline # → git log --onelinePassthrough preserves stdin / stdout / stderr / exit code, so aliasing git=hams git is safe.
Hamsfile example
git-config and git-clone keep separate Hamsfiles and state files, so you can version-control your identity config and your cloned-repo list independently:
# macOS/git-config.hams.yaml
schema_version: 1
provider: git-config
groups:
- tag: identity
items:
- urn: "urn:hams:git-config:user-name"
step: Set git user name
key: user.name
value: "Your Name"
- urn: "urn:hams:git-config:user-email"
step: Set git user email
key: user.email
value: "[email protected]"
- tag: workflow
items:
- urn: "urn:hams:git-config:rerere"
step: Enable git rerere (remember conflict resolutions)
key: rerere.autoUpdate
value: "true"# macOS/git-clone.hams.yaml
schema_version: 1
provider: git-clone
groups:
- tag: personal
items:
- urn: "urn:hams:git-clone:dotfiles"
step: Clone dotfiles repository
remote: https://github.com/zthxxx/dotfiles.git
local_path: ~/Projects/dotfiles
default_branch: mainFields for git-config:
key/value— exactly thegit configkey and valuestep— a one-line description that shows up in apply logsurn— hams’s internal ID. Keep it readable
Fields for git-clone:
remote— repo URL (HTTPS or SSH, your choice)local_path— local target path,~/is expandeddefault_branch— optional. Checkout to this branch after cloning. If omitted, use the remote default
How state is probed
git-config: for each entry, hams runs git config --global --get <key> and compares to the
Hamsfile value. Match → ok. Different → outdated. Missing → missing.
git-clone: the check is pragmatic:
- Does
local_pathexist? - If so, does
git -C <local_path> remote get-url originmatch the Hamsfileremote? - Both match →
ok.
hams doesn’t pull for you. Auto-pulling every apply would slow things down and occasionally cause conflicts. Deciding when to pull is your call.
go-git, not the system git
The hams binary bundles go-git , so the machine doesn’t need
git installed for clone-based resources to work. That matters during bootstrap: you don’t need
to brew install git before starting an apply.
System vs user scope (git config)
By default, hams writes to --global scope (your user’s ~/.gitconfig). Special cases:
- Repo-scope (
--local) — doesn’t belong in hams at all. That’s per-project config, and it lives with the project. - System-scope (
--system) — use thebashprovider withsudo git config --system ....
SSH authentication (git clone)
For SSH-style remotes ([email protected]:...), hams tries in order:
- Common key paths:
~/.ssh/id_ed25519,~/.ssh/id_rsa, and similar - Keys loaded in a running
ssh-agent - Falls back to interactive prompts if needed
The typical snag on a fresh machine: SSH keys haven’t been set up yet. Two workarounds: use HTTPS
URLs (pair with gh auth login or a PAT), or get SSH keys in place before running apply.
Handy patterns
Separate work and personal identity. git’s includeIf directive loads different configs based
on where the repo sits. hams can manage both the directive and the pointer:
- urn: "urn:hams:git-config:work-includeif"
step: Include work config when under ~/work/
key: 'includeIf."gitdir:~/work/".path'
value: ~/.gitconfig-workGPG signing. The signing key ID is identity-level config, so this is a natural fit:
- urn: "urn:hams:git-config:signing-key"
step: Set GPG signing key
key: user.signingkey
value: "AAAAAAAAAA"
- urn: "urn:hams:git-config:commit-gpgsign"
step: Sign all commits
key: commit.gpgsign
value: "true"Don’t put sensitive values into the committed Hamsfile. Tokens, the GPG key’s private ID,
anything secret — put them in git-config.hams.local.yaml (gitignored) or the system keychain.
hams git clone is for “I need this repo, at this exact path.” If you just want to run a script
once, curl | bash inside a bash provider step is simpler. git-clone earns its weight when
you want hams to keep ensuring the repo exists at the right location.