Git Account Switcher
A Python CLI tool to easily switch between multiple Git SSH accounts. Manage multiple Git accounts with separate SSH keys and switch between them seamlessly.
Features
- Manage multiple Git accounts with separate SSH keys
- Switch between accounts easily — one command, no fuss
- Generate SSH keys automatically (rsa, ed25519, ecdsa, and more)
- Optional passphrase support for SSH keys
- Opt-in SSH commit signing per account
- Colored terminal output with active account indicator
- Pre-commit hook to prevent commits with the wrong account
- Opt-in directory-based auto-switching (
gitacc rule) with a bash/zsh shell hook - Per-account SSH config
Hostaliases (gitacc alias) forgit@<alias>:org/repoclone URLs - Shell autocomplete for bash and zsh
- Cross-platform support (Linux / macOS)
Installation
pip install gitacc-switcher
From source
git clone https://github.com/ktechhub/gitacc_switcher.git
cd gitacc_switcher
pip install .
Quick start
# 1. Add your accounts
gitacc add # prompts for name, email, optional passphrase
gitacc add --type ed25519 # specify key type
# 2. Switch between them
gitacc switch work # full form
gitacc work # shorthand — same thing
gitacc switch work --local # only this repo, leave the global identity alone
# 3. See what's registered (active account is marked with *)
gitacc list
# 4. Prevent wrong-account commits in a repo
gitacc init work # sets expected account + installs pre-commit hook
gitacc verify # manual check
Commands
gitacc add [--type TYPE] [--sign]
Add a new Git account. Prompts for:
- Account identifier (used in key filename and as a reference)
- Git display name (defaults to account identifier)
- Optional SSH key passphrase
Available key types: rsa (default), ed25519, ecdsa, ecdsa-sk, ed25519-sk, dsa
gitacc add
gitacc add --type ed25519
gitacc add --sign # opt in to SSH commit signing for this account
Pass --sign to opt this account into SSH commit signing. When you later gitacc switch to it,
user.signingkey is set to the account's public key and gpg.format=ssh / commit.gpgsign=true
are enabled (locally too, with --local), so every commit made under this identity is signed.
Switching to an account without --sign clears any signing config left by a previous account.
Toggle it later with gitacc update <account> --sign / --no-sign.
gitacc switch <account> [--local] / gitacc <account>
Switch to a registered account. Clears all keys from the SSH agent, loads only this account's key, and sets git config --global user.name/email.
gitacc switch mywork
gitacc mywork # shorthand
Pass --local/-l to set the identity for the current repository only (git config local scope), leaving the global user.name/user.email untouched. Must be run from inside a Git repository.
gitacc switch mywork --local
The SSH agent must already be running (
eval $(ssh-agent)). If it isn't, gitacc will tell you.
gitacc list
List all registered accounts. The currently active account (matching global git config) is marked with *.
gitacc list
# Registered accounts:
# * work → Git name: Jane Doe (jane@company.com) (active)
# - personal (jane@personal.com)
gitacc remove [account]
Remove an account and its SSH keys. Prompts for confirmation.
gitacc remove mywork
gitacc remove # prompts for account name
gitacc update <account> [--name NAME] [--email EMAIL] [--sign | --no-sign]
Update the Git display name and/or email for an existing account. Prompts for any field not provided as a flag.
gitacc update mywork --name "Jane Doe"
gitacc update mywork --email "jane@newcompany.com"
gitacc update mywork # prompts for both
gitacc update mywork --sign # enable SSH commit signing for this account
gitacc update mywork --no-sign # disable it
gitacc init <account>
Bind the current repository to an account and install a pre-commit hook. Any commit attempt with a mismatched account will be blocked.
cd ~/projects/work-repo
gitacc init mywork
gitacc verify
Check whether the current Git identity matches the account expected by this repository.
gitacc verify
gitacc logout
Kill the SSH agent and unset the global Git user config.
gitacc logout
gitacc rule add <account> [directory] / gitacc rule remove [directory] / gitacc rule list
Opt-in, direnv-style directory-based auto-switching: bind an account to a directory (and
everything beneath it) so the right identity is picked automatically as you move around, instead
of running gitacc switch by hand. directory defaults to the current directory. The most
specific matching directory wins, so a rule on a subdirectory overrides one on its parent.
gitacc rule add work ~/projects/work # anything under ~/projects/work uses "work"
gitacc rule add personal ~/projects/side # anything under ~/projects/side uses "personal"
gitacc rule list
gitacc rule remove ~/projects/side
Rules by themselves don't do anything — nothing triggers on cd until you install the shell hook
below.
gitacc rule hook <bash|zsh>
Print a shell snippet that calls gitacc rule check so rules apply automatically. Add it to your
shell profile and restart your shell (or source it):
# bash
gitacc rule hook bash >> ~/.bashrc
# zsh
gitacc rule hook zsh >> ~/.zshrc
The hook is silent unless it actually needs to switch accounts: no matching rule, an SSH agent
that isn't running, or an identity that's already correct all do nothing. This is entirely
opt-in — gitacc rule add alone never touches your shell config.
gitacc alias add <account> <host-alias> [--hostname HOSTNAME] [--user USER] / gitacc alias remove <host-alias> / gitacc alias list
Bind an SSH config Host alias to an account's key by writing a clearly delimited, safely
add/updatable/removable block to ~/.ssh/config. This lets you clone/push via a per-account host
alias (e.g. git@github-work:org/repo) without hand-editing your SSH config, and without the
account's key needing to be loaded into the SSH agent at all.
gitacc alias add work github-work # git@github-work:org/repo uses "work"'s key
gitacc alias add personal github-personal --hostname github.com
gitacc alias list
gitacc alias remove github-work
--hostname defaults to github.com and --user defaults to git. Running alias add again
for the same alias updates it in place; everything else already in ~/.ssh/config (including
aliases for other accounts) is left untouched.
# clone using the "work" account's key, without ever switching the active identity
git clone git@github-work:myorg/myrepo.git
gitacc autocomplete install
Install tab-completion for your shell (bash or zsh). After running, restart your shell or source your profile.
gitacc autocomplete install
Completions cover: all command names, account names (for switch, remove, init, update), and key types (for add --type).
gitacc --version
gitacc --version
# gitacc 0.1.0
How pre-commit validation works
gitacc init myworkstoresgitacc.expected-account = myworkin the repo's local git config and writes a pre-commit hook.- On every
git commit, the hook reads~/.gitaccand compares the expected account's name/email against the currentgit config user.*. - If they don't match, the commit is blocked with a helpful message pointing to
gitacc switch.
File layout
| Path | Purpose |
|---|---|
~/.gitacc |
Stores all account entries (INI format) |
~/.gitaccrules |
Directory → account rules for gitacc rule (opt-in auto-switch) |
~/.ssh/id_<type>_<account> |
Private SSH key per account |
~/.ssh/id_<type>_<account>.pub |
Public SSH key per account |
~/.ssh/config |
Holds gitacc-managed Host alias blocks (gitacc alias), clearly delimited from any other entries |
~/.gitacc format:
[mywork]
name = Jane Doe
email = jane@company.com
private_key = /home/jane/.ssh/id_ed25519_mywork
public_key = /home/jane/.ssh/id_ed25519_mywork.pub
sign = false
~/.gitaccrules format (one rule per line, most-specific directory wins):
/home/jane/projects/work = work
/home/jane/projects/work/client-a = client-a
Requirements
- Python 3.8+
- Git
- SSH tools (
ssh-keygen,ssh-agent,ssh-add) inPATH
Changelog
See CHANGELOG.md for a full history of changes.
Versions and the changelog are generated automatically by Release Please from Conventional Commit PR titles on main — feat: bumps minor, everything else bumps patch, and ! after the type (e.g. feat!:) bumps major. See CONTRIBUTING.md for the full commit/branch convention.
Contributing
See CONTRIBUTING.md for setup instructions, commit conventions, and the PR process.
License
MIT — see LICENSE for details.
Metadata
Release files for gitacc-switcher 1.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| gitacc_switcher-1.7.0.tar.gz | 48.4 kB | Without provenance | Details for gitacc_switcher-1.7.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| gitacc_switcher-1.7.0-py3-none-any.whl | Python 3 | none | any | Details for gitacc_switcher-1.7.0-py3-none-any.whl |
Total release size: 99.8 kB
Release files / gitacc_switcher-1.7.0.tar.gz
| Download URL | gitacc_switcher-1.7.0.tar.gz |
|---|---|
| Size | 48.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8aee6cb14145eb7d6ea876c3c4f981b3b80aa6667d83d153849a6de71ff0adf3
|
|
BLAKE2b-256 checksum How to use checksums |
3c25c59d9a67f9d0122e8557977408d405a052f160730e50bd2a3571a42d0da6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Release files / gitacc_switcher-1.7.0-py3-none-any.whl
| Download URL | gitacc_switcher-1.7.0-py3-none-any.whl |
|---|---|
| Size | 51.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c47caed437b7235f05409fca805d7b5103f80b4d8716bd1554eb1dd19e8ef79c
|
|
BLAKE2b-256 checksum How to use checksums |
7475c0d2e66eb2a40c9c67f1230e1d161a75c35dbb569cf30befd4bb17bc823a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Security for gitacc-switcher 1.7.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.