Technology Aug 26, 2026 · 8 min read

Using Multiple GitHub Accounts: Automatically Select the Correct `gh` PAT Based on Repo Owner

When using multiple GitHub accounts, the process of selecting the correct Personal Access Token (PAT) for git push or git pull over HTTPS can be a bit cumbersome. Specifically, when dealing with repositories from multiple owners, such as: https://github.com/aont/foo.git https://github.com/anothe...

DE
DEV Community
by vast cow
Using Multiple GitHub Accounts: Automatically Select the Correct `gh` PAT Based on Repo Owner

When using multiple GitHub accounts, the process of selecting the correct Personal Access Token (PAT) for git push or git pull over HTTPS can be a bit cumbersome.

Specifically, when dealing with repositories from multiple owners, such as:

https://github.com/aont/foo.git
https://github.com/another-user/bar.git

Git Credential Manager or gh auth git-credential might default to the currently active account, leading to errors like:

remote: Permission to owner/repo.git denied to other-user.

To address this, the owner portion of the remote URL is interpreted as the GitHub CLI account name, and a credential helper is embedded directly into the .gitconfig file. This helper retrieves the PAT using:

gh auth token --user OWNER

and provides it to Git.

This eliminates the need for external scripts.

Prerequisites

First, ensure that you are logged into your GitHub accounts using gh:

gh auth login

If you have multiple accounts registered, you can verify them with:

gh auth status

With this method, if a repository URL is:

https://github.com/aont/foo.git

the command:

gh auth token --user aont

will be executed.

Therefore, the basic assumption is:

repository owner = gh registered account name

.gitconfig

The configuration should be as follows:

[credential]
    useHttpPath = true

[credential "https://github.com/"]
    helper =
    helper = "!f() { \
        [ \"$1\" = get ] || exit 0; \
        account=''; \
        while IFS='=' read -r k v; do \
            [ \"$k\" = path ] && account=${v%%/*}; \
        done; \
        [ -n \"$account\" ] || exit 0; \
        token=$(gh auth token --user \"$account\") || exit 0; \
        printf 'username=%s\\npassword=%s\\n' \"$account\" \"$token\"; \
    }; f"

[credential "https://gist.github.com/"]
    helper =
    helper = "!f() { \
        [ \"$1\" = get ] || exit 0; \
        account=''; \
        while IFS='=' read -r k v; do \
            [ \"$k\" = path ] && account=${v%%/*}; \
        done; \
        [ -n \"$account\" ] || exit 0; \
        token=$(gh auth token --user \"$account\") || exit 0; \
        printf 'username=%s\\npassword=%s\\n' \"$account\" \"$token\"; \
    }; f"

There are three key points:

credential.useHttpPath = true is Important

Typically, Git's credential helper receives only:

protocol=https
host=github.com

However, in this case, we need:

aont/foo.git

the path.

Therefore, set:

[credential]
    useHttpPath = true

This causes the path to be passed to the credential helper's standard input, such as:

protocol=https
host=github.com
path=aont/foo.git

Use the Beginning of the Path as the Account

Inside the helper, the first element of the path is extracted using:

[ "$k" = path ] && account=${v%%/*}

For example, if:

path=aont/foo.git

then:

account=aont

After that, the corresponding PAT for that account is retrieved from the GitHub CLI using:

token=$(gh auth token --user "$account")

Therefore, when accessing:

https://github.com/aont/foo.git

the command:

gh auth token --user aont

is automatically executed.

Conversely, for:

https://github.com/another-user/bar.git

the command:

gh auth token --user another-user

is executed.

There is no need to run gh auth switch every time.

Reset Existing Credential Helpers with helper =

Another important point is:

helper =

On Git for Windows, for example, Git Credential Manager or gh auth git-credential might already be configured.

If another helper returns the credentials first, this helper might not be executed.

As a result, you might encounter an error like:

remote: Permission to foo/bar.git denied to wrong-account.

Therefore, use:

helper =
helper = "!f() { ... }; f"

The first empty helper = resets any previously configured credential helpers, and then only this helper is registered.

This is crucial when dealing with multiple GitHub accounts.

Use the Same Mechanism for Gists

The same credential helper can be configured for Gists.

However, the standard Gist clone URL is:

https://gist.github.com/GIST_ID.git

and the username cannot be determined from the URL.

Therefore, in this setup, the Gist remote URL is intentionally formatted as:

https://gist.github.com/USER/GIST_ID.git

For example, if:

https://gist.github.com/aont/0123456789abcdef.git

then, from the credential helper's perspective:

path=aont/0123456789abcdef.git

so, the command:

gh auth token --user aont

is automatically used.

This allows you to treat GitHub repositories and Gists with the same rules.

github.com/USER/REPO
gist.github.com/USER/GIST
                ↓
             USER is extracted
                ↓
gh auth token --user USER

Verification

You can check which credentials Git is actually retrieving using git credential fill.

For example, run:

printf '%s\n' \
  'protocol=https' \
  'host=github.com' \
  'path=aont/foo.git' \
  '' |
git credential fill

The expected output is:

protocol=https
host=github.com
username=aont
password=...

If the username is a different account, you can check if another credential helper is still present using:

git config --show-origin --get-all credential.helper

Why Not Use gh auth git-credential Directly?

The GitHub CLI has a standard command:

gh auth git-credential

This is sufficient for normal single-account usage.

However, when using multiple accounts with the same host (github.com), you might want to explicitly control which gh account is used based on the repository owner.

This helper uses a very simple rule:

remote URL
  ↓
owner is extracted
  ↓
gh auth token --user owner

so you don't need to be aware of which account is currently active in gh.

Advantages of This Configuration

This method does not save the PAT itself in the .gitconfig file.

The PAT is retrieved each time it is needed using:

gh auth token --user ACCOUNT

Therefore, the configuration only saves the rule for which account to use.

Additionally, you do not need to run:

gh auth switch

or set:

git config credential.username ...

for each repository.

The remote URL itself becomes the credential routing information.

Summary

When using multiple GitHub accounts over HTTPS, using the account portion of:

github.com/<account>/<repo>

directly for selecting the gh account can simplify operations.

The mechanism is:

Git remote URL
  ↓
credential.useHttpPath
  ↓
path=owner/repo.git
  ↓
owner is extracted
  ↓
gh auth token --user owner
  ↓
username/password is returned to Git

If you have multiple personal accounts and the relationship:

repository owner = GitHub account

holds true, this method is quite easy to use.

For organization-owned repositories where:

owner != account used for authentication

you will need separate mappings, but this configuration is sufficient for primarily personal accounts.

GitHub複数アカウント運用で、repo ownerから自動的にghのPATを選ぶ

GitHubで複数アカウントを使っていると、HTTPSでのgit pushgit pull時に「どのアカウントのPATを使うか」が地味に面倒です。

特に、

https://github.com/aont/foo.git
https://github.com/another-user/bar.git

のように複数ownerのrepositoryを扱っていると、Git Credential Managerやgh auth git-credentialが現在のアクティブアカウントを使ってしまい、

remote: Permission to owner/repo.git denied to other-user.

のようなエラーになることがあります。

そこで、remote URLのowner部分をそのままGitHub CLIのアカウント名として解釈し、

gh auth token --user OWNER

からPATを取り出してGitに返すcredential helperを.gitconfigへ直接埋め込みます。

外部スクリプトも不要です。

前提

まず、利用するGitHubアカウントはあらかじめghにログインしておきます。

gh auth login

複数アカウントを登録している場合は、

gh auth status

で確認できます。

この方法では、たとえばrepository URLが

https://github.com/aont/foo.git

なら、

gh auth token --user aont

を実行します。

したがって、基本的には

repository owner = ghに登録したaccount名

という運用を前提にします。

.gitconfig

設定は次のようにします。

[credential]
    useHttpPath = true

[credential "https://github.com/"]
    helper =
    helper = "!f() { \
        [ \"$1\" = get ] || exit 0; \
        account=''; \
        while IFS='=' read -r k v; do \
            [ \"$k\" = path ] && account=${v%%/*}; \
        done; \
        [ -n \"$account\" ] || exit 0; \
        token=$(gh auth token --user \"$account\") || exit 0; \
        printf 'username=%s\\npassword=%s\\n' \"$account\" \"$token\"; \
    }; f"

[credential "https://gist.github.com/"]
    helper =
    helper = "!f() { \
        [ \"$1\" = get ] || exit 0; \
        account=''; \
        while IFS='=' read -r k v; do \
            [ \"$k\" = path ] && account=${v%%/*}; \
        done; \
        [ -n \"$account\" ] || exit 0; \
        token=$(gh auth token --user \"$account\") || exit 0; \
        printf 'username=%s\\npassword=%s\\n' \"$account\" \"$token\"; \
    }; f"

ポイントは3つあります。

credential.useHttpPath = true が重要

通常、Gitのcredential helperには

protocol=https
host=github.com

程度しか渡されません。

しかし今回必要なのは、

aont/foo.git

というpathです。

そこで、

[credential]
    useHttpPath = true

を設定します。

これによってcredential helperの標準入力に、

protocol=https
host=github.com
path=aont/foo.git

のようにpathも渡されます。

pathの先頭をaccountとして使う

helper内では、

[ "$k" = path ] && account=${v%%/*}

として、pathの最初の要素を取得しています。

たとえば、

path=aont/foo.git

なら、

account=aont

になります。

その後、

token=$(gh auth token --user "$account")

で、そのアカウントに対応するPATをGitHub CLIから取得します。

つまり、

https://github.com/aont/foo.git

へのアクセス時は自動的に、

gh auth token --user aont

相当になります。

一方、

https://github.com/another-user/bar.git

なら、

gh auth token --user another-user

になります。

gh auth switchを毎回実行する必要はありません。

helper = で既存credential helperをリセットする

もう一つ重要なのが、

helper =

です。

Git for Windowsなどでは、すでにGit Credential Managerやgh auth git-credentialなどが設定されている場合があります。

たとえば別のhelperが先にcredentialを返すと、今回のhelperまで処理が回ってきません。

その結果、

remote: Permission to foo/bar.git denied to wrong-account.

のようになります。

そこで、

helper =
helper = "!f() { ... }; f"

とします。

最初の空のhelper =で、それ以前に設定されていたcredential helperをリセットし、その後に今回のhelperだけを登録しています。

複数GitHubアカウントを扱う場合には、この部分がかなり重要です。

Gistにも同じ仕組みを使う

Gistにも同じcredential helperを設定できます。

ただし通常のGist clone URLは、

https://gist.github.com/GIST_ID.git

となっていて、URLからユーザー名を判断できません。

そこで、この運用ではGistのremote URLを意図的に、

https://gist.github.com/USER/GIST_ID.git

という形式にします。

たとえば、

https://gist.github.com/aont/0123456789abcdef.git

なら、credential helperから見ると、

path=aont/0123456789abcdef.git

となるので、

gh auth token --user aont

を自動的に使えます。

つまりGitHub repositoryとGistを同じルールで扱えます。

github.com/USER/REPO
gist.github.com/USER/GIST
                ↓
             USERを抽出
                ↓
gh auth token --user USER

動作確認

Gitが実際にどのcredentialを取得するかは、git credential fillで確認できます。

たとえば、

printf '%s\n' \
  'protocol=https' \
  'host=github.com' \
  'path=aont/foo.git' \
  '' |
git credential fill

を実行します。

期待する出力は、

protocol=https
host=github.com
username=aont
password=...

です。

ここでusernameが別アカウントになっている場合は、

git config --show-origin --get-all credential.helper

で、別のcredential helperが残っていないか確認するとよいです。

なぜgh auth git-credentialをそのまま使わないのか

GitHub CLIには標準で、

gh auth git-credential

があります。

通常の単一アカウント運用ならこれで十分です。

ただ、複数アカウントを同一ホストgithub.comで使っている場合、「repository ownerに応じてどのgh accountを使うか」を明示的に制御したくなります。

今回のhelperでは、

remote URL
    ↓
ownerを抽出
    ↓
gh auth token --user owner

という非常に単純な規則にしているため、現在どのアカウントがghでactiveになっているかを意識する必要がありません。

この構成の利点

この方法だとPATそのものを.gitconfigに保存しません。

PATは必要になるたびに、

gh auth token --user ACCOUNT

から取得します。

そのため、設定として保存されるのは「どのアカウントを使うか」というルールだけです。

また、repositoryごとに、

gh auth switch

したり、

git config credential.username ...

を設定したりする必要もありません。

remote URLそのものがcredential routingの情報になります。

まとめ

複数GitHubアカウントをHTTPSで使う場合、

github.com/<account>/<repo>

account部分をそのままghのaccount選択に使うと、かなりシンプルに運用できます。

仕組みとしては、

Git remote URL
  ↓
credential.useHttpPath
  ↓
path=owner/repo.git
  ↓
ownerを抽出
  ↓
gh auth token --user owner
  ↓
username/passwordとしてGitへ返す

だけです。

個人アカウントを複数使っていて、

repository owner = GitHub account

という関係が成立している環境なら、かなり扱いやすい方法だと思います。

Organization配下のrepositoryなどで、

owner != 認証に使うaccount

となる場合だけは別途マッピングが必要ですが、個人アカウント中心ならまずこの構成で十分です。

DE
Source

This article was originally published by DEV Community and written by vast cow.

Read original article on DEV Community
Back to Discover

Reading List