概述
用公司电脑写个人项目,git log 里却全是公司邮箱?推送到 GitHub 却提示权限拒绝?这是每个同时使用公司 GitLab 和个人 GitHub 的开发者都会遇到的问题。
本文基于一次真实的配置过程,采用 SSH 多密钥 + Git 条件包含 方案,实现不同目录自动切换 Git 身份。从密钥生成到推送成功,包含完整步骤、原理图解,以及公司网络下端口被封、Host Key 验证失败等实际踩坑的解决方案。
你也可以将当前网页保存,然后用Claudecode参考这个网页内容直接完成。
适用场景:公司 GitLab + 个人 GitHub 并存(也适用于任意两个 Git 平台的多账号管理)
阅读时间:约 10 分钟 | 配置时间:约 15 分钟
需求场景
graph LR
A["你的电脑"] --> B["公司项目<br/>(任意目录)"]
A --> C["个人项目<br/>(指定目录)"]
B -->|公司密钥 + 公司邮箱| D["公司 GitLab"]
C -->|个人密钥 + 个人邮箱| E["个人 GitHub"]
style B fill:#4A90D9,color:#fff
style C fill:#7B68EE,color:#fff
style D fill:#FC6D26,color:#fff
style E fill:#238636,color:#fff
配置前的准备
在开始之前,请先确认你有以下信息:
| 信息 | 示例 | 你的值 |
|---|---|---|
| 公司 GitLab 地址 | git.company.com | ______ |
| 公司邮箱 | zhangsan@company.com | ______ |
| 公司 Git 用户名 | zhangsan | ______ |
| 个人 GitHub 邮箱 | zhangsan@qq.com | ______ |
| 个人 GitHub 用户名 | zhangsan | ______ |
| 个人项目目录 | D:/obsidian/ | ______ |
下面的步骤以 Windows 为例。macOS/Linux 路径稍有不同,会在对应步骤标注。
Step 1: 生成个人 SSH 密钥
打开 Git Bash,执行:
ssh-keygen -t ed25519 -C "你的个人邮箱" -f ~/.ssh/id_ed25519_personal
会提示输入密码(passphrase),直接按两次回车跳过即可。
执行成功后会在 ~/.ssh/ 目录下生成两个文件:
id_ed25519_personal— 私钥(不要给任何人)id_ed25519_personal.pub— 公钥(后面要添加到 GitHub)
注意:如果你还没有公司的 SSH 密钥,也用类似命令生成一份:
ssh-keygen -t ed25519 -C "你的公司邮箱" -f ~/.ssh/id_ed25519
Step 2: 配置 SSH config
创建或编辑 SSH 配置文件:
- Windows:
C:\Users\你的用户名\.ssh\config - macOS/Linux:
~/.ssh/config
写入以下内容(根据你的实际信息修改):
# ====================================
# 公司 GitLab(使用公司密钥)
# ====================================
Host git.company.com
HostName git.company.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
# ====================================
# 个人 GitHub(使用个人密钥)
# ====================================
Host github-personal
HostName ssh.github.com
Port 443
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes
逐行解释:
| 配置项 | 含义 |
|---|---|
Host | 给这个连接起个别名,后面 git 操作会用到 |
HostName | 实际连接的服务器地址 |
Port 443 | 使用 443 端口(很多公司网络封了默认的 22 端口,443 端口更通用) |
User git | SSH 用户名,Git 服务固定为 git |
IdentityFile | 指定使用哪个私钥文件 |
IdentitiesOnly yes | 只使用指定的密钥,不尝试其他密钥 |
为什么 GitHub 用
ssh.github.com和 443 端口? 很多公司防火墙会封锁 22 端口,导致ssh -T git@github.com超时。 GitHub 官方提供了 443 端口的替代方案,用ssh.github.com即可绕过限制。 如果你不在公司网络环境下,也可以用标准配置:Host github-personal HostName github.com User git IdentityFile ~/.ssh/id_ed25519_personal IdentitiesOnly yes
Step 3: 把个人公钥添加到 GitHub
3.1 复制公钥内容
cat ~/.ssh/id_ed25519_personal.pub
会输出类似这样的一行内容(选中并复制):
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...... your@email.com
3.2 添加到 GitHub
- 打开浏览器,登录 GitHub
- 点击右上角头像 → Settings
- 左侧菜单找到 SSH and GPG keys
- 点击 New SSH key
- Title:随便填个名字,比如
work-laptop - Key:粘贴刚才复制的公钥内容
- 点击 Add SSH key
公司 GitLab 同理:如果还没添加过公司密钥,把
~/.ssh/id_ed25519.pub的内容添加到 GitLab 的 SSH Keys 设置中。
Step 4: 添加 GitHub 的 Host Key
首次连接 GitHub 时,SSH 需要确认服务器身份。提前添加可以避免后续报错:
ssh-keyscan -p 443 ssh.github.com >> ~/.ssh/known_hosts 2>/dev/null
如果你在 Step 2 中用的是标准 22 端口配置,则执行:
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
Step 5: 测试 SSH 连接
# 测试个人 GitHub
ssh -T git@github-personal
# 测试公司 GitLab
ssh -T git@git.company.com
期望结果:
# GitHub 成功输出(退出码 1 是正常的):
Hi 你的用户名! You've successfully authenticated, but GitHub does not provide shell access.
# GitLab 成功输出:
Welcome to GitLab, 你的名字!
如果失败了怎么办? 见文末 常见问题 。
Step 6: 配置 Git 用户身份(条件包含)
目标:不同目录自动使用不同的用户名和邮箱,无需手动切换。
6.1 编辑全局 Git 配置
打开全局配置文件:
- Windows:
C:\Users\你的用户名\.gitconfig - macOS/Linux:
~/.gitconfig
确保文件中有以下内容(在文件末尾添加 includeIf 部分):
[user]
name = 公司用户名
email = 公司邮箱@company.com
# 当在个人项目目录下操作时,自动加载个人配置
[includeIf "gitdir:D:/obsidian/"]
path = ~/.gitconfig-personal
macOS/Linux 路径写法不同:
[includeIf "gitdir:~/obsidian/"] path = ~/.gitconfig-personal
注意:
gitdir:后面的路径末尾必须带/,否则不会生效。
6.2 创建个人配置文件
新建文件 ~/.gitconfig-personal(跟 .gitconfig 同目录),写入:
[user]
name = 你的GitHub用户名
email = 你的个人邮箱
6.3 验证配置是否生效
# 在个人项目目录下
cd D:/obsidian
git init # 如果还不是 git 仓库的话
git config user.name
git config user.email
# 应该输出你的个人用户名和个人邮箱
# 在公司项目目录下
cd /path/to/company/project
git config user.email
# 应该输出你的公司邮箱
Step 7: 初始化个人仓库并推送
7.1 在 GitHub 上创建仓库
- 打开 GitHub → 点击右上角 + → New repository
- 填写仓库名(如
obsidian) - 不要勾选任何初始化选项(不要添加 README、.gitignore 等)
- 点击 Create repository
为什么不要勾选初始化选项? 如果 GitHub 自动创建了一个
master分支(带 README),而你本地也创建了提交, 两边的 Git 历史是独立的,推送时会遇到refusing to merge unrelated histories错误,需要额外处理。 空仓库则不会有这个问题。
7.2 本地初始化并推送
cd D:/obsidian
# 初始化 Git 仓库
git init
# 添加远程仓库(注意用 github-personal,不是 github.com)
git remote add origin git@github-personal:你的用户名/仓库名.git
# 添加所有文件并提交
git add .
git commit -m "chore: 初始化仓库"
# 推送到远程(首次推送需要 -u 设置上游分支)
git push -u origin master
关键点:远程地址中用
github-personal而不是github.com。 这样 SSH 才会匹配到 Step 2 中配置的个人密钥。
7.3 后续日常推送
首次推送设置了 -u 之后,以后只需:
cd D:/obsidian
git add .
git commit -m "你的提交信息"
git push
完整配置文件参考
~/.ssh/config
# 公司 GitLab
Host git.company.com
HostName git.company.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
# 个人 GitHub(443 端口,适配公司网络)
Host github-personal
HostName ssh.github.com
Port 443
User git
IdentityFile ~/.ssh/id_ed25519_personal
IdentitiesOnly yes
~/.gitconfig
[user]
name = 公司用户名
email = 公司邮箱@company.com
[includeIf "gitdir:D:/obsidian/"]
path = ~/.gitconfig-personal
~/.gitconfig-personal
[user]
name = GitHub用户名
email = 个人邮箱
常见问题
Q1: ssh -T 超时(Connection timed out)
原因:公司网络封了 22 端口。
解决:在 ~/.ssh/config 中将 GitHub 配置改为 443 端口:
Host github-personal
HostName ssh.github.com
Port 443
...
Q2: Host key verification failed
原因:首次连接服务器,SSH 不认识对方身份。
解决:手动添加服务器的 host key:
# GitHub(443 端口)
ssh-keyscan -p 443 ssh.github.com >> ~/.ssh/known_hosts 2>/dev/null
# GitHub(22 端口)
ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null
# 公司 GitLab
ssh-keyscan git.company.com >> ~/.ssh/known_hosts 2>/dev/null
Q3: Permission denied (publickey)
排查步骤:
# 1. 查看详细连接日志
ssh -vT git@github-personal
# 2. 确认密钥文件存在
ls -la ~/.ssh/id_ed25519_personal*
# 3. 确认公钥已添加到 GitHub(对比本地公钥和 GitHub 设置页面的内容)
cat ~/.ssh/id_ed25519_personal.pub
Q4: refusing to merge unrelated histories
原因:GitHub 上创建仓库时勾选了初始化选项(生成了 README),导致远程和本地是两个独立的 Git 历史。
解决:
# 先拉取远程分支
git fetch origin
# 合并时允许不相关历史
git merge origin/master --allow-unrelated-histories -m "merge: 合并远程分支"
# 推送
git push
建议:创建 GitHub 仓库时不要勾选任何初始化选项,可以避免这个问题。
Q5: git config user.email 显示的还是公司邮箱
排查步骤:
# 1. 确认当前目录
pwd
# 2. 确认目录是个 git 仓库(必须有 .git 目录,条件包含才会生效)
git status
# 3. 检查 .gitconfig 中 includeIf 的路径是否正确(末尾要有 /)
cat ~/.gitconfig
# 4. 手动设置(仅当前仓库,作为兜底方案)
git config user.name "你的GitHub用户名"
git config user.email "你的个人邮箱"
原理小结
整体架构
graph TB
subgraph 你的电脑
subgraph SSH 层 ["SSH 层(~/.ssh/config)"]
KEY1["id_ed25519<br/>公司密钥"]
KEY2["id_ed25519_personal<br/>个人密钥"]
end
subgraph Git 身份层 ["Git 身份层(条件包含)"]
GC[".gitconfig<br/>公司身份(默认)"]
GP[".gitconfig-personal<br/>个人身份"]
end
subgraph 项目目录
P1["公司项目<br/>C:/work/project/"]
P2["个人项目<br/>D:/obsidian/"]
end
end
subgraph 远程服务器
GITLAB["公司 GitLab<br/>git.company.com"]
GITHUB["个人 GitHub<br/>github.com:443"]
end
P1 --> GC
P2 -->|"includeIf gitdir:D:/obsidian/"| GP
GC --> KEY1
GP --> KEY2
KEY1 -->|"Host: git.company.com"| GITLAB
KEY2 -->|"Host: github-personal"| GITHUB
style KEY1 fill:#4A90D9,color:#fff
style KEY2 fill:#7B68EE,color:#fff
style GC fill:#4A90D9,color:#fff
style GP fill:#7B68EE,color:#fff
style P1 fill:#4A90D9,color:#fff
style P2 fill:#7B68EE,color:#fff
style GITLAB fill:#FC6D26,color:#fff
style GITHUB fill:#238636,color:#fff
git push 执行流程
以在 D:/obsidian/ 目录下执行 git push 为例:
sequenceDiagram
participant U as 你
participant Git as Git
participant Config as .gitconfig
participant SSH as SSH
participant GH as GitHub
U->>Git: git push
Git->>Config: 读取全局配置(公司身份)
Config->>Config: 检查 includeIf 条件
Note over Config: 当前目录 D:/obsidian/<br/>匹配 gitdir:D:/obsidian/
Config->>Git: 加载 .gitconfig-personal<br/>覆盖为个人身份
Git->>SSH: 连接 github-personal
SSH->>SSH: 匹配 ~/.ssh/config 中的<br/>Host github-personal
SSH->>SSH: 使用 id_ed25519_personal 密钥
SSH->>GH: SSH 连接 ssh.github.com:443
GH->>GH: 验证公钥
GH-->>SSH: 认证成功
SSH-->>Git: 连接建立
Git->>GH: 推送代码(身份: 个人邮箱)
GH-->>U: 推送完成
概述
用公司电脑写个人项目,git log 里却全是公司邮箱?推送到 GitHub 却提示权限拒绝?这是每个同时使用公司 GitLab 和个人 GitHub 的开发者都会遇到的问题。
本文基于一次真实的配置过程,采用 SSH 多密钥 + Git 条件包含 方案,实现不同目录自动切换 Git 身份。从密钥生成到推送成功,包含完整步骤、原理图解,以及公司网络下端口被封、Host Key 验证失败等实际踩坑的解决方案。
适用场景:公司 GitLab + 个人 GitHub 并存(也适用于任意两个 Git 平台的多账号管理)
阅读时间:约 10 分钟 | 配置时间:约 15 分钟
graph LR
subgraph SSH配置
SC["~/.ssh/config"]
K1["~/.ssh/id_ed25519"]
K2["~/.ssh/id_ed25519_personal"]
SC -->|"公司 Host"| K1
SC -->|"个人 Host"| K2
end
subgraph Git配置
GC["~/.gitconfig"]
GP["~/.gitconfig-personal"]
GC -->|"includeIf<br/>目录匹配时加载"| GP
end
subgraph 远程平台
GL["GitLab<br/>添加 id_ed25519.pub"]
GH["GitHub<br/>添加 id_ed25519_personal.pub"]
end
K1 -.->|公钥认证| GL
K2 -.->|公钥认证| GH
style SC fill:#f5f5f5,stroke:#333
style GC fill:#f5f5f5,stroke:#333
style GP fill:#f5f5f5,stroke:#333
style GL fill:#FC6D26,color:#fff
style GH fill:#238636,color:#fff
配置步骤总览
flowchart TB
S1["Step 1<br/>生成个人 SSH 密钥"]
S2["Step 2<br/>编写 SSH config"]
S3["Step 3<br/>公钥添加到 GitHub"]
S4["Step 4<br/>添加 Host Key"]
S5["Step 5<br/>测试 SSH 连接"]
S6["Step 6<br/>配置 Git 条件包含"]
S7["Step 7<br/>初始化仓库并推送"]
S1 --> S2 --> S3 --> S4 --> S5
S5 -->|成功| S6 --> S7
S5 -->|失败| FAQ["查看常见问题排查"]
FAQ -.-> S5
style S1 fill:#4A90D9,color:#fff
style S2 fill:#4A90D9,color:#fff
style S3 fill:#4A90D9,color:#fff
style S4 fill:#4A90D9,color:#fff
style S5 fill:#7B68EE,color:#fff
style S6 fill:#238636,color:#fff
style S7 fill:#238636,color:#fff
style FAQ fill:#D9534F,color:#fff