💡 出现的问题
我在 macOS 上开发 HarmonyOS 应用,使用 Sourcetree 管理 Git 代码,并通过 SSH 推送到 Gitee 仓库:
scss
git@gitee.com:jc/testDemo.git
一切看起来都配置好了:
- 已生成 Ed25519 SSH 密钥(带 passphrase)
- 公钥已添加到 Gitee
- 终端中
ssh -T git@gitee.com测试成功 - 终端中
git push也能正常推送
但唯独 Sourcetree 一点击"推送",就报错:
scss
git@gitee.com: Permission denied (publickey).
fatal: Could not read from remote repository.
这让我非常困惑:为什么终端能推,Sourcetree 却不行?
🔍 查找问题根源:GUI 应用无法访问 SSH 密码
我的私钥 ~/.ssh/id_ed25519 是带密码(passphrase)保护的 。
当 SSH 客户端使用它时,必须提供这个密码才能解锁。
- ✅ 在终端中 :我运行过
ssh-add ~/.ssh/id_ed25519,密码被缓存在ssh-agent中,所以git push成功。 - ❌ 在 Sourcetree 中 :作为 GUI 应用,它无法访问终端的
ssh-agent,也无法弹出密码输入框 → 直接失败。
这就是典型的 "macOS GUI 应用与 SSH 密钥权限隔离" 问题。
✅ 突破口:配置 ~/.ssh/config
为了解决这个问题,我在 ~/.ssh/config 文件中添加了以下内容:
bash
Host gitee.com
IdentityFile ~/.ssh/id_ed25519
AddKeysToAgent yes
UseKeychain yes
并执行了一条关键命令:
javascript
ssh-add -K ~/.ssh/id_ed25519
奇迹发生了:Sourcetree 立刻可以正常推送了!
那么,这一切是怎么发生的?
📚 ~/.ssh/config 是什么?
~/.ssh/config 是 OpenSSH 客户端的用户级配置文件,用于为不同主机(Host)定义连接参数。
它的作用类似于"SSH 的路由规则"------当你连接某个服务器时,SSH 会自动读取该文件,应用对应的设置。
例如:
- 指定私钥路径
- 设置别名(如
Host myserver→ 实际连user@192.198.1.100) - 启用代理、端口转发等高级功能
在 macOS 上,它还有一个隐藏超能力:与系统钥匙串(Keychain)集成。
🔑 关键配置项解析
1. Host gitee.com
- 表示:当连接
gitee.com时,应用以下规则 - 注意:这里写的是
gitee.com,不是git@gitee.com,也不是完整 URL
2. IdentityFile ~/.ssh/id_ed25519
- 明确指定使用哪个私钥文件
- 避免 SSH 自动尝试多个密钥(如
id_rsa,id_ecdsa等),提高效率和确定性
3. AddKeysToAgent yes
- 如果密钥尚未加载到
ssh-agent,自动加载 - 确保密钥始终可用
4. UseKeychain yes(macOS 特有!)
- 核心魔法所在!
- 告诉 OpenSSH:把 passphrase 存储在 macOS 系统钥匙串(Keychain)中
- 之后任何应用(包括 Sourcetree、VS Code、IDEA)在需要时,都能通过系统安全机制自动获取密码
🔐 ssh-add -K:把密码存进钥匙串
普通 ssh-add 只是把密钥加载到内存中的 ssh-agent,重启后就没了。
而 -K 参数是 macOS 特有的扩展:
javascript
ssh-add -K ~/.ssh/id_ed25519
它的作用是:
- 将密钥加入
ssh-agent - 同时把 passphrase 写入 macOS 钥匙串(Keychain)
- 下次系统启动或 SSH 需要该密钥时,自动从钥匙串取出密码解锁
💡 你可以打开 "钥匙串访问" App,搜索
ssh,就能看到一条名为
SSH: /Users/xxx/.ssh/id_ed25519的记录!
🔄 整个工作流程(Sourcetree 推送时)
- Sourcetree 执行
git push→ 触发ssh git@gitee.com - SSH 客户端读取
~/.ssh/config,匹配到Host gitee.com - 使用指定的私钥
~/.ssh/id_ed25519 - 发现私钥有 passphrase,于是查询 macOS 钥匙串
- 从钥匙串中自动获取 passphrase,解锁私钥
- 完成 SSH 认证,推送成功 ✅
整个过程无需人工干预,GUI 应用也能像终端一样使用带密码的 SSH 密钥!
✅ 为什么这个方案如此优雅?
| 优势 | 说明 |
|---|---|
| 一次配置,永久生效 | 重启电脑后依然有效 |
| 所有 GUI 工具通用 | Sourcetree、VS Code、WebStorm、Terminal 均受益 |
| 安全性高 | passphrase 由系统级钥匙串保护,不暴露在脚本或环境变量中 |
| 符合 macOS 设计哲学 | 利用系统原生安全机制,而非 hack 方式 |
🛠️ 操作步骤总结(供读者复现)
-
确保已生成 SSH 密钥(带 passphrase)
perlssh-keygen -t ed25519 -C "your@email.com" -
将公钥添加到 Gitee/GitHub
-
创建或编辑
~/.ssh/configjavascriptnano ~/.ssh/config添加:
bashHost gitee.com IdentityFile ~/.ssh/id_ed25519 AddKeysToAgent yes UseKeychain yes -
将密钥加入钥匙串
bashssh-add -K ~/.ssh/id_ed25519 # 输入你的 passphrase -
重启 Sourcetree(完全退出再打开)
-
愉快地推送吧! 🎉
📌 补充:多账号支持
如果你有多个 Gitee/GitHub 账号,可以这样配置:
bash
# Gitee 个人账号
Host gitee-personal
HostName gitee.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
UseKeychain yes
AddKeysToAgent yes
# GitHub 工作账号
Host github-work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_work
UseKeychain yes
AddKeysToAgent yes
然后远程地址改为:
kotlin
git remote set-url origin git@gitee-personal:username/repo.git