Skip to content

Instantly share code, notes, and snippets.

@Luiyit
Created June 4, 2026 09:39
Show Gist options
  • Select an option

  • Save Luiyit/d8ade93c5933ecefe13e71a0fe288ee8 to your computer and use it in GitHub Desktop.

Select an option

Save Luiyit/d8ade93c5933ecefe13e71a0fe288ee8 to your computer and use it in GitHub Desktop.
Multi-account gh CLI — workspace-scoped GitHub auth on Windows

Multi-account gh CLI — workspace-scoped GitHub auth on Windows

You can keep separate GitHub identities per workspace folder by pointing the gh CLI at a per-workspace config directory via the GH_CONFIG_DIR environment variable. Each workspace gets its own active account; your default account stays intact for everything outside the workspace.

This guide walks through the full setup on Windows + PowerShell, using a Dawere workspace at I:\code\dawere\ as a working example. Adapt the paths to your case.


What we want

Context Active account
Default shell / any other folder personal account
Inside the Dawere workspace work account

Both accounts coexist in the OS credential store (keyring). The active one is decided by the hosts.yml file that gh reads — and that file lives in whichever directory GH_CONFIG_DIR points to.


Step 1 — Create the per-workspace config directory

mkdir I:\code\dawere\.gh-config

Add a .gitignore so the auth state never gets committed if the workspace itself is a git repo:

# I:\code\dawere\.gh-config\.gitignore
*
!.gitignore

Step 2 — Persist GH_CONFIG_DIR at the user level

This makes every new terminal (cmd, PowerShell, Git Bash) inside the workspace pick the variable up automatically.

setx GH_CONFIG_DIR "I:\code\dawere\.gh-config"

setx writes the variable to the Windows registry. Existing shells won't see it until they're closed and reopened.

Verify in a brand-new PowerShell:

[Environment]::GetEnvironmentVariable("GH_CONFIG_DIR", "User")
$env:GH_CONFIG_DIR

Both should print I:\code\dawere\.gh-config.

If you only want the variable in the current shell, skip setx and run:

$env:GH_CONFIG_DIR = "I:\code\dawere\.gh-config"

Step 3 — Log in to the work account

Open a fresh PowerShell inside the workspace so $env:GH_CONFIG_DIR is already set, then:

gh auth login

Wizard answers:

  1. Where do you use GitHub?GitHub.com
  2. Preferred protocol for Git operations?HTTPS (or SSH, your call)
  3. Authenticate Git with your GitHub credentials?Yes
  4. How would you like to authenticate?Login with a web browser
  5. Copy the one-time code, press Enter, paste it in the browser, and log in with the work account.

After it finishes, verify the work account landed in the workspace config:

gh auth status

You should see the work account as Active account: true and a hosts.yml file inside I:\code\dawere\.gh-config\.


Step 4 — Make sure the global default is your personal account

Outside the workspace, gh reads %APPDATA%\GitHub CLI\hosts.yml. If your personal account is already the default there, you're done. If not:

# Run in a shell where GH_CONFIG_DIR is NOT set
gh auth switch -u <personal-username>

If your personal account isn't logged in globally yet, log it in once:

gh auth login

…in a shell where $env:GH_CONFIG_DIR is empty (e.g. cmd /c or a PowerShell where you ran Remove-Item Env:GH_CONFIG_DIR first).


Step 5 — Verify the isolation

Run both checks in two different shells.

Outside the workspace (or anywhere GH_CONFIG_DIR is unset):

gh auth status
# Expected: personal account is Active

Inside the workspace (where GH_CONFIG_DIR points to the per-folder config dir):

gh auth status
# Expected: work account is Active

Final sanity check by hitting a private org repo:

gh repo view <org>/<repo> --json name,viewerPermission

How this actually works

  • gh keeps two pieces of state per host: a small hosts.yml config file and the actual auth token.
  • hosts.yml decides which username is the active one. It lives in GH_CONFIG_DIR (or the default %APPDATA%\GitHub CLI\ when the var is unset).
  • The token itself is stored in the OS credential store (Windows Credential Manager on Windows, Keychain on macOS, Secret Service on Linux), keyed by host + username. All gh config dirs on the same machine share the same keyring, so you only ever log in once per account — switching the active account just means switching which username hosts.yml points at.
  • That's why you can have N config dirs, each picking a different active account from the shared credential store.

Common operations

# List every account that gh knows about on this host
gh auth status

# Switch the active account inside the current config dir
gh auth switch -u <username>

# Drop the workspace var in the current shell (revert to global)
Remove-Item Env:GH_CONFIG_DIR
gh auth status   # back to the global default

# Completely remove the persisted var
setx GH_CONFIG_DIR ""

Caveats

  • setx doesn't update the current shell. Always reopen the terminal after running it.
  • The token lives in the OS keyring, not in the per-folder config dir. Don't expect to copy .gh-config\ to another machine and have it work — the keyring entries won't follow.
  • Token scopes are per-account, not per-config-dir. If the work account needs workflow scope and the personal one doesn't, generate the tokens accordingly when logging each one in.
  • Git push/pull doesn't use the gh CLI auth automatically — it uses the Git credential manager. If you also want git pushes to a private org repo to authenticate as the work account, configure that separately (e.g. SSH keys or a per-repo credential helper).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment