Skip to main content

gw

CI PyPI License: MIT

Switch between multiple git/GitHub accounts, per repository, and see which account is active right in your shell prompt.

Install

pipx install gwitch

Published on PyPI as gwitch; installs the gw command. Or, from a checkout of this repository:

pipx install .

Quick start

gw account add personal
gw account add work

cd ~/code/some-repo
gw use personal
gw status

Shell prompt

gw init zsh    # or bash / fish

prints a small shell function, plus a one-line instruction for wiring it into your prompt — paste both into your shell config yourself. gw never edits your shell rc files automatically.

gw init zsh --install    # or bash

--install does the wiring for you, for zsh/bash only (not fish yet): it writes a gw-prompt script to ~/.local/bin/gw-prompt and a gw-check script to ~/.local/bin/gw-check (the cd-triggered account-check described below), and appends two marked blocks to your rc file — one per script. It's idempotent — safe to re-run. Note for macOS bash users: ~/.bashrc isn't read by login shells (Terminal and iTerm start bash as a login shell), so unless you've already wired ~/.bashrc to be sourced from ~/.bash_profile, you'll need to add that yourself for the installed integration to take effect.

What gw use <account> changes

  • user.name / user.email — local to the current repo only (git config --local)
  • core.sshCommand — forces the SSH key registered for that account
  • credential.https://<host>.helper — scoped to this repo and this host, so HTTPS pushes/pulls use this account's token instead of whatever's cached in the OS keychain or gh's globally active account (see below)
  • gw.account — a marker read by gw status and the shell prompt function
  • gw-remote-map.<remote URL>.account — records this repo's remote in global git config, for the cd-triggered mismatch check below

gw use also records this repo's remote-to-account mapping in global git config (for the cd-triggered mismatch check, see below) — everything else stays local-only. None of this touches ~/.ssh/config or ssh-agent.

HTTPS credential support

If a repo's remote uses HTTPS instead of SSH, gw use <account> sets a repo-scoped git credential helper (credential.https://<host>.helper, cleared and reset each time you switch, so it's never a blanket override — only this repo, only this host) that points back at gw credential-helper. When git needs to authenticate an HTTPS push/pull, it invokes that internal command, which looks up the account currently active in this repo and fetches a token for it via gh auth tokengw never stores a credential itself, it just asks gh for the one it already has. This gives an HTTPS remote the same per-repo isolation SSH already had, without a stale token cached by the OS keychain or gh's globally active account silently winning instead.

Requires the gh CLI to be installed and already logged in to the account in question; if it isn't, gw credential-helper produces no output and git falls back to its normal (interactive) credential prompt for that repo, rather than silently reusing a wrong cached credential.

Remote-account mismatch check

With gw init <shell> --install, a gw-check script is wired to run every time your shell cds into a different directory. If the repo you land in has an origin remote that gw use <account> has previously recorded, and the account currently active in that repo doesn't match, it prints a warning to stderr telling you which account to switch to. This cd-triggered check never blocks or changes anything on its own — it's purely informational.

For a blocking version of the same check — useful since the cd-triggered check above only fires in an interactive shell and is invisible to AI coding agents, CI, or any other non-interactive git caller — run gw install-hooks once in a repo. It installs pre-commit/pre-push git hooks that run the same check and, on a real mismatch, reject the commit or push outright (exit 1). The block message always names git's own --no-verify flag as the way to bypass it deliberately. If the repo already has a pre-commit/pre-push hook, gw install-hooks preserves it (renamed to <hookname>.gw-original) and chains to it after its own check passes, rather than overwriting it.

Known limitations

gh (GitHub CLI) authentication is global, not per-repo. GitHub CLI's authenticated account is global to your machine (gh keeps one active user per host), not per-repo — that's inherent to how gh itself works. gw use <account> will call gh auth switch for you, which changes gh's active account machine-wide, even for other repos/terminal tabs, until you gw use a different account somewhere else. Your git identity and SSH key stay correctly isolated per-repo regardless.

gw status shows both this repo's git identity and gh's currently active account as separate lines, so if they've drifted apart it's visible rather than silent.

Linked git worktrees share git identity. git config --local in a linked worktree (created via git worktree add) resolves to the same shared config file as the main checkout — git only isolates local config per-worktree if the repo opts into extensions.worktreeConfig, which gw does not assume. That means gw use <account> run inside a linked worktree changes the identity for the main checkout and every sibling worktree of that repo too, not just the worktree you ran it in. gw use detects this and prints a warning when you run it inside a linked worktree, but it does not block the switch or set up per-worktree config automatically.

The remote-account check is last-write-wins, URL-exact, and cd-triggered only for the shell-integration version. The gw-remote-map registry has no per-clone tracking: running gw use <account> anywhere for a given remote overwrites what "the right account" means for every other clone of that remote — this is intentional, not a bug. It also matches on the exact remote URL string, so an SSH clone and an HTTPS clone of the same repo are treated as two unrelated remotes. The cd-triggered gw-check script only runs on cd, so a shell already sitting in a mismatched repo when it starts won't warn until you cd away and back — gw install-hooks's blocking hooks don't have this gap, since they fire on the git action itself.

Commands

  • gw account add <name> — register an account (prompts for git name/email, GitHub username; can generate a new SSH key for you)
  • gw account list — list registered accounts
  • gw account remove <name> — remove a registered account
  • gw use <name> — activate an account for the current repo
  • gw status / gw whoami — show the active account for the current repo
  • gw init <shell> — print the shell prompt snippet for zsh, bash, or fish; add --install (zsh/bash only) to write and wire it up automatically
  • gw install-hooks — install blocking pre-commit/pre-push git hooks in the current repo that reject a commit/push when the wrong account is active (bypassable with git's own --no-verify)
  • gw credential-helper <get|store|erase> — internal, invoked by git itself as this repo's HTTPS credential helper; not meant to be run directly

Contributing

See CONTRIBUTING.md for dev setup and how to run the tests. Please follow the Code of Conduct. For security issues, see SECURITY.md instead of opening a public issue.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gwitch-0.2.0.tar.gz (46.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gwitch-0.2.0-py3-none-any.whl (19.8 kB view details)

Uploaded Python 3

File details

Details for the file gwitch-0.2.0.tar.gz.

File metadata

  • Download URL: gwitch-0.2.0.tar.gz
  • Upload date:
  • Size: 46.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for gwitch-0.2.0.tar.gz
Algorithm Hash digest
SHA256 8f263dc0d01bce9a920dac780c9ec977b0df3a858a47194da06558923336faef
MD5 66cf6627487a65a737c42ea7dd530fa2
BLAKE2b-256 e62ea6e5991efb744d7dca37d237cdd1c9e5ecd62f929fa300b7520ac6814786

See more details on using hashes here.

Provenance

The following attestation bundles were made for gwitch-0.2.0.tar.gz:

Publisher: publish.yml on isamrish/gwitch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gwitch-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: gwitch-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 19.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for gwitch-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5ad066479839ef6c748ea0aaad3bf97ad06332b907f808bf290d41e899eefea3
MD5 c2a7b2054f6fc2d3f2d1679edc615408
BLAKE2b-256 a90d429365194ee6c7aa45dfc6dffb066001c4766ab7ed0ddd8d44acd149ccb6

See more details on using hashes here.

Provenance

The following attestation bundles were made for gwitch-0.2.0-py3-none-any.whl:

Publisher: publish.yml on isamrish/gwitch

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.3.0

2 files

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page