Kanji
・Cloud engineer / freelance ・Born in 1993 ・From Ehime / Living in Shibuya, Tokyo ・5 years AWS experience Profile details
Table of Contents
gh auth switch
gh auth status
Active account: true
github.com
gh auth switch -u <username>
git push
git pull
gh auth setup-git
gh
gh auth login
unset GH_TOKEN GITHUB_TOKEN
When I first wrote this article in February 2023, GitHub CLI ( gh ) had no built-in way to store and switch between multiple accounts on the same host. Back then, the only practical workaround was copying ~/.config/gh/hosts.yml.${profile} files back and forth via custom shell aliases.
~/.config/gh/hosts.yml.${profile}
Starting with GitHub CLI v2.40.0 (released December 2023) , GitHub introduced native multi-account support via gh auth switch . Today (verified on gh version 2.102.0 ), you can log in to multiple accounts simultaneously and switch between them with a single native command—without manually overwriting config files:
gh version 2.102.0
# 1. Log in to an additional account (added alongside existing accounts without overwriting) gh auth login # 2. Check all logged-in accounts and see which one is currently active gh auth status # 3. Switch accounts (toggles immediately if you have 2 accounts on github.com) gh auth switch # 4. Switch non-interactively by specifying the username (for scripts or 3+ accounts) gh auth switch -u kanji-shinohara # 5. Sync Git HTTPS operations (git push / pull / clone) with the active gh account gh auth setup-git
If all you need is to run gh pr create or gh issue list under a different account, gh auth switch is all it takes.
gh pr create
gh issue list
However, as someone who switches daily between work repositories and personal repositories on the same Mac, I repeatedly ran into three real-world pitfalls that gh auth switch alone does not solve:
git commit
user.email
GH_TOKEN
GITHUB_TOKEN
personal
work
In this guide, I will walk through the official gh auth switch workflow, how to solve all three pitfalls using a two-layer separation architecture, and how to configure role-based aliases for automation.
▲ Two-Layer Multi-Account Architecture: API/HTTPS Credential Switching (gh auth switch) + Commit Author Isolation (Git includeIf)
While already logged in to your first account (e.g., work-taro ), simply run gh auth login again and authenticate with your second account (e.g., kanji-shinohara ):
work-taro
kanji-shinohara
gh auth login -h github.com -p https -w
Modern versions of GitHub CLI store OAuth tokens in your OS keyring by default (macOS Keychain, Windows Credential Manager, or Linux Secret Service) rather than writing plaintext oauth_token strings into ~/.config/gh/hosts.yml .
oauth_token
~/.config/gh/hosts.yml
Run gh auth status to inspect all registered accounts and verify which one has Active account: true :
$ gh auth status github.com ✓ Logged in to github.com account kanji-shinohara (keyring) - Active account: true - Git operations protocol: https - Token: gho_************************************ - Token scopes: 'gist', 'read:org', 'repo', 'workflow' ✓ Logged in to github.com account work-taro (keyring) - Active account: false - Git operations protocol: https - Token: gho_************************************ - Token scopes: 'gist', 'read:org', 'repo', 'workflow'
If you want to inspect only the active account in a script or terminal prompt, use --active ( -a ) or query the API directly:
--active
-a
# Display only the currently active account gh auth status --active # Print only the active GitHub username (useful in pre-push scripts) gh api user --jq '.login'
You can switch accounts in three ways depending on your setup:
# Option A: Toggle immediately when you have exactly two accounts on github.com gh auth switch # Option B: Specify the target username explicitly (best for scripts or 3+ accounts) gh auth switch -u kanji-shinohara # Option C: Specify both hostname and username (when using GitHub Enterprise Server) gh auth switch --hostname github.company.internal -u work-taro
git clone
Permission denied
One of the most common frustrations I hit was running gh auth switch -u kanji-shinohara , verifying Active account: true , and still getting remote: Permission to kanji-shinohara/repo.git denied to work-taro. (or Repository not found ) on git push .
gh auth switch -u kanji-shinohara
remote: Permission to kanji-shinohara/repo.git denied to work-taro.
Repository not found
This happens when Git’s own credential helper (such as macOS osxkeychain or Windows Credential Manager) caches an older token and intercepts HTTPS authentication before GitHub CLI is consulted.
osxkeychain
First, run the official setup command:
If your OS default credential helper still overrides GitHub CLI, clear the https://github.com helper chain first with an empty string '' and register !gh auth git-credential explicitly:
https://github.com
''
!gh auth git-credential
# Clear any system-level credential helper for github.com git config --global --replace-all 'credential.https://github.com.helper' '' # Delegate github.com HTTPS credentials exclusively to GitHub CLI git config --global --add 'credential.https://github.com.helper' '!gh auth git-credential'
Your ~/.gitconfig will now contain the following block, guaranteeing that git push and git pull immediately follow whichever account is active in gh auth switch :
~/.gitconfig
[credential "https://github.com"] helper = helper = !/opt/homebrew/bin/gh auth git-credential
user.name
includeIf
Here is the trap that catches almost everyone: gh auth switch only switches your API and HTTPS authentication token. It never changes user.name or user.email in Git.
If you switch authentication to your personal account and run git commit , Git will still stamp your commits with your global user.email (often your company address). To eliminate human error, I pair gh auth switch with Git’s directory-based includeIf configuration so commit identities switch automatically based on folder path.
# ~/.gitconfig [user] name = Kanji Shinohara email = kanji.shinohara@example.com # Automatically apply personal author identity inside ~/workspace/personal/ [includeIf "gitdir:~/workspace/personal/"] path = ~/.gitconfig-personal # Automatically apply work author identity inside ~/workspace/work/ [includeIf "gitdir:~/workspace/work/"] path = ~/.gitconfig-work [credential "https://github.com"] helper = helper = !/opt/homebrew/bin/gh auth git-credential
# ~/.gitconfig-personal [user] name = Kanji Shinohara email = kanji.shinohara@gmail.com
# ~/.gitconfig-work [user] name = Kanji Shinohara email = kanji.shinohara@company.co.jp
(Note: Make sure to include the trailing slash / in gitdir:~/workspace/personal/ so Git applies the rule recursively to all subdirectories.)
/
gitdir:~/workspace/personal/
When gh auth switch or git push does not behave as expected, walk through this diagnostic flow:
If direnv ( .envrc ), an MCP server config, or a shell export sets GH_TOKEN or GITHUB_TOKEN , GitHub CLI prioritizes the environment variable over your keyring configuration:
direnv
.envrc
$ gh auth switch X Active account on github.com cannot be switched while GH_TOKEN environment variable is set
Always check gh auth status —if it reports (from GH_TOKEN) , run unset GH_TOKEN GITHUB_TOKEN before switching.
(from GH_TOKEN)
In my daily workflow, AI coding agents (such as Claude Code and Antigravity) operate across both personal and work repositories. Rather than hardcoding specific GitHub usernames into shared agent instructions ( AGENTS.md ), I define a role-based alias ( gh switch-profile personal / gh switch-profile work ) so every automation rule can use a consistent command.
AGENTS.md
gh switch-profile personal
gh switch-profile work
gh auth switch -u
Add a switch-profile alias to ~/.config/gh/config.yml that maps role names to your GitHub usernames:
switch-profile
~/.config/gh/config.yml
# ~/.config/gh/config.yml git_protocol: https aliases: switch-profile: >- !case "$1" in personal) gh auth switch -h github.com -u kanji-shinohara ;; work) gh auth switch -h github.com -u work-taro ;; *) echo "[ERROR] Usage: gh switch-profile <personal|work>" && exit 1 ;; esac && gh auth status --active
Now both human developers and AI agents can run a uniform pre-push command:
gh switch-profile personal && git push origin HEAD
hosts.yml.${profile}
If you prefer storing separate hosts.yml.${profile_name} files on disk (when using --insecure-storage ), you can configure the four profile management aliases below in ~/.config/gh/config.yml :
hosts.yml.${profile_name}
--insecure-storage
git_protocol: https aliases: create-profile: '![ -z "$1" ] && echo "[ERROR] Please specify the profile name." && exit 1; gh auth status && read -p "Do you want to create this profile? (y/N): " yn; case "$yn" in [yY]*) cp ~/.config/gh/hosts.yml ~/.config/gh/hosts.yml.$1 && echo "New hosts file created: ~/.config/gh/hosts.yml.$1";; esac' switch-profile: '![ -z "$1" ] && echo "[ERROR] Please specify the profile name." && exit 1; if [ -e ~/.config/gh/hosts.yml.$1 ]; then cp ~/.config/gh/hosts.yml.$1 ~/.config/gh/hosts.yml && gh auth status && echo "[INFO] Hosts file switched"; else echo "[ERROR] Hosts file not found: ~/.config/gh/hosts.yml.$1"; fi' delete-profile: '![ -z "$1" ] && echo "[ERROR] Please specify the profile name." && exit 1; read -p "Do you want to delete this profile? (y/N): " yn; case "$yn" in [yY]*) rm -f ~/.config/gh/hosts.yml.$1 && echo "Hosts file deleted: ~/.config/gh/hosts.yml.$1";; esac' list-profiles: '!ls ~/.config/gh/hosts.yml.* | sed -e "s|^.*hosts.yml.||" | sed -e "s|^| - |"'
hosts.yml
-u <username>
Combining native gh auth switch (for OS keyring token management) with gh auth setup-git , includeIf (for commit email isolation), and a thin gh switch-profile role alias has completely eliminated Permission denied errors and wrong-email commits in my multi-account environment. The one feature I still hope to see in a future GitHub CLI release is native directory-scoped account selection (similar to Git’s includeIf ), which would remove the need to run a switch command altogether.
gh switch-profile
Nov 2026 LLM leaderboard: SWE-bench (86.8%), ARC-AGI (99.9%), Terminal-Bench & $2/$10 API pricing ac ... [Read more]
Comprehensive retrospective of the 2-year evolution of AI coding tools. Tracing the shift from GitHu ... [Read more]
Gen 3 AI agent memory architecture: replace binary vector DBs with Git Markdown SSOT & Hybrid GraphR ... [Read more]
yq
Master conversation skills with realistic AI phone training and 5-axis feedback. Includes 16-lesson interactive academy and studio AI portraits.
Effortlessly snap receipts for instant AI itemization. Integrated with LINE for seamless group expense tracking and pain-free settlement.
Interactive AI personas (Fortune Teller, Butler, Bartender) host real-time games, challenges, and conversation starters for unforgettable gatherings.
Get the complete configuration pack featured in this article: universal AGENTS.md, deterministic hooks.json, Git safety guardrails, and validation scripts tested across Antigravity, Kiro, Claude Code, and Codex.