feat: identity lifecycle commands — list, add, delete, rename#27
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:~/.config/gitswitch/config.jsongitswitch listgitswitch delete <name>init's auto-generated silly namegitswitch rename <old> <new>initmissedgitswitch add <name>What's in the PR
gitswitch listlsgitswitch add <name>new.pubnext to private key for SSH signing.gitswitch delete <name>rm,removegh auth— those aren't gitswitch's to delete.gitswitch rename <old> <new>mvAll four use the existing
internal/blockshelper for~/.gitconfigedits, so block markers stay consistent across operations.Verified
9 end-to-end cases pass against an isolated
$HOME(output captured locally):listrenameretargets bindings (binding for old name now points at new name)deletecascades cleanly: identity gone, binding gone, includeIf block stripped —grep -c gitswitch:returns 0addwith flags creates the identity, suggests the next step (gitswitch use ...)gitswitch listto see what's configured"Out of scope (lower priority lifecycle, can land later)
gitswitch unbind <dir>— today's path isgitswitch use <id> <dir> --unbind, which is awkward but functionalgitswitch show <name>—list+ reading JSON covers the use caseRelease 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
)