🛠️ 为什么配置 ~/.ssh/config 后,Sourcetree 就能正常推送了?

💡 出现的问题

我在 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

它的作用是:

  1. 将密钥加入 ssh-agent
  2. 同时把 passphrase 写入 macOS 钥匙串(Keychain)
  3. 下次系统启动或 SSH 需要该密钥时,自动从钥匙串取出密码解锁

💡 你可以打开 "钥匙串访问" App,搜索 ssh,就能看到一条名为
SSH: /Users/xxx/.ssh/id_ed25519 的记录!


🔄 整个工作流程(Sourcetree 推送时)

  1. Sourcetree 执行 git push → 触发 ssh git@gitee.com
  2. SSH 客户端读取 ~/.ssh/config,匹配到 Host gitee.com
  3. 使用指定的私钥 ~/.ssh/id_ed25519
  4. 发现私钥有 passphrase,于是查询 macOS 钥匙串
  5. 从钥匙串中自动获取 passphrase,解锁私钥
  6. 完成 SSH 认证,推送成功 ✅

整个过程无需人工干预,GUI 应用也能像终端一样使用带密码的 SSH 密钥!


✅ 为什么这个方案如此优雅?

优势 说明
一次配置,永久生效 重启电脑后依然有效
所有 GUI 工具通用 Sourcetree、VS Code、WebStorm、Terminal 均受益
安全性高 passphrase 由系统级钥匙串保护,不暴露在脚本或环境变量中
符合 macOS 设计哲学 利用系统原生安全机制,而非 hack 方式

🛠️ 操作步骤总结(供读者复现)

  1. 确保已生成 SSH 密钥(带 passphrase)

    perl 复制代码
    ssh-keygen -t ed25519 -C "your@email.com"
  2. 将公钥添加到 Gitee/GitHub

  3. 创建或编辑 ~/.ssh/config

    javascript 复制代码
    nano ~/.ssh/config

    添加:

    bash 复制代码
    Host gitee.com
      IdentityFile ~/.ssh/id_ed25519
      AddKeysToAgent yes
      UseKeychain yes
  4. 将密钥加入钥匙串

    bash 复制代码
    ssh-add -K ~/.ssh/id_ed25519
    # 输入你的 passphrase
  5. 重启 Sourcetree(完全退出再打开)

  6. 愉快地推送吧! 🎉


📌 补充:多账号支持

如果你有多个 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

希望这篇博客能帮到更多开发者!如果你觉得有用,欢迎点赞、收藏、转发 💙

相关推荐
Sylus_sui2 小时前
Vue2 与 Vue3 数据双向绑定:区别与原理详解
前端·javascript·vue.js
ConardLi2 小时前
AI:我裂开了!现在的大模型评测究竟有多变态?
前端·人工智能·后端
这是你的玩具车吗2 小时前
能和爸妈讲明白的大模型原理
前端·人工智能·机器学习
霍理迪3 小时前
CSS文本样式
前端·css
Ashley_Amanda3 小时前
JavaScript 中 JSON 的处理方法
前端·javascript·json
烛阴3 小时前
C# 正则表达式(3):分组与捕获——从子串提取到命名分组
前端·正则表达式·c#
eason_fan4 小时前
从一则内存快照看iframe泄漏:活跃与Detached状态的回收差异
前端·性能优化
狗头大军之江苏分军4 小时前
年底科技大考:2025 中国前端工程师的 AI 辅助工具实战盘点
java·前端·后端
编程修仙5 小时前
第三篇 Vue路由
前端·javascript·vue.js