Zero runtime. Pure config.

Stop getting Permission denied on the wrong account.

sshift writes your ~/.ssh/config so each Git host uses the right key. Then it gets out of the way — native git, native SSH, no wrapper. sshift 帮你写好 ~/.ssh/config,让不同 Git host 走正确的 key。之后还是原生 git 和 SSH,不包命令、不常驻。

Install

$ curl -fsSL https://th1humble.github.io/sshift/install.sh | sh

Installs to ~/.local/bin. No sudo needed. 默认安装到 ~/.local/bin,通常不需要 sudo。 macOS and Linux only for now. 暂不支持 Windows。

$ sshift doctor
 
Repository
origin: git@github.com:th1humble/sshift.git
host: github.com
 
Matched Profile
name: github-com-th1humble
key: ~/.ssh/id_ed25519_github_com
 
SSH Auth
ok: Authenticated as Th1Humble
 

The actual pain

You already have a working company setup. Adding a personal GitHub key shouldn't break it. 公司 Git 已经能用时,再加个人 GitHub,不应该把现有配置搞乱。

Without sshift

You clone a personal repo on your work laptop. Permission denied (publickey). You Google the SSH config format, paste something in, try again. It works — but then you push a commit and realize the author says work@example.com. Already on GitHub. Can't undo.

在公司电脑 clone 个人仓库,Permission denied。查了半天 SSH config 格式,终于通了——结果 push 上去才发现 commit 邮箱是公司的,已经推上去了。
$ git push
Permission denied (publickey).

# 30 minutes later...
$ git log --oneline -1
a1b2c3d feat: add feature (work@example.com)

With sshift

Add a profile, sshift writes the config. Clone works immediately. Run sshift doctor in any repo to confirm which key and identity it uses.

加一个 profile,config 自动写好。clone 直接通。doctor 随时确认当前 repo 用的是哪个 key。
$ sshift add        # 3 questions, done
$ git clone git@github.com:me/repo.git
$ sshift doctor     # confirms: right key, right author

How it works

Configure once, then forget sshift exists. It doesn't run during git operations. 配置一次,之后继续正常用 git。git 操作时不需要 sshift 参与。

1

Add identities

Pick a host (GitHub, GitLab, or custom), name your account, generate or select a key.

选平台、填账号、生成或选择 key。
2

Config is written

sshift writes a managed block in ~/.ssh/config. A backup is created first. Your existing config stays untouched.

写入受管理块,已有配置不动,写入前备份。
3

Use git normally

git clone, push, pull — OpenSSH reads the config and picks the right key. sshift is not involved.

正常用 git。OpenSSH 读 config 选 key,sshift 不参与。

What sshift does NOT do

  • Wrap or intercept git commands不包装、不拦截 git 命令
  • Run as a background daemon不作为后台进程常驻
  • Read or store private key content不读取、不存储私钥内容
  • Manage ssh-agent不接管 ssh-agent

Common scenarios

Works for both a fresh machine and an already-configured work laptop. 新电脑能从零配置;已有工作电脑也能增量接入。

New computer

Start from zero. Add all your identities in one session.

新电脑从零开始,一次加完所有身份。
$ sshift add
? Host template → GitHub
? Account       → th1humble
? Generate key? → Yes
✓ Public key printed — add to GitHub

? Add another?  → Yes
? Host template → GitLab
...

✓ SSH config applied.

Existing work laptop

Company config already works. Add GitHub without touching it.

公司配置已经好了,增量加 GitHub 不影响现有的。
$ sshift scan
SSH Keys (2 found)
  ~/.ssh/id_ed25519       (company)
  ~/.ssh/id_rsa           (legacy)
SSH Config: 1 host (unmanaged)

$ sshift add
# adds GitHub profile only
# company config untouched

$ sshift doctor
  ok: Authenticated as Th1Humble

Check author before committing

Run doctor first. Bind only if the current repo author does not match the profile.

提交前先跑 doctor 看当前仓库身份;不一致时,再决定是否 bind。
$ sshift doctor
  Git Identity
  local: (unset)
  global: dev <work@example.com>
  profile: Th1Humble <personal@example.com>
  ⚠ mismatch with profile
  Run: sshift bind github-com-th1humble

$ sshift bind github-com-th1humble
✓ New commits in this repo use:
  user.name  = Th1Humble
  user.email = personal@example.com

Something broke

Roll back to the previous SSH config in one command.

出问题了?一条命令回滚。
$ sshift rollback
Restored ~/.ssh/config from backup
  2026-05-18T14:30:22

$ ssh -T git@github.com
Hi Th1Humble! You've successfully
authenticated.

Safety guarantees

SSH keys are sensitive. sshift keeps private key handling entirely in native OpenSSH. SSH key 很敏感。sshift 只维护配置,私钥处理仍然交给原生 OpenSSH。

  • Never uploads keys永不上传 key
  • Never reads private key content永不读取私钥内容
  • Only records file paths只记录路径
  • Fingerprints from public keys only指纹仅来自公钥
  • Backup before every write每次写入前备份
  • Reversible via sshift rollback随时可回滚
  • Only edits its own managed block只改自己的受管理块
  • Native OpenSSH + Git only只用原生 SSH 和 Git