适用读者:第一次把代码推到远端的人;以及
git push被拒、看不懂报错的人。
前置:S01-B07(终端可用)、S01-B09(工具可重建)。
实测环境:Ubuntu 24.04.1 / Git 2.43.0;本文两类被拒报错均为 2026-11-05 真实复现。
覆盖旧文:A-1400(Git 使用说明与配置,230 点)、A-1375(IDEA 配置 Git,52 点)+ A-1849 的 60 命令附录段(计入 B10 附录)。
上一篇:S01-B09 · 环境重置与迁移:干净卸载、清缓存、配置搬家
下一篇:S01-B11 · Git 托管与网络可达性。
1. 一句话结论
Git 只有四个位置:工作区 → 暂存区 → 本地仓库 → 远端仓库。90% 的困惑来自"我不知道东西现在在哪个位置"。
工作区 暂存区 本地仓库 远端
(你改的文件) (git add) (git commit) (git push)
│ │ │ │
│ git add ──────►│ │ │
│ │ git commit ───►│ │
│ │ │ git push ────►│
│ │ │◄──── git fetch │
│◄──────── git checkout / restore ──│ │
│ │◄── git reset ───│ │
git push 被拒,本质是"本地仓库和远端仓库的历史对不上"。搞清这一点,两种最常见的报错就不再神秘。
2. 安装与身份:user.name / user.email
git --version # 实测:git version 2.43.0
git config --global user.name "Zhang San"
git config --global user.email "[email protected]"
这两行不是可选项。 没有它们,git commit 会拒绝执行:
Author identity unknown
*** Please tell me who you are.
2.1 全局 vs 仓库级:优先级实测
Git 配置有三级:系统 /etc/gitconfig → 全局 ~/.gitconfig → 仓库 .git/config。就近覆盖。
$ cd /tmp/gitdemo/a
$ git config user.name A # 只改这个仓库
$ git config --show-origin --get user.name
file:.git/config A
--show-origin 会告诉你"这个值是从哪个文件读出来的"。当现场出现"我的提交作者不对",这一条命令就能定位到底是哪个配置在生效。
2.2 换行符:core.autocrlf(Windows 必看)
| 平台 | 建议设置 | 原因 |
|---|---|---|
| Windows | git config --global core.autocrlf true |
检出时转 CRLF,提交时转回 LF |
| macOS / Linux | git config --global core.autocrlf input |
提交时转 LF,检出保持 LF |
统一到 LF 存仓库是唯一正确的做法。不然会出现"我什么都没改,整个文件都是 diff"。
3. SSH 密钥:一次配置,长期免密
ls ~/.ssh/id_ed25519 || ssh-keygen -t ed25519 -C "[email protected]"
# 一路回车(密码短语可选,公司机器建议设)
eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub # 复制这一行,粘到 GitHub/Gitee/Gitcode 的 SSH Keys
为什么用 ed25519 而不是 RSA:更短、更快、更安全。RSA 只在对接老系统时才需要(且要用 4096 位)。旧文给的 RSA 步骤仍可用,但默认值应该换成 ed25519。
3.1 验证连通(真实报错)
$ ssh -T [email protected]
[email protected]: Permission denied (publickey).
这条就是"没配置好密钥"的标准报错(2026-11-05 实测复现)。三种原因,按概率排:
| 原因 | 验证 | 修法 |
|---|---|---|
| 公钥没粘到平台 | 平台的 SSH Keys 列表里有没有 | 复制 id_ed25519.pub 全文(含 ssh-ed25519 前缀)重新添加 |
| 本地有多个密钥,SSH 没选对 | ssh -vT [email protected] 看 Offering public key |
写 ~/.ssh/config 指定 IdentityFile(B11 详讲) |
| ssh-agent 里没有密钥 | ssh-add -l |
ssh-add ~/.ssh/id_ed25519 |
成功的输出长这样(各平台不同):
Hi username! You've successfully authenticated, but GitHub does not provide shell access.
4. 第一次闭环:从零到推送成功
4.1 两个起点
# A. 已有远端仓库
git clone [email protected]:user/repo.git
cd repo
# B. 本地已有代码
cd myproject
git init
git remote add origin [email protected]:user/repo.git
4.2 提交并推送
git status # 看哪些文件在"未跟踪/已修改"
git add . # 放进暂存区
git commit -m "feat: 初始化项目" # 提交到本地仓库
git push -u origin main # 推到远端;-u 记住上游,之后直接 git push
-u 的作用:把本地 main 和 origin/main 绑定,之后 git push / git pull 不用再写参数。
4.3 .gitignore 最小集(Java 项目)
# 构建产物
target/
build/
*.class
*.jar
# IDE
.idea/
*.iml
.vscode/
# 系统
.DS_Store
Thumbs.db
# 密钥与本地配置(绝不提交)
*.pem
*.key
.env
.idea/要不要提交是常见争议:团队若统一 Code Style(S01-B04 §5),可以只提交.idea/codeStyles/、.idea/encodings.xml这类约定类文件,忽略workspace.xml等个人类文件。判据与 B04 §1 一致。
5. 两种"被拒",处理方式完全不同
5.1 认证被拒:Permission denied (publickey)
见 §3.1。代码一行没动,纯环境问题。 判断特征:报错出现在建立连接阶段,还没到"推送"。
5.2 历史被拒:non-fast-forward(真实复现)
两个克隆各自提交,后推的会被拒:
$ git push origin master
To /tmp/gitdemo/remote.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to '/tmp/gitdemo/remote.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
这不是权限问题,是"远端有你本地没有的提交"。 修法二选一:
# 方案一(推荐,保留线性历史)
git pull --rebase origin master
git push origin master
# 方案二(产生 merge commit)
git pull origin master
git push origin master
实测修复后:
$ git log --oneline -3
de23350 second
c1a9bdf first
两个提交都在,历史线性。
绝对不要在团队仓库上用
git push -f解决这个问题——那会抹掉别人的提交。-f只在自己独占的分支(如个人 feature 分支)上才安全。进阶见 S01-J03。
5.3 一张对照表
| 报错关键词 | 类型 | 第一反应 |
|---|---|---|
Permission denied (publickey) |
认证 | 查密钥/agent/config |
[rejected] ... (fetch first) / non-fast-forward |
历史分叉 | pull --rebase 后重推 |
Updates were rejected because the tip of your current branch is behind |
同上 | 同上 |
fatal: refusing to merge unrelated histories |
两个独立根 | 确认后 --allow-unrelated-histories(谨慎) |
error: failed to push some refs + protected branch |
分支保护 | 走 MR/PR 流程(S01-J02) |
6. 在 IDEA 里配置 Git(A-1375)
Settings → Version Control → Git
Path to Git executable: 自动探测,或指向 /usr/bin/git、C:\Program Files\Git\cmd\git.exe
→ Test 按钮 ✅ 显示版本号即成功
常见问题:
| 现象 | 原因 | 修法 |
|---|---|---|
Test 按钮灰/失败 |
PATH 里没有 git,或指向了 git-bash.exe |
指到真正的 git.exe/git |
提交作者显示 unknown |
IDEA 用的 Git 与命令行不是同一个 | 统一到同一个可执行文件;再检查 user.name |
| 提交对话框里没有改动 | 文件被 ignore 或未加入 VCS | File → Settings → Version Control → Directory Mappings |
IDEA 的 Git 提交界面只是 add + commit 的封装。核心概念仍以命令行版为准——出问题时命令行是唯一可信的观察点。
7. 自检清单
| # | 检查 | 命令 | 预期 |
|---|---|---|---|
| 1 | 身份配好 | git config --show-origin --get user.email |
打印正确邮箱与来源文件 |
| 2 | 密钥存在 | ls ~/.ssh/id_ed25519.pub |
存在 |
| 3 | 平台认证通 | ssh -T [email protected] |
Hi <user>! You've successfully authenticated |
| 4 | 能克隆 | git clone <repo> |
成功 |
| 5 | 能推送 | 改一行 → add/commit/push |
远端可见 |
| 6 | 被拒能自解 | 故意制造分叉 | 能用 pull --rebase 修好 |
8. 旧文对照
| 旧文 | 内容 | 本篇处理 |
|---|---|---|
| A-1400 | Git 起源、三平台安装、配账户、生成 SSH 密钥、检出代码、IDEA 里检出/提交 | 保留为主干;密钥类型升级为 ed25519;补 ssh-agent、ssh -T 验证与真实报错 |
| A-1375 | IDEA 配置 Git(Path to Git executable + Test) | 压缩为 §6,补三类常见故障 |
| A-1849 的 60 命令段 | 完整命令清单(新建/配置/增删/提交/分支/远程/撤销…) | 移入附录思路:本篇只给"首次闭环"必需命令,完整命令表由 B11 附录与 J03 承接 |
| — | 旧文未讲"被拒的两种类型" | 新增 §5,含 2026-11-05 真实复现的两段报错 |
| — | 未讲 core.autocrlf 与 .gitignore 最小集 |
新增 §2.2、§4.3 |
9. 自测
Permission denied (publickey)与[rejected] (fetch first)分别属于哪一层问题?各用哪条命令先看?git push -u origin main里的-u做了什么?- 为什么团队仓库不能用
git push -f解决分叉? .idea/目录该不该提交?判据是什么?git config --show-origin在什么场景下能救你?
10. 下一篇
S01-B11 · Git 托管与网络可达性:GitHub / Gitee / Gitcode
能提交了,下一个问题往往是"连不上"。下一篇把 GitHub / Gitee / Gitcode 三家的差异、ssh -vT 的分层排障、以及 22 端口被封时改 443 的做法讲清楚,并给出一台机器同时配三个平台的 ~/.ssh/config 写法。
本篇属于系列《S01 · 开发环境与工具链》。旧文来源:A-1400、A-1375、A-1849(附录段);报错文本为 2026-11-05 实测复现。