# Git ## Signing uses SSH, not GPG 1Password has no GPG agent and ships only `op-ssh-sign`, so SSH signing is the only thing it can actually do. Git has supported it since 2.34, and `git.nakama.town` (Forgejo 14) verifies it, as do GitHub, GitLab and Bitbucket. The private key never leaves 1Password. Storing a GPG key in 1Password as a Document is possible, but 1Password cannot *serve* it to `gpg` — the key would have to be imported into `~/.gnupg` on every machine, which is exactly what this avoids. Only the public half is committed, in `.chezmoi.toml.tmpl` under `[data.user]`. It feeds both the gitconfig and `allowed_signers`, so rotating the key is a one-line change. ### The signing block is capability-gated `dot_gitconfig.tmpl` emits it only where the signer binary exists — `/opt/1Password/op-ssh-sign` on Linux, `/Applications/1Password.app/Contents/ MacOS/op-ssh-sign` on macOS — checked with `stat` at apply time. A machine with only the 1Password CLI gets a working git with signing off, rather than one that fails on every commit. No per-host declaration to keep in sync. ### allowed_signers `~/.config/git/allowed_signers` is managed so `git log --show-signature` can verify our own commits locally. Without it signing works but every signature reads as an unknown key. ## Registering the key with a forge Adding the key to Forgejo or GitHub requires signing a challenge token with it. The obvious command from their UI assumes a private key on disk, which does not exist here; the key has to come from the agent instead. In fish: ```fish set -l sock $HOME/.1password/agent.sock env SSH_AUTH_SOCK=$sock ssh-add -L | grep 'Git Signing Key' > /tmp/sig.pub echo -n 'TOKEN' | env SSH_AUTH_SOCK=$sock ssh-keygen -Y sign -n git.nakama.town -f /tmp/sig.pub ``` `env` is required because fish has no `VAR=value cmd` form, and `SSH_AUTH_SOCK` is not set anywhere. The `grep` matters — the agent holds more than one key, and an auth key will fail to sign. Change `-n` to match the host asking. The key must be added as a **signing** key, separately from any auth key. ## Credentials `git-credential-op` answers credential queries from 1Password at auth time, so no token is ever written to disk. It is scoped per host via `credential..helper`, and reads whatever `GIT_CREDENTIAL_OP_REF` points at — the script itself never sees a URL. ## Other capability gates Two more blocks follow the same rule as the signing block — emitted only where the binary exists, checked with `lookPath` at apply time. `filter "lfs"` is the dangerous one. Those filters are declared per-repository work that git runs on *every* checkout, so asserting them on a machine without `git-lfs` breaks checkouts wholesale rather than degrading. Gating it means the same gitconfig is safe on a minimal remote box. The GitHub credential helper is emitted with `gh`'s absolute path from `lookPath`, not a hardcoded `/opt/homebrew/bin/gh`, so the same template serves Homebrew on Apple silicon, Homebrew on Intel and a distro package. The empty `helper =` line before it is deliberate: it resets any helper inherited from the system config, so the stack cannot silently fall back to a stale keychain entry. ## Aliases | | | |---|---| | `br` | `branch` | | `cane` | `commit --amend --no-edit` | | `co` | `checkout` | | `d` | `diff` | | `fp` | fetch all remotes with prune, then `pull --ff-only` | | `last` | `log -1 HEAD` | | `lo` | `log --oneline -n 10` | | `pr` | `pull --rebase` | | `s` | `status` | `fp` refuses to merge or rebase a diverged branch, matching `dotfiles update`. ## Work identity When the work laptop arrives, its identity belongs in git's own conditional include, not a new registry field: ```gitconfig [includeIf "gitdir:~/work/"] path = ~/.config/git/config.work ```