Stop pushing commits from the wrong GitHub account
gas switches your Git identity, SSH key, and remote URL per folder — or per
repo with one command. A pre-commit hook blocks email mismatches before they
hit origin.
cd ~/some/repo
gas apply work # local user.email + SSH alias + remote, all set
Install -> · Commands -> · Recipes ->
How It Works
graph LR
A[git commit] --> B{In a configured<br/>workspace?}
B -->|Yes| C[includeIf picks<br/>the right identity]
B -->|No| D[gas apply id<br/>sets it locally]
C --> E[Pre-commit hook<br/>verifies email]
D --> E
E -->|match| F[commit succeeds]
E -->|mismatch| G[commit blocked]
| Layer | What gas configures |
|---|---|
~/.ssh/config |
Host aliases like gh-work, gh-personal -> the right key |
~/.gitconfig |
includeIf.gitdir: blocks per workspace |
Repo origin |
Rewrites git@github.com: -> git@gh-work: |
| Pre-commit hook | Aborts commits where user.email doesn't match the workspace |
Install
Preferred — package managers first:
pip install git-auto-switch
npm install -g git-auto-switch
Curl installer (only when no package manager fits). Download it first so you can inspect it, then run with an explicit checksum pin:
curl -fsSL https://raw.githubusercontent.com/luongnv89/git-auto-switch/main/install-curl.sh -o install-curl.sh
GAS_CHECKSUM=<sha256-of-the-release-tarball> bash install-curl.sh
Piping (curl -fsSL .../install-curl.sh | bash) still works but skips
pre-run inspection — avoid it when you can.
Verification: the installer downloads the release tarball to a file and
checks its SHA256 before extracting or executing anything. Precedence:
explicit --checksum <sha256> / GAS_CHECKSUM first, then a
<tarball-url>.sha256 sidecar (override with GAS_CHECKSUM_URL). On
mismatch the download is deleted and the install aborts. With no checksum
available (e.g. main snapshots publish no sidecar) it warns and
continues — pin GAS_CHECKSUM for a verified install.
Every method installs the same Bash CLI, so all of them need Bash 3.2+,
Git 2.13+, and jq at runtime. Each method adds its own requirement:
pip install git-auto-switch— Python >=3.11; the wheel bundles the CLI behind a Python launchernpm install -g git-auto-switch— Node >=22; the package wraps the CLI via a Node launcherinstall-curl.sh—curlandtar, plussha256sumorshasumfor the verified installmake installfrom a clone —make
Both launcher shims check the runtime deps on first run and offer to install missing ones via your package manager.
The PyPI and npm packages are published manually at release time. CI
(.github/workflows/ci.yml) runs lint and tests on every push and PR —
there is no automated release workflow yet.
See SECURITY.md for the full hardening posture, including
the make security-scan secret-scan gate and state-file permissions.
Commands
| Command | What it does |
|---|---|
gas init |
First-time setup wizard — adds your first account |
gas add |
Add another account (interactive) |
gas list |
Show all accounts and their workspaces |
gas current |
Show which account is active in the current directory (alias: whoami) |
gas apply |
Re-sync all configs (SSH, git, hooks, remotes) system-wide |
gas apply <id|alias> |
Apply one account to the current repo only |
gas apply --yes / --no-prompt |
Same, never pausing for confirmation (CI/scripts) |
gas apply --no-passphrase |
Allow generating an unencrypted SSH key (default prompts for a passphrase) |
gas audit |
Scan repos for identity mismatches |
gas audit --fix |
Same, plus auto-correct what it finds |
gas validate |
Check the config for errors (overlapping workspaces, dup aliases, …) |
gas validate --check-ssh |
Same, also testing SSH connections without prompting |
gas validate --yes / --no-prompt |
Assume yes / skip optional checks (CI/scripts) |
gas remove <id> |
Drop an account |
gas version / gas help |
Self-explanatory |
Recipes
Most workflows are 1-2 commands. The recipes below cover everything most users will need.
Set up your first two accounts
gas init
Walk through the prompts: account label, workspace folder(s), SSH key path, git name, git email. The wizard validates the SSH key and tests GitHub auth before saving.
gas add
Same prompts for the second account. After this, every repo inside a configured workspace uses that account's identity automatically.
"Which account am I committing as right now?"
gas current
Output:
========================================
Current Account: work
========================================
Account ID: work
Git Name: John Doe
Git Email: john@company.com
SSH Alias: gh-work
Directory: /home/user/workspace/work/project
Workspaces:
- ~/workspace/work
- ~/projects/company
Returns nothing if you're outside any configured workspace.
Apply an account to a single repo
For one-off repos that sit outside any configured workspace, or to override the workspace default for one project:
cd ~/some/repo
gas apply work
Or by SSH alias — both forms work:
gas apply gh-work
What it does:
- Sets local
user.name/user.email(no--global) - Adds the SSH alias to
~/.ssh/configif it's missing - Rewrites
originfromgit@github.com:->git@gh-work: - Switches the alias if
originwas already pointing at a different one
Local config wins over includeIf, so this works inside or outside any
workspace.
Find and fix wrong-identity repos
gas audit
Lists every repo whose user.email or remote alias doesn't match its
workspace. Read-only — won't change anything.
gas audit --fix
Same scan, but:
- Removes local
user.emailoverrides soincludeIfcan take over - Rewrites
git@github.com,ssh://git@github.com, andhttps://github.comremotes to use the correct SSH alias
Clone a new repo under the right account
git clone git@gh-work:org/repo.git
Use the SSH alias instead of github.com when cloning. If you forget,
gas audit --fix will rewrite it next time.
Update everything after editing the config by hand
gas apply
Re-generates ~/.ssh/config, ~/.gitconfig includes, the pre-commit hook,
and rewrites remotes for every workspace.
When Things Go Wrong
| Symptom | Command |
|---|---|
| Commit rejected with "email mismatch" | gas current to see expected, then gas audit --fix |
| Pushed but wrong account got credit | gas audit (read-only diagnostic), then fix the remote |
Permission denied (publickey) |
gas list -> verify key path, then ssh -T git@gh-<alias> |
| Just want to undo everything | Restore from ~/.git-auto-switch/backup/<timestamp>/ |
Comparison
Manual git config |
gas |
|
|---|---|---|
| Per-repo identity | Edit .git/config by hand |
gas apply <id> |
| SSH key per account | Hand-crafted ~/.ssh/config |
Generated from one wizard |
| Wrong-email guard | None | Pre-commit hook (blocks before push) |
| Audit existing repos | Custom shell script | gas audit |
License
Configuration file format
State lives in ~/.git-auto-switch/config.json:
{
"version": "1.0.0",
"accounts": [
{
"id": "work",
"name": "Work Account",
"ssh_alias": "gh-work",
"ssh_key_path": "~/workspace/work/.ssh/id_ed25519",
"workspaces": [
"~/workspace/work",
"~/projects/company"
],
"git_name": "John Doe",
"git_email": "john@company.com"
}
]
}
Repository scans are cached per workspace under
~/.git-auto-switch/cache/repo-scans/ so back-to-back commands (e.g.
gas apply then gas audit --fix) walk each workspace once. Entries
expire after GAS_SCAN_CACHE_TTL seconds (default 300; set 0 to
disable).
Backups are written to ~/.git-auto-switch/backup/<timestamp>/ before
every change. Restore with:
cp ~/.git-auto-switch/backup/<timestamp>/ssh_config ~/.ssh/config
cp ~/.git-auto-switch/backup/<timestamp>/gitconfig ~/.gitconfig
Multiple workspaces per account
One account can map to several folders — useful when client work and personal projects share an identity but live in different directories.
Workspace folder [~/workspace/work]: ~/workspace/work
Add another workspace? (leave empty to continue): ~/projects/company
Add another workspace? (leave empty to continue):
Edit later by adding to the account's workspaces list in
~/.git-auto-switch/config.json, then run gas apply. gas list
shows the full set:
[work] Work Account
Git: John Doe <john@company.com>
SSH: gh-work
Workspaces:
- ~/workspace/work
- ~/projects/company
- ~/freelance/client-a
Install from source
git clone https://github.com/luongnv89/git-auto-switch.git
cd git-auto-switch
brew install jq # or: sudo apt install jq
make install
To uninstall a curl-installed copy:
curl -fsSL https://raw.githubusercontent.com/luongnv89/git-auto-switch/main/install-curl.sh | bash -s uninstall
Development
brew install shellcheck bats-core jq
make lint # ShellCheck
make test # bats suite (226 tests)
bats test/ # same suite, direct invocation
make all # both
See CONTRIBUTING.md for guidelines.
How identity switching works internally
- SSH keys — separate ed25519 key per account, generated on first run if missing.
- SSH config — host aliases (
gh-work,gh-personal) routed to the right key in~/.ssh/config. - Git config —
includeIf.gitdir:blocks in~/.gitconfigswitchuser.name/user.emailbased on the current directory. - Pre-commit hook — installed globally; aborts commits when
user.emaildoesn't match the workspace's expected email. - Remote rewriting —
git@github.com:org/repo.gitis rewritten togit@gh-<alias>:org/repo.gitso each push uses the right key.
Metadata
Release files for git-auto-switch 0.3.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 | |
|---|---|---|---|
| git_auto_switch-0.3.0.tar.gz | 43.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| git_auto_switch-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 90.5 kB
Release files / git_auto_switch-0.3.0.tar.gz
| Download URL | git_auto_switch-0.3.0.tar.gz |
|---|---|
| Size | 43.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2443e7b402ce2c6737e2d2b5aaa8aa9420064e47a5c3dad07a75fab2d2e0a600
|
|
BLAKE2b-256 checksum How to use checksums |
51850b82d56862a892a9fe9c08d46d1805ae78ba840192c80e3341b9604db734
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.7
|
Release files / git_auto_switch-0.3.0-py3-none-any.whl
| Download URL | git_auto_switch-0.3.0-py3-none-any.whl |
|---|---|
| Size | 47.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7127123ba25295a116222358e03745ab5fc8c6371056917bb0fc2dba34283296
|
|
BLAKE2b-256 checksum How to use checksums |
9aa08c2b7300a396c0f24b88d451d7fdd8731060811804719ef6fb6b73c35d9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.7
|