Skip to content

feat: identity lifecycle commands — list, add, delete, rename#27

Merged
OfirHaim1 merged 1 commit into
mainfrom
feat/list-and-delete
May 1, 2026
Merged

feat: identity lifecycle commands — list, add, delete, rename#27
OfirHaim1 merged 1 commit into
mainfrom
feat/list-and-delete

Conversation

@OfirHaim1
Copy link
Copy Markdown
Member

UX miss correction. The first cut of v1.x CLI shipped only the five demo-able verbs (init, use, guard, doctor, why) and skipped the lifecycle a real user actually walks through:

The user wants to... Today Now
See what's configured edit ~/.config/gitswitch/config.json gitswitch list
Remove a duplicate / stale identity edit JSON gitswitch delete <name>
Fix init's auto-generated silly name delete and re-add gitswitch rename <old> <new>
Add an identity init missed edit JSON gitswitch add <name>

What's in the PR

Command Aliases What it does
gitswitch list ls Identities table + bindings table, aligned columns
gitswitch add <name> new Manual register — flags or interactive prompts. Auto-detects .pub next to private key for SSH signing.
gitswitch delete <name> rm, remove Confirm-prompted. Strips includeIf block, deletes per-identity gitconfig, retargets / removes bindings. Does NOT touch SSH keys or gh auth — those aren't gitswitch's to delete.
gitswitch rename <old> <new> mv Symmetric: renames in JSON, moves the per-identity gitconfig file, rewrites the sentinel-marked includeIf block, retargets every binding.

All four use the existing internal/blocks helper for ~/.gitconfig edits, so block markers stay consistent across operations.

Verified

9 end-to-end cases pass against an isolated $HOME (output captured locally):

  • duplicates rendered correctly by list
  • rename retargets bindings (binding for old name now points at new name)
  • delete cascades cleanly: identity gone, binding gone, includeIf block stripped — grep -c gitswitch: returns 0
  • add with flags creates the identity, suggests the next step (gitswitch use ...)
  • error paths print "no identity named X — run gitswitch list to see what's configured"

Out of scope (lower priority lifecycle, can land later)

  • gitswitch unbind <dir> — today's path is gitswitch use <id> <dir> --unbind, which is awkward but functional
  • gitswitch show <name>list + reading JSON covers the use case

Release impact

feat: prefix → release-please will auto-bump from v1.0.2 to v1.1.0 when this lands. Pipeline tested in PR #25/#26 — fully automated from this point.

🤖 Generated with Claude Code
EOF
)

UX miss correction. The first cut of the v1.x CLI shipped only the
five demo-able verbs (init, use, guard, doctor, why) and skipped
the lifecycle a real user actually walks through:

  "what do I have configured?"        → no `list`, edit JSON
  "how do I remove a duplicate?"      → no `delete`, edit JSON
  "init named me 'ofirhaim1' — yuck"  → no `rename`, delete and re-add
  "init missed an identity"           → no `add`, edit JSON

This PR ships all four. Each one is symmetric — no orphaned state,
no leftover blocks in ~/.gitconfig after a delete, no stale
references in bindings after a rename.

  gitswitch list      (alias `ls`)
      Identities table + bindings table. Sorted by directory,
      aligned columns. Printed when you forget your identity names.

  gitswitch add <name> [--email ... --ssh-key ... --gh ...]
      (alias `new`) Manually register an identity init didn't
      catch. Interactive prompts for missing fields when not in
      --yes mode. Auto-detects the .pub next to a private key
      for SSH commit signing.

  gitswitch delete <name>           (aliases `rm`, `remove`)
      Confirm-prompted (or --yes for scripts). Removes the
      identity from JSON, retargets / removes any binding
      pointing at it, strips the corresponding includeIf block
      from ~/.gitconfig, deletes the per-identity gitconfig
      file. Does NOT touch SSH keys or `gh auth` — those
      aren't gitswitch's to delete.

  gitswitch rename <old> <new>      (alias `mv`)
      Renames the identity in JSON. Moves
      ~/.config/gitswitch/identities/<old>.gitconfig to <new>.
      Rewrites the includeIf block (the sentinel comments use
      the identity name). Retargets every binding that pointed
      at <old>. Refuses if <new> already exists.

All four use the existing internal/blocks helper for ~/.gitconfig
edits, so block markers stay consistent. The new wiring in
internal/cmd/root.go preserves the original five command order
and tacks the new ones on after — `gitswitch --help` shows them
alphabetically anyway.

Verified end-to-end against an isolated $HOME with 9 cases:
duplicates listed, rename + delete + add cycle, rename retargets
active bindings, delete cascades cleanly (no leftover blocks),
error paths give helpful "run gitswitch list" hints.

Out of scope (lower priority lifecycle commands, can land later):
- `gitswitch unbind <dir>`  (today: `gitswitch use <id> <dir> --unbind`)
- `gitswitch show <name>`   (today: `gitswitch list` + read JSON)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@OfirHaim1 OfirHaim1 merged commit 5fba051 into main May 1, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant