一台电脑,两个 Git 身份:公司 GitLab + 个人 GitHub 共存

2 阅读8分钟

概述

用公司电脑写个人项目,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 配置文件:

  • WindowsC:\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 gitSSH 用户名,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

  1. 打开浏览器,登录 GitHub
  2. 点击右上角头像 → Settings
  3. 左侧菜单找到 SSH and GPG keys
  4. 点击 New SSH key
  5. Title:随便填个名字,比如 work-laptop
  6. Key:粘贴刚才复制的公钥内容
  7. 点击 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 配置

打开全局配置文件:

  • WindowsC:\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 上创建仓库

  1. 打开 GitHub → 点击右上角 +New repository
  2. 填写仓库名(如 obsidian
  3. 不要勾选任何初始化选项(不要添加 README、.gitignore 等)
  4. 点击 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