Add git-identity: switch git author identity from a saved menu
Identities live in ~/.git-identities (alias|Name|email). Interactive menu to select, add, or remove identities; direct mode via alias argument; --global/-g scope flag (defaults to local inside a repo, global fallback outside); --list/--current helpers. Full --dryrun support and a 27-assertion test suite driven through dryrun. GIT_IDENTITIES_FILE env override for testability.
This commit is contained in:
102
specs/git-identity.spec.md
Normal file
102
specs/git-identity.spec.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# 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 <paul@example.net>
|
||||
|
||||
1) personal Paul Example <paul@example.net>
|
||||
2) work Paul Example <paul.example@corp.com>
|
||||
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 <paul@example.net>
|
||||
work Paul Example <paul.example@corp.com>
|
||||
```
|
||||
Reference in New Issue
Block a user