# git-identity ## Purpose Switch the git author identity (user.name + user.email) for the current repo or globally, from a menu of identities saved in `~/.git-identities`. ## Usage ``` git-identity [OPTIONS] [ALIAS] ``` ### Arguments | Argument | Default | Description | |----------|---------|-------------| | `ALIAS` | — | Apply this saved identity directly (non-interactive). Omit for the interactive menu. | ### Flags | Flag | Description | |------|-------------| | `--help`, `-h` | Show usage information | | `--dryrun`, `-n` | Preview all actions without changing config or the identities file | | `--global`, `-g` | Apply to global git config instead of the current repo | | `--list`, `-l` | List saved identities and exit | | `--current`, `-c` | Show the identity in effect for the current directory and exit | ### Environment | Variable | Description | |----------|-------------| | `GIT_IDENTITIES_FILE` | Override the identities file path (default `~/.git-identities`). Used by tests. | ## Identities file format One identity per line: `alias|Name|email`. Blank lines and lines starting with `#` are ignored. ``` # alias|Name|email personal|Paul Example|paul@example.net work|Paul Example|paul.example@corp.com ``` ## Behaviour 1. Determine scope: `--global` → global config; otherwise local config if inside a git repository, else fall back to global (with a note). 2. **Direct mode** (`ALIAS` given): look up the alias in the identities file; apply `git config user.name` + `user.email` in the chosen scope; print confirmation showing scope, name, and email. 3. **Interactive mode** (no alias): print the identity currently in effect, then a numbered menu of saved identities plus a final option `s) Something else...`. - Selecting a number applies that identity (as in direct mode). - `s` opens a submenu: `a) Add identity`, `r) Remove identity`, `q) Cancel`. - **Add**: prompts for alias, name, email; validates alias is unique and contains no `|`; validates email contains `@`; appends to the file; then offers to apply it now. - **Remove**: numbered menu of identities; selected line is deleted from the file. Never touches git config. - `q` or empty input cancels with exit 0. 4. Applying an identity never modifies the identities file; add/remove never modify git config (except the post-add "apply now" offer). ## Dryrun Behaviour Every mutating action prints a `[dryrun]` line instead of acting: - Apply: `[dryrun] Would set user.name 'NAME' and user.email 'EMAIL' (--local in /path/to/repo)` (or `(--global)`) - Add: `[dryrun] Would append 'alias|NAME|EMAIL' to FILE` - Remove: `[dryrun] Would remove identity 'alias' from FILE` Menus and prompts still function in dryrun so a full flow can be rehearsed. ## Edge Cases | Case | Handling | |------|----------| | Identities file missing (interactive) | Offer to create it seeded with the current global identity, then continue to menu | | Identities file missing (direct/`--list`) | Error: "No identities file at FILE (run git-identity to create one)", exit 1 | | Unknown alias in direct mode | Error: "No identity 'ALIAS' in FILE", exit 1; list available aliases | | Empty identities file | Menu shows only "Something else..." | | Duplicate alias on add | Error: "Alias 'X' already exists", re-prompt | | Alias containing `\|` | Error: "Alias must not contain '\|'", re-prompt | | Not in a git repo, no `--global` | Note "not inside a git repository — applying globally", apply to global | | Malformed line in file | Skipped silently (comment/blank handling covers this) | ## Examples ```bash # Interactive menu $ git-identity Current identity (local): Paul Example 1) personal Paul Example 2) work Paul Example s) Something else... Select [1-2/s/q]: 2 Set user.name 'Paul Example' and user.email 'paul.example@corp.com' (--local in /home/paul/dev/myrepo) # Direct, dryrun $ git-identity -n work [dryrun] Would set user.name 'Paul Example' and user.email 'paul.example@corp.com' (--local in /home/paul/dev/myrepo) # List $ git-identity --list personal Paul Example work Paul Example ```