Skip to content

About

A small Windows app for people who use more than one GitHub account on the same machine. Every repository automatically commits and pushes as the account that owns it — no per-repo setup, nothing to remember when you clone.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

GitHub Accounts

A native Windows and macOS app for people who use more than one GitHub account on the same machine. Every repository automatically commits and pushes as the account that owns it — no per-repo setup, nothing to remember when you clone.

Repositories

The problem

With two accounts, HTTPS doesn't work. Git's credential store keys tokens by host, and both accounts are github.com, so whichever you authenticated last wins. You end up pushing to a work repo as your personal account, or hitting 403 for no obvious reason — and the wrong author email is baked into commits before you notice.

The usual fix is SSH host aliases plus includeIf in .gitconfig. It works, but it's fiddly to set up, easy to get subtly wrong, and invisible once done. This app sets it up, keeps it correct, and shows you the current state.

Install

Download the macOS .dmg or Windows .exe from Releases. On Mac, open the disk image and drag the app to Applications. On Windows, run the portable executable directly. The source build instructions below are an alternative to downloading a release.

macOS

Requires macOS 13 Ventura or later and Git 2.36 or later.

Opening the downloaded app

Current macOS releases are ad-hoc signed and have not been notarized by Apple. On first launch, macOS may show “Apple could not verify GitHub Accounts is free of malware that may harm your Mac or compromise your privacy.”

If you downloaded the app from this repository's Releases and choose to trust it:

  1. Open the .dmg and drag GitHub Accounts to Applications. If updating, quit the old app first and choose Replace when prompted.
  2. In Finder, open Applications and double-click GitHub Accounts.
  3. When the warning appears, click Done or Cancel to dismiss it and keep the app.
  4. Immediately open System Settings → Privacy & Security. Scroll down past the privacy permissions to the Security section.
  5. Click Open Anyway beside the message about GitHub Accounts, authenticate when prompted, then confirm Open.

If Open Anyway is missing: close System Settings, try opening the installed app again to trigger a fresh warning, dismiss it, and immediately reopen Privacy & Security. Scroll all the way down to Security; the option appears after a blocked launch attempt. Make sure you are opening the copy you just installed in /Applications, rather than an older copy or the app inside the mounted disk image. Source builds installed by install-macos.sh live in ~/Applications, which is a different folder.

On a Mac managed by an employer or school, these options may be restricted; contact the administrator if they remain unavailable. See Apple's instructions for opening apps safely.

Build from source

Install Apple's Command Line Tools with xcode-select --install if they are not already present. No .NET, Homebrew, Python, or Swift package dependencies are needed.

git clone https://github.com/web-dev-nav/multi-git-holder
cd multi-git-holder
sh install-macos.sh
open "$HOME/Applications/GitHub Accounts.app"

The installer builds a universal app for Apple Silicon and Intel, installs it in ~/Applications, and keeps a backup of a previous app installation. To build only for your current Mac, use ARCH="$(uname -m)" sh install-macos.sh.

In the macOS app:

The Mac interface follows the Windows layout: Repositories, Accounts, and Folders tabs, compact tables and toolbars, and a status bar.

  1. On Accounts, use Detect keys… to verify existing ~/.ssh/*.pub key pairs with GitHub and save/apply their routing. Select an account to use Edit routing, Remove, Test SSH, or Copy public key.
  2. Add account… opens the same four-step flow as Windows: account details, choose or generate a key, give its public half to GitHub, then verify and finish. The saved username comes from GitHub's authentication response.
  3. Add organizations using Edit routing. Use Test repository… to check an exact repository URL with the selected account without cloning it.
  4. Add parent folders in Folders, set Search depth, and choose Rescan now to return to Repositories.
  5. On Repositories, select one or more rows, choose an account, and use Apply to switch them. Fix all mismatches restores owner-based routing across the scanned repositories. Both actions ask for confirmation before changing origin URLs and local commit settings. Open folder opens the selection in Finder. Existing commits are unchanged.

For an encrypted key, first unlock it with ssh-add --apple-use-keychain ~/.ssh/your_key. Key generation creates a new ed25519 key without a passphrase and never overwrites an existing key.

The macOS app reads and writes the same PascalCase JSON format at ~/.gh-accounts.json as Windows. It backs up affected configuration files before applying routing and preserves text outside the managed markers. It rejects conflicting owner assignments, malformed marker blocks, and managed-file symlinks rather than overwriting them. Private keys are never read into the app or uploaded; OpenSSH uses them to authenticate. Key paths must point to files on this Mac; Windows key paths are not automatically migrated.

The included CLI uses the same routing engine:

"bin/GitHub Accounts.app/Contents/MacOS/gh-accounts" detect
"bin/GitHub Accounts.app/Contents/MacOS/gh-accounts" setup-existing
"bin/GitHub Accounts.app/Contents/MacOS/gh-accounts" test-repository https://github.com/owner/repo.git

detect verifies keys without changing routing; setup-existing verifies them again, saves the accounts, and applies the configuration. GHACCT_HOME can point at an isolated home directory for testing. The CLI and app do not switch gh's independently authenticated account.

Unlike Windows, the macOS app reports a global core.sshCommand override instead of deleting it. Review its source with git config --show-origin --get core.sshCommand if routing fails. Removing an account on macOS keeps its SSH keys and identity file; only the routing is removed.

Windows

git clone https://github.com/web-dev-nav/multi-git-holder
cd multi-git-holder
install.cmd

There is nothing to install first — Windows already ships the compiler this uses. A prebuilt GhAccounts.exe may also be attached to Releases.

install.cmd compiles the app, copies it to %LOCALAPPDATA%\Programs\GhAccounts and adds Desktop and Start Menu shortcuts.

Requirements: Windows with .NET Framework 4.x (in-box since Windows 8) and Git for Windows. No .NET SDK, no runtime installer, no admin rights. The exe is about 50 KB and starts instantly.

First time, with no SSH keys at all

If you have never set up SSH for GitHub, Accounts → Add account... walks you through it in four steps. Do it once per account.

Step 1 Step 2
Step 3 Step 4

1. Which account. The username exactly as it appears in your profile URL. Leave name and email blank to use the GitHub noreply address, which keeps working even with Keep my email private turned on.

2. Choose a key. Generate a new key if you have never set up SSH — it creates an ed25519 key in your .ssh folder. Otherwise point at one you have.

3. Give the key to GitHub. The public half is already on your clipboard and shown on screen; the private half never leaves your machine. Sign in to GitHub as this account before pasting — for a second account use a private window or sign out first. This is the step people get wrong.

4. Check it works. The app asks GitHub who the key belongs to. You want Hi <username>! If GitHub reports a different username than you typed, the account is saved under GitHub's answer — URL matching needs it exact, and a typo would otherwise stop every repo for that account from being recognised.

Already have working keys? Skip all of it and press Detect keys... — it tests every key in ~/.ssh against GitHub and adds the ones that work.

Removing an account

On Windows, Accounts → Remove takes it out of the routing and deletes the identity file it created. Repositories keep working; they just stop being assigned to that account automatically. If the key lives in your .ssh folder, it offers to delete that too — it never touches a key you pointed at from elsewhere, and it reminds you that GitHub keeps its own copy until you remove it there as well.

Quick start

1. Add your accounts. Detect keys... tries every key in ~/.ssh against GitHub and adds the ones that authenticate, naming each from GitHub's own Hi <user>! reply — so a key can't end up filed under the wrong account. Add account... handles a new one, including generating the SSH key, copying the public half to your clipboard and opening GitHub's "add key" page. Add any organizations that should use that identity (for example TNHBSupport) under Organizations / owners. A GitHub username and an organization are separate: one SSH identity may route repositories for several owners.

Accounts

2. Point it at your code. Add the folders holding your repositories and set how deep to search. Common locations are detected on first run.

Folders

3. That's it. Clone anything — paste a plain https://github.com/... URL — and it is routed to the right key and the right commit identity automatically.

Use Test repository... on the Accounts tab to verify an exact private URL before cloning it. The test follows the same Git-to-SSH routing as git clone and does not download or modify the repository.

Use regular git clone for automatic account routing. gh repo clone first checks repository access through the GitHub CLI's independently selected account, before Git can apply these SSH routing rules.

The Repositories tab flags anything inconsistent: a repo committing as the wrong account for its remote, an identity belonging to neither account, a locally pinned override. Both interfaces provide Apply for selected repositories and Fix all mismatches for the scanned list.

How it works

Three standard Git and SSH features, wired together:

Piece What it does
SSH host aliases github-<account> in ~/.ssh/config, each bound to one key with IdentitiesOnly yes
url.<alias>.insteadOf Rewrites any pasted github.com URL for every assigned repository owner or organization onto that account's alias
includeIf "hasconfig:remote.*.url:…" Selects user.name / user.email from the remote URL (Git 2.36+)

Everything the app writes lives between markers:

# >>> gh-account-switcher >>>
...
# <<< gh-account-switcher <<<

Only that block is rewritten. Anything else in your .gitconfig or .ssh/config — other hosts, other settings — is left untouched.

Configuration is a single JSON file at %USERPROFILE%\.gh-accounts.json on Windows or ~/.gh-accounts.json on macOS. Existing configuration files are upgraded automatically: the authenticated username becomes the first repository owner, and organizations can then be added with Edit routing.

WSL

Windows and WSL keep separate ~/.ssh and ~/.gitconfig, and WSL's ssh rejects keys stored on /mnt/c because they always appear world-readable. To mirror the setup into WSL:

bash wsl-sync.sh

It copies the keys in with mode 600, writes the same managed blocks on the Linux side, and tests each alias.

Things worth knowing

  • Email privacy. If an account has Keep my email private enabled, pushes using a real address are rejected. Use the ID+username@users.noreply.github.com form from that account's email settings. New accounts default to the noreply form for this reason.
  • Windows clears core.sshCommand; macOS reports it. If it points at some other ssh config, the aliases won't resolve and every push fails with Could not resolve hostname github-<account>. Both apps verify with ssh -G that each alias resolves before reporting success.
  • ** in hasconfig patterns degrades to * mid-token and cannot cross //, so the https:// and ssh:// forms are written out in full rather than prefixed with **. A pattern like **github.com/org/** silently matches nothing.
  • Past commits keep their original author. This only affects new commits. git commit --amend --reset-author fixes the most recent one, if it isn't pushed yet.
  • Unknown orgs fall back to your global user.name / user.email rather than guessing.

Uninstall

On macOS, quit the app and move ~/Applications/GitHub Accounts.app to Trash. Keys and account routing are retained. Remove the marked blocks from ~/.gitconfig and ~/.ssh/config to stop routing, and remove ~/.gh-accounts.json and the generated ~/.gitconfig-<account> files if desired.

On Windows:

uninstall.cmd

Removes the app and its shortcuts. Your keys, repositories and config are left alone; delete the marked blocks from .gitconfig and .ssh\config by hand for a full revert.

Building

macOS

sh build-macos.sh
sh test-macos.sh
sh package-macos.sh

The build produces bin/GitHub Accounts.app, containing a SwiftUI interface and a command-line helper, with arm64 and x86_64 slices. Set ARCH=arm64 or ARCH=x86_64 for a single architecture. Tests use a temporary home directory and real Git/SSH parsers, without changing your account configuration or making network requests. The packaging script creates bin/GitHub-Accounts-macOS.dmg with the app and an Applications shortcut, then verifies the disk image. The CI workflow uploads the DMG and the standalone Windows executable.

The app is ad-hoc signed for local use. Public distribution outside a local build requires a Developer ID signature and notarization to avoid Gatekeeper prompts.

Windows

build.cmd

Compiles with csc.exe from the in-box .NET Framework, so there is nothing to install. The source targets C# 5 for that compiler — no string interpolation, no null-conditional operator.

Publishing a release

Both platforms use the same blue/purple two-account icon. To regenerate the Windows ICO, macOS ICNS, and source PNG sizes, run swift macos/GenerateIcons.swift on a Mac and commit the updated assets/ and src/app.ico files. The Mac build bundles the ICNS; Windows embeds the ICO in the executable and uses it for its windows and taskbar.

Push a version tag to build and publish both apps automatically:

git pull --ff-only
git tag -a v1.0.1 -m "GitHub Accounts v1.0.1"
git push origin v1.0.1

Use a new vMAJOR.MINOR.PATCH version for each release. In Actions → Build and release, GitHub tests and builds the universal macOS app, builds the Windows executable, then publishes a release containing GitHub-Accounts-macOS.dmg and GitHub-Accounts-Windows.exe. Publication only runs after both builds succeed. The Mac app's bundle version is taken from the tag.

For a local Mac build without publishing, run sh build-macos.sh; optionally set APP_VERSION=1.0.1. The bundle is written to bin/GitHub Accounts.app.

License

MIT

About

A small Windows app for people who use more than one GitHub account on the same machine. Every repository automatically commits and pushes as the account that owns it — no per-repo setup, nothing to remember when you clone.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages