xsh Library - git.
Utilities for working with git and GitHub from the shell, packaged as an
xsh library.
About xsh and its libraries, check out the xsh document.
Tested with bash:
- 5.x and 4.x on Linux (ubuntu-latest in CI)
- 3.2.57 on macOS (macos-latest in CI)
This project is still at version 0.x and should be considered immature.
-
xsh-lib/core — should be loaded before this library.
xsh load xsh-lib/core
-
Some utilities have additional dependencies (e.g.
gh,ssh,w3m,collaborator). See the per-utility help for details.
Assume xsh is already installed.
To load this library into xsh:
xsh load xsh-lib/gitThe loaded library is referenced by the name git.
The leading slash in an LPUR (e.g.
xsh /string/upper) is reserved for the default libraryxsh-lib/core. For this library, write the lib name explicitly:xsh git/<package>/<util>.
List the utilities exposed by this library:
xsh list gitGet help on any utility:
xsh help git/<package>/<util>| Utility | Kind | Purpose |
|---|---|---|
git/hub/account-for-email |
function | Walk XSH_GIT_HUB_ACCOUNTS, return the account whose email matches. |
git/hub/account-for-org |
function | Walk XSH_GIT_HUB_ACCOUNTS, return the account that defaults for the given GitHub org. First-match-wins. |
git/hub/account-for-repo |
function | Derive the account from git config user.email in the current repo (delegates to account-for-email). |
git/hub/run |
function | Run a command with a chosen gh account active, isolated from concurrent shell sessions via per-call GH_CONFIG_DIR. |
git/hub/ssh |
script | SSH wrapper for core.sshCommand: picks the right per-account key from the repo owner in git's command line. |
git/hub/collaborator |
function | Add, remove, or list collaborators of the current GitHub repo. Requires collaborator and w3m. |
git/rebase-i-in-dumb-term |
script | Helper for running git rebase -i in dumb terminals. |
The git/hub/* utilities read a single env var that describes every gh
account you operate. Whitespace-separated records, each with three
colon-separated fields:
<account> : <email> : <org>[,<org>...]
| Field | Cardinality | Meaning |
|---|---|---|
account |
required | gh account name; also the suffix in ~/.ssh/github-<account>. |
email |
0..1 | Email tied to this account by ~/.gitconfig includeIf rules. Empty for bot-style accounts with no per-directory binding. |
orgs |
0..N | Comma-separated GitHub orgs this account defaults for. Read by account-for-org and git/hub/ssh. |
Example:
export XSH_GIT_HUB_ACCOUNTS="alice:alice@example.com:alice,xsh-alice bob:bob@corp.io:bob-corp"If two records list the same org, first match wins — the earlier
record's account becomes the default for that org. The other account is
still reachable via the explicit SSH alias URL
git@github-<account>:<org>/<repo>.git.
If you operate multiple GitHub accounts simultaneously (e.g. personal +
work) and rely on ~/.gitconfig's includeIf "gitdir:..." rules to switch
identities per directory tree, this library makes it transparent to push,
PR, and clone against the right account without ever mutating the global
active account in ~/.config/gh.
-
Map your accounts via the env var described above.
-
Use
git/hub/runas a transparent wrapper around anyghcommand (account auto-derived from the current repo'suser.email):xsh git/hub/run -- gh pr create --fill xsh git/hub/run -u alice-corp -- gh pr list # explicit overrideEach call snapshots
~/.config/ghto a private mode-700 tempdir, runsgh auth switch -u <account>against the copy, and exportsGH_CONFIG_DIRonly for the wrapped command. The real config is never mutated, so other shell sessions and credential-helper invocations are unaffected — even when severalgit/hub/runcalls are in flight at the same time. -
Wire
git/hub/sshinto git for transparent SSH routing on baregit@github.com:<org>/<repo>.gitURLs:xsh imports git/hub/ssh git config --global core.sshCommand git-hub-ssh
Now
git clone git@github.com:<org>/<repo>.git(orgh repo clone, or the web "Clone with SSH" copy-paste) auto-resolves to the right~/.ssh/github-<account>key — without rewriting the URL stored in the clonedorigin. SSH key selection happens in the wrapper based on the org parsed from git'sgit-{upload,receive}-packcommand line.The wrapper falls through to plain
sshfor any host that isn'tgit@github.com(CodeCommit, EC2, the per-accountgithub-<name>aliases, etc.) and for any org that isn't inXSH_GIT_HUB_ACCOUNTS— letting your existing SSH config handle those cases unchanged.
Run the test suite:
xsh load xsh-lib/git
bash test.shFor local iteration against a working copy that hasn't been pushed yet, link
the workspace as a development library and re-run with XSH_DEV=1:
xsh lib-dev-manager link xsh-lib/git /path/to/parent-of-this-repo
XSH_DEV=1 bash test.shNetwork-dependent tests (real gh round-trips) are skipped by default.
Enable them with XSH_GIT_TEST_NETWORK=1 once you have a logged-in gh
account available.
CI runs the same test.sh on ubuntu-latest and macos-latest for every
push and PR. See the
ci-unittest workflow.