Git 项目管理
从一个人写代码,到一群人写代码
不背术语、不啃文档。用生活里的比喻把 Git 讲明白,再把单人开发和团队协作两个场景,从头到尾完整走一遍。
00开场:为什么非学 Git 不可核心
先讲清楚"不用 Git 会有多惨",后面每一个命令你才会觉得是刚需,而不是负担。
先看一个大家都经历过的场景 —— 交毕业论文的时候,你的文件夹是不是长这样:
📁 我的论文/
论文.docx
论文_修改版.docx
论文_修改版2.docx
论文_最终版.docx
论文_最终版_真的最终版.docx
论文_最终版_听导师的改完了.docx
论文_最终版_这次真的不改了.docx ← 现在告诉我,哪个是最新的?
论文_备份_20260731.docx ← 这个跟上面那个差在哪?
你能想起来"这次真的不改了"和"听导师的改完了"之间,到底改了哪几段吗?想不起来。而写代码的时候,这个问题会放大一百倍:
- 改着改着功能突然崩了,想退回到昨天那个能跑的版本 —— 退不回去了。
- 想试一个大胆的重构,又怕搞砸现在能跑的代码 —— 不敢动手。
- 三个人同时改一个项目,靠微信互传压缩包 —— 互相覆盖,代码凭空消失。
- 线上出 bug,想知道这行代码是谁、什么时候、为什么加的 —— 无从查起。
所以 Git 解决的其实就是四件事。记住这四个词,后面所有命令都能挂在上面:
都记下来
任意历史点
互不干扰
安全合并
01原理篇:Git 到底是个啥
这一章不背命令,只建立"心智模型"。模型对了,命令是自然推导出来的;模型错了,你会一辈子靠死记硬背过日子,一出问题就抓瞎。
1.1 版本控制到底解决什么问题核心
版本控制系统(VCS)干的事,说白了就是:帮你自动管理刚才那个"论文_最终版"文件夹,而且管得比你好一万倍。
它记录的不是一堆文件副本,而是一条时间线。时间线上每个点都标注清楚了:谁、什么时候、改了哪些文件的哪几行、以及为什么改(提交说明)。
1.2 集中式 vs 分布式:Git 凭什么赢了解即可
老一辈的 SVN 是集中式的,Git 是分布式的。用图书馆打个比方:
SVN = 全世界只有一座中央图书馆
所有历史资料只存在总馆。你要查一本旧书、要借书还书,必须联网跑一趟总馆。
总馆着火了(服务器挂了)→ 全公司历史记录全没。
断网了 → 你什么都干不了。
Git = 每个人家里都有一座全量分馆
你 clone 一次,就把整座图书馆连同全部历史搬回了自己电脑。查历史、开分支、提交存档,全程不用联网,快得飞起。
中央服务器炸了?随便找个同事的电脑推一份上去就恢复了。
"我明明 commit 了,为什么同事看不到我的代码?"—— 因为 commit 只是存进了你家里那座分馆。要让别人看到,必须再 git push 送到总馆去。
commit ≠ 上传。 这句话请写在小本本上。
1.3 三个区域:整个 Git 最重要的一张图核心
如果今天你只记住一张图,请记住这张。90% 的 Git 命令,本质都是在这几个区域之间搬东西。
你正在编辑的文件
准备打包的东西
你电脑里的历史
GitHub / 公司 GitLab
为什么要多一个"暂存区"这么麻烦?因为它让你能挑着提交。比如你这一下午干了两件不相干的事:修了一个 bug,又顺手改了 README。你可以分两次装箱、分两次贴标签:
# 第一箱:只装 bug 修复相关的文件
git add src/login.js
git commit -m "fix: 修复登录按钮点击两次才生效的问题"
# 第二箱:只装文档
git add README.md
git commit -m "docs: 补充本地启动步骤"
这样历史记录清清楚楚,将来哪一箱有问题就退哪一箱。要是一股脑全塞进一个箱子,将来想单独退回其中一件东西,就只能拆箱重装了。
1.4 一次 commit 到底存了什么核心
新人常以为 commit 存的是"我改了哪几行"。其实不是。Git 存的是"整个项目当时长什么样"的一张完整快照。
每张"照片"上都贴着一串身份证号,就是那个 40 位的哈希值,比如 a3f5c9e...。平时用前 7 位就够了(a3f5c9e)。它是这次提交的唯一 ID,全世界不重复。
git log --oneline
a3f5c9e (HEAD -> main) feat: 新增用户头像上传
7b2e841 fix: 修复登录按钮重复提交
c1d0f33 docs: 补充启动步骤
e5a7b90 chore: 初始化项目
同时,每张照片还记着"我的上一张是谁"。所以这些提交串成了一条链子 —— 这就是所谓的"提交历史"。
1.5 分支只是一张便利贴核心
很多人一听"分支"就头大,觉得是很重的东西。真相是:一个分支只是一个 41 字节的小文件,里面就写了一个提交 ID。
1.6 进阶:Git 底层就四种"零件"进阶 · 可跳过
这段属于"知道了会更踏实",30 分钟的分享一带而过就行。Git 的 .git 目录里其实只存了四种对象:
| 对象 | 存的是 | 大白话 |
|---|---|---|
blob | 文件内容 | 一个文件的内容本身(不含文件名)。内容一样的两个文件,Git 只存一份。 |
tree | 目录结构 | 一个文件夹的目录表:记录"这个目录下有哪些文件名,各自指向哪个 blob"。 |
commit | 一次提交 | 指向一个顶层 tree(=那张快照),外加作者、时间、说明、以及父提交是谁。 |
tag | 标签对象 | 给某个 commit 起的一个好记的名字,比如 v1.2.0。 |
所以整个 Git 就是一个"用哈希值当 key 的小型数据库" + 一堆指来指去的指针。你可以亲手扒开看看:
git cat-file -p HEAD # 看看最新那次提交里到底存了啥
tree 9a3b1c... # ← 指向那张"快照"
parent 7b2e84... # ← 指向上一次提交
author linxingyu <xxx@example.com> 1754...
feat: 新增用户头像上传
02场景一:一个人开发
目标:把 Git 当成你的"个人存档 + 后悔药"。这一章的命令,是每天要敲几十遍的肌肉记忆。
2.1 第一次用:三行配置核心
装完 Git 先做这个,否则你的每次提交都会显示"提交人:不知道是谁"。
# 告诉 Git 你是谁(会写进每一次提交记录,同事就靠这个找你)
git config --global user.name "linxingyu"
git config --global user.email "linxingyu@example.com"
# 让中文文件名不显示成一串数字乱码
git config --global core.quotepath false
# 检查一下配好没
git config --global --list
邮箱要用公司代码平台账号绑定的那个邮箱。用错了,平台认不出是你提交的,你的贡献记录是灰的,Code Review 也 @ 不到你。
怎么开局:两种情况
# 情况 A:从零开始一个新项目
mkdir my-blog && cd my-blog
git init # 在当前文件夹建一个空仓库(会多出一个 .git 隐藏文件夹)
# 情况 B:接手已有项目(实习生 99% 是这种)
git clone https://github.com/company/project.git
cd project # clone 会自动建好文件夹并把全部历史拉下来
.git 文件夹是什么它就是那座"分馆"本身 —— 所有历史、所有分支都在里面。把它删了,项目就退化成一堆普通文件,历史全没。所以:永远不要手动去动 .git 里的东西。
2.2 日常四连招:status → add → commit → log核心
这四个命令占你日常 Git 使用的 80%。
① 我现在改了啥?(最该养成的习惯:一有疑问就敲它)
git status
On branch main
Changes not staged for commit: ← 红色:改了但还没放进箱子
modified: src/login.js
Untracked files: ← 红色:Git 压根没见过的新文件
src/avatar.js
② 具体改了哪几行?
git diff # 看工作区的改动(还没 add 的)
git diff --staged # 看已经放进箱子的改动
③ 装箱
git add src/login.js # 装一个文件
git add src/ # 装一个文件夹
git add . # 装当前目录下所有改动(最常用,但记得先 status 确认别装错)
④ 封箱贴标签
git commit -m "feat: 新增用户头像上传功能"
⑤ 回顾历史
git log --oneline --graph --all # 一行一条 + 画出分支图,强烈推荐
git commit -am "xxx" 可以把 add 和 commit 一步做完。但注意:它只对 Git 已经跟踪过的文件生效,新建的文件不会被带上。所以新文件还是得老老实实先 git add。
2.3 .gitignore:别把垃圾提上去核心
项目里有很多东西不该进仓库:依赖包(几万个文件)、编译产物、IDE 配置,还有最要命的 —— 密码和密钥。
# .gitignore 文件放在项目根目录,直接写文件名 / 路径 / 通配符
# 依赖包 —— 别人 npm install 一下就有,没必要提交几万个文件
node_modules/
target/
venv/
# 编译产物
dist/
build/
*.class
*.pyc
# IDE 和系统垃圾文件
.idea/
.vscode/
.DS_Store
# ⚠️ 最重要:任何带密码、密钥、token 的文件
.env
*.key
config/secret.yml
删掉文件再提交一次 没有用 —— 历史记录里还躺着。正确做法是:
① 立刻把那个密码 / 密钥作废重置(这一步最重要,必须马上做);
② 再去清理历史(用 git filter-repo 或 BFG 工具,之后要通知全组重新 clone)。
顺序不能反:清历史很慢,而爬虫扫公开仓库里的密钥只要几十秒。
已经提交过的文件,怎么让 Git 不再管它
# 加进 .gitignore 之后,还得手动把它从 Git 的跟踪列表里踢出去(本地文件会保留)
git rm --cached .env
git rm -r --cached node_modules/
git commit -m "chore: 停止跟踪本地配置文件"
2.4 后悔药大全:改错了怎么办核心 · 全场最实用
新人最怕的就是"我好像把东西弄没了"。其实只要你提交过,Git 里基本没有真正丢得掉的东西。关键是搞清楚:你后悔的那个东西,现在在哪个区域。
| 你的处境 | 命令 | 大白话 |
|---|---|---|
| 文件改乱了,还没 add,想变回上次提交的样子 | git restore 文件名老写法:git checkout -- 文件名 |
把房间里那件东西擦干净复原。 ⚠️ 改动直接消失、救不回来,想清楚再敲。 |
已经 add 了,想从箱子里拿出来(改动保留) |
git restore --staged 文件名老写法:git reset HEAD 文件名 |
把东西从纸箱里掏回房间,东西本身不动。很安全。 |
| 刚 commit 完,发现提交说明写错了 | git commit --amend -m "新说明" |
撕掉标签重写一张。也可以顺手把漏掉的文件 add 了再 amend,合并进上一次提交。 |
| 想撤销最近一次提交,改动留着继续改 | git reset --soft HEAD~1 |
拆箱,但东西还在箱口(回到 add 之后的状态)。最温柔的一档。 |
| 撤销提交,改动退回工作区 | git reset HEAD~1(默认就是 --mixed) |
拆箱,东西倒回房间。最常用的一档。 |
| 撤销提交,连改动一起彻底抹掉 | git reset --hard HEAD~1 |
连箱带货一起烧掉。 ⚠️ 核武器,敲之前先深呼吸。 |
| 要撤销的提交已经 push 到公共分支了 | git revert 提交ID |
不删历史,而是新加一次"反向操作"的提交。别人拉下来不会乱。这是团队场景唯一正确的撤销方式。 |
我 reset --hard 完就后悔了 😱 |
git reflog 找到 ID,再 git reset --hard 那个ID |
Git 的黑匣子。它记录了你 HEAD 走过的每一步,哪怕提交已经"消失",这里还查得到。终极后悔药。 |
# reflog 实战:手滑把最新提交 reset --hard 掉了
git reflog
7b2e841 HEAD@{0}: reset: moving to HEAD~1
a3f5c9e HEAD@{1}: commit: feat: 新增用户头像上传 ← 就是它!还活着!
7b2e841 HEAD@{2}: commit: fix: 修复登录按钮
git reset --hard a3f5c9e # 满血复活 🎉
"任何危险操作之前,先 git commit 一次,或者 git stash 一下。"
只要东西进过 Git 的仓库,reflog 就能把它捞回来。没进过仓库的改动,神仙也救不了。
2.5 分支:你的安全实验田核心
单人开发也要用分支!典型玩法:主线 main 永远保持随时能跑,任何新功能、任何大改,都开一个分支去折腾。
git branch # 看有哪些分支,带 * 的是当前所在
git switch -c feature/avatar # 新建并切过去(新写法,推荐)
# 等价老写法:git checkout -b feature/avatar
# ... 在这个分支上放心大胆地改、提交 ...
git switch main # 切回主线
git merge feature/avatar # 把实验成果合并回主线
git branch -d feature/avatar # 合并完了,撕掉这张便利贴
git branch -D feature/avatar # 大写 D = 强删(没合并过也删,那些提交就找不着了)
feature/user-avatar 新功能 · fix/login-double-submit 修 bughotfix/pay-timeout 线上紧急修复 · refactor/order-module 重构
格式就是 类型/简短描述,用英文小写加连字符。
千万别叫 test、mybranch、xxx、new、111 —— 一周后你自己都不知道那是啥。
2.6 stash:临时插单神器核心
经典场景:你正在开发新功能,代码改了一半(这状态根本没法提交),产品经理突然冲过来:"线上炸了!你先去修个紧急 bug!"
git stash push -m "头像上传写了一半" # 塞进抽屉,工作区立刻变干净
git switch -c hotfix/pay-timeout # 去修紧急 bug
# ... 修完、提交、合并、上线 ...
git switch feature/avatar # 回到原来的分支
git stash list # 看看抽屉里有啥
stash@{0}: On feature/avatar: 头像上传写了一半
git stash pop # 端回桌面,并从抽屉移除(最常用)
# git stash apply = 端回来,但抽屉里还留一份备份
2.7 tag:给版本盖个章进阶
发版的时候用。tag 是钉死在某个提交上的名牌,跟分支不一样:分支会往前跑,tag 永远不动。
git tag -a v1.2.0 -m "2026 年 8 月版本,新增头像上传"
git tag # 列出所有 tag
git push origin v1.2.0 # ⚠️ tag 不会跟着 git push 自动上传,得单独推
git push origin --tags # 或者一次全推上去
2.8 完整实战演练:从 0 做一个个人博客核心 · 建议现场演示
把上面所有东西串成一条真实的工作流。建议边讲边在终端敲一遍。
- 开工
mkdir my-blog && cd my-blog && git init echo "node_modules/" > .gitignore git add . && git commit -m "chore: 初始化项目" - 写首页,提交一版能跑的
# 写完 index.html 之后 git status # 习惯性确认一下 git add index.html git commit -m "feat: 完成博客首页布局" - 想加评论功能,但不确定能不能搞定 → 开分支
git switch -c feature/comments # 折腾两小时,提交了 3 次…… - 突然发现首页有个错别字,得紧急改 → stash
git stash push -m "评论功能写一半" git switch main # 改掉错别字 git commit -am "fix: 修正首页标题错别字" git switch feature/comments && git stash pop # 回来继续干 - 评论功能搞定了 → 合并回主线
git switch main git merge feature/comments git branch -d feature/comments git log --oneline --graph --all # 欣赏一下自己干净的历史 - 发布 → 打标签
git tag -a v1.0.0 -m "博客第一个正式版本"
03场景二:一群人开发
单人开发是"自己跟自己玩",多人协作才是 Git 真正的主场,也是新人最容易出事的地方。这一章的核心就一句话:怎么在不踩到别人脚的前提下,把自己的代码安全地并进去。
3.1 远程仓库与 origin核心
回到图书馆那个比喻:每个人家里都有分馆,那大家怎么同步?—— 约定一个"总馆",所有人都跟总馆对齐。这个总馆就是远程仓库(GitHub / Gitee / 公司 GitLab)。
origin 不是什么关键字,它只是总馆地址的默认昵称。你 clone 的时候 Git 自动给它起的名,就像你把老板的手机号存成"老板"一样。
git remote -v # 看看我连着哪些"总馆"
origin https://github.com/company/project.git (fetch)
origin https://github.com/company/project.git (push)
git remote add origin 仓库地址 # 本地 init 的项目,手动关联远程
main → 你本地的分支(你自己的便利贴)
origin/main → 你上次联网时看到的远程分支状态(一份"缓存的快照")
远程真正的 main → 服务器上此刻的状态,可能同事刚推了新东西,你还不知道
所以 origin/main 不会自己更新,必须 git fetch 才会刷新。
3.2 fetch / pull / push:三个动作说清楚核心
# 每天上班第一件事:拉最新代码
git pull # 最常用
git pull --rebase # 进阶:历史更干净,见 3.7
# 写完了推上去
git push
git push -u origin feature/avatar # 第一次推新分支要带 -u,建立"绑定关系"
# 之后这个分支就可以直接 git push / git pull 了
正确习惯:每天开工前、每次开新分支前、每次准备 push 前,都先 pull 一次。
你基于三天前的代码写了一整天,同事那三天早把地基改了 —— 这时候合并起来才叫惨。
3.3 分支策略:团队怎么定规矩核心
分支策略就是团队的"交通规则"。业界常见三种,对我们这种规模的团队,我建议用中间那种:
| 策略 | 长什么样 | 适合谁 / 大白话 |
|---|---|---|
| Git Flow 重型 |
main / develop / feature/* / release/* / hotfix/* 五种分支 |
规矩最全,但也最繁琐。适合有明确版本号、按季度发版的产品(比如客户端 App、私有化部署的系统)。小团队用会累死。 |
| GitHub Flow 推荐 👍 |
只有一条 main,所有人从 main 开 feature/* 分支,做完提 PR 合回 main |
简单到实习生半天就能学会。main 永远保持可发布,随时能上线。绝大多数 Web 项目、内部系统都够用。 |
| 主干开发 Trunk Based |
基本只有 main,分支活不过一天,靠功能开关控制上线 | 要求团队自动化测试非常强、CI/CD 完善。新人多的团队不建议,容易把主干搞崩。 |
① 永远不要直接在 main 上写代码、直接 push。公司一般也会把 main 设成"受保护分支",你想推也推不上去。
② 分支活得越短越好。一个分支最好 1~3 天就合回去。拖两周的分支,合并时冲突能让你怀疑人生。
3.4 PR 全流程实操(GitHub / Gitee)核心 · 实习生每天都要走
PR = Pull Request,中文叫"合并请求"。说白了就是:「我写完了,请你们看一眼,觉得没问题就帮我合进主线。」
- 同步主线,从最新的 main 开分支
git switch main git pull # 一定要先拉最新! git switch -c feature/user-avatar - 写代码,小步多次提交
git add . git commit -m "feat: 新增头像上传接口" git commit -m "feat: 前端头像裁剪组件" git commit -m "test: 补充头像上传单测" - 推到远程
git push -u origin feature/user-avatar推完终端会直接给你一个 PR 链接,点进去就行。
- 在网页上创建 PR,把描述写清楚
## 这个 PR 做了什么 支持用户上传自定义头像,含裁剪、压缩、上传三步。 ## 为什么要做 关联需求 #128,目前用户只能用系统默认头像。 ## 怎么测 1. 进入「个人中心 → 编辑资料」 2. 点击头像,选一张 >2MB 的图,确认能正常裁剪并上传成功 3. 选一个 .txt 文件,确认有格式错误提示 ## 截图 (贴上效果图 / 录屏) ## 风险点 改动了公共的文件上传工具类,麻烦重点看一下 utils/upload.js - 等 Review,根据意见改
# 直接在同一个分支继续提交、继续 push,PR 会自动更新,不用重开 git commit -am "fix: 按 review 意见补充文件大小校验" git push - 审批通过 → 合并 → 删分支
# 网页上点 Merge 即可,一般会顺手勾选"删除源分支" git switch main git pull # 把刚合并的成果拉回本地 git branch -d feature/user-avatar # 本地也清理掉
三种合并方式,选哪个?进阶
| 方式 | 效果 | 什么时候用 |
|---|---|---|
| Merge commit | 保留你分支上所有提交,另外多一个"合并提交" | 想完整保留开发过程时 |
| Squash and merge 最推荐 | 把你分支上那十几次"改改改""再改改"压成干干净净的一条提交合进 main | 日常首选,main 的历史特别清爽,一个功能就一条记录 |
| Rebase and merge | 把你的提交一条条搬到 main 顶上,历史是一条直线 | 希望保留每条提交、又不想有分叉时 |
Fork = 把别人的仓库整个复制一份到你自己账号下。因为你对人家的仓库没有写权限,只能在自己的复制品上改,然后跨仓库提 PR。
给开源项目贡献代码用 Fork 流程;公司内部项目你本来就有权限,直接开分支即可,不用 Fork。
3.5 Code Review 怎么做才不伤感情核心
✅ 提 PR 的人
- PR 要小。300 行以内最好。一个 2000 行的 PR,没人真的看得动,最后只会被草草 Approve。
- 描述写清楚"做了什么 / 为什么 / 怎么测",别让 reviewer 猜。
- 自己先 Review 一遍:调试用的
console.log、注释掉的死代码、密钥,全都清掉。 - 被提意见 ≠ 被否定,是别人在帮你免费兜底。
💬 评审的人
- 对事不对人。说"这里空指针风险",别说"你怎么这都不会"。
- 区分严重程度:
[必须改]/[建议]/[闲聊],让对方知道哪些是硬伤。 - 提问式表达:"这里如果 list 为空会怎样?" 比 "这里写错了" 好得多。
- 写得好的地方也说一句 👍,Review 不是只挑刺。
3.6 冲突:其实一点都不可怕核心 · 建议现场演示
先破除恐惧:冲突不是报错,不是你把仓库搞坏了。它只是 Git 在说:"这一行你俩都改了,我不敢替你们做主,你自己决定留哪个。"
冲突长什么样
git pull
CONFLICT (content): Merge conflict in src/config.js
Automatic merge failed; fix conflicts and then commit the result.
# 打开 src/config.js,你会看到 Git 插进来的这几行标记:
<<<<<<< HEAD
timeout: 3000, // ← 这是你写的(当前分支)
=======
timeout: 5000, // ← 这是别人写的(要合进来的分支)
>>>>>>> origin/main
解决三步走
- 决定留什么,然后把标记行全删掉
留你的、留他的、或者两个都要、甚至重写一个新的都行。关键是最后文件里不能再有
<<<===>>>这些标记。// 比如商量后决定用 5000 timeout: 5000, - 告诉 Git "这个文件我处理好了"
git add src/config.js git status # 确认所有冲突文件都处理完了 - 提交,完事
git commit # 直接回车用默认的合并说明就行 # 中途反悔想放弃这次合并:git merge --abort (一键回到合并前)
① 不确定怎么改就去问人。冲突的另一半代码是同事写的,跑去问他两句,比你自己猜半小时强一百倍。删掉别人的代码是很严重的事。
② 用 IDE 解决,别用记事本。VS Code / IDEA 都有可视化的冲突界面,直接点"采用当前 / 采用传入 / 都保留",比手删标记安全得多。
③ 勤 pull、分支别拖太久。冲突的严重程度跟"你多久没同步主线"成正比。
3.7 merge vs rebase:一场经典之争进阶 · 但值得讲
git merge
A---B---C feature
/ \
D---E---F---G---H main
合并提交 ↑
✅ 安全、不改写历史、真实记录
❌ 分支多了以后 log 图很乱
git rebase
D---E---F---G---A'--B'--C' main
(原来的 A B C
被复制成新提交)
✅ 历史一条直线,非常好读
❌ 改写了提交 ID,用错了会坑队友
# 典型用法:把主线的最新代码"垫"到我的分支下面
git switch feature/avatar
git rebase main
# 有冲突就解决,然后:
git add 冲突文件 && git rebase --continue
# 想放弃:git rebase --abort
# 日常拉代码时用 rebase 代替 merge,避免一堆没意义的"合并提交"
git pull --rebase
# 嫌每次都要加参数,可以设成默认:
git config --global pull.rebase true
永远不要对「已经推送到远程、并且别人可能已经拉过」的分支做 rebase。
为什么?rebase 会把提交复制成全新的提交(ID 全变了),相当于你把大家共同踩着的地板整个换了一遍。同事再 pull 的时候,Git 会以为凭空多出一堆提交,历史彻底乱套。
安全口诀:rebase 只用在「自己的、还没分享出去的」分支上。公共分支老老实实用 merge。
3.8 提交信息规范:写给三个月后的自己核心
❌ 反面教材
update
修改
1
fix bug
提交一下
aaa
终于好了
测试
三个月后线上出事,你对着这样一屏 log 定位问题,只能一条条点开看 diff。
✅ 正确姿势(Conventional Commits)
feat: 新增用户头像上传
fix: 修复订单金额精度丢失
docs: 补充接口文档
style: 格式化代码,不改逻辑
refactor: 重构支付回调逻辑
perf: 优化列表查询,减少 N+1
test: 补充下单流程单测
chore: 升级 axios 到 1.7.2
格式很简单:类型: 做了什么。复杂的改动可以加正文和关联单号:
git commit -m "fix: 修复用户头像上传超过 2MB 时失败" \
-m "原因:Nginx 默认 client_max_body_size 为 1M。
已调整为 10M,并在前端加上传前大小校验。
Closes #128"
"三个月后的你,光看这条提交信息,能不能想起来当时改了啥、为什么改?"能,就是好的提交信息。
3.9 翻车急救手册核心 · 建议截图保存
| 你遇到的报错 / 状况 | 原因 & 解法 |
|---|---|
! [rejected] ... fetch firstpush 被拒绝了 |
远程有你没有的新提交(同事推过东西了)。 解法: git pull --rebase 拉下来合并好,再 git push。 |
切分支时报Your local changes would be overwritten |
你有没提交的改动,切过去会被覆盖。 解法:要么 git commit 提交,要么 git stash 先收进抽屉。 |
detached HEAD"我怎么不在任何分支上了?" |
你 checkout 到了某个具体提交上(HEAD 没贴在便利贴上,飘着呢)。 解法:想保留改动就 git switch -c 新分支名;不想要就 git switch main 走人。 |
| 不小心把分支删了 | git reflog 找到删除前那个提交 ID,然后 git branch 分支名 那个ID 重建。 |
| 合并到一半想反悔 | git merge --abort / git rebase --abort,一键回到操作前。 |
| 把密码/密钥提交上去了 | 第一时间去重置那个密钥(最重要),再用 git filter-repo 或 BFG 清历史,然后通知全组重新 clone。 |
| 提交到错误的分支了 | 在错误分支上 git reset --soft HEAD~1 撤回提交(改动还在),git stash,切到正确分支,git stash pop,重新提交。 |
| 本地彻底乱了,只想跟远程一模一样 | git fetch origin 然后 git reset --hard origin/main。⚠️ 本地未提交的改动全没,先确认没有要留的东西。 |
① 别在公共分支(main / develop)上 git push -f(强推)。这会直接覆盖掉服务器上的历史,同事的代码可能凭空消失。真要强推也请用 --force-with-lease,它至少会在别人有新提交时拦住你。
② 别把 node_modules、编译产物、密钥提交上去。
③ 遇到看不懂的报错,别乱试命令,先截图问人。Git 里绝大多数问题都能救回来,但乱敲一通之后就不一定了。
04工具:怎么让 Git 更省事
命令行必须会(出问题时只有它能救你),但日常干活该用图形界面就用。会命令行 + 用图形界面 = 最舒服的状态。
4.1 图形化工具核心
| 工具 | 价格 | 大白话点评 |
|---|---|---|
| VS Code 内置 + GitLens 插件 | 免费 | 实习生首选。左边栏点点点就能 add / commit / push,冲突有可视化界面。GitLens 插件能在每行代码旁边直接显示"这行是谁、什么时候改的",查历史神器。 |
| JetBrains 系 IDEA / PyCharm / WebStorm | 付费 | Git 集成是同类里最强的,三向合并冲突界面尤其好用。用 IDEA 的同学不用装别的了。 |
| Sourcetree | 免费 | 老牌独立客户端,分支图画得漂亮,适合用来"看清楚仓库现在是什么形状"。 |
| Fork / GitKraken | 付费为主 | 颜值和体验都很好,个人使用可以考虑。 |
| GitHub Desktop | 免费 | 最简单,功能也最少。纯新手过渡期用可以。 |
| lazygit | 免费 | 终端里的图形界面,键盘党的爱。习惯了效率极高。 |
4.2 让命令行更好用的配置进阶 · 但强烈建议抄走
# 常用命令起别名,少敲很多字
git config --global alias.st "status -sb"
git config --global alias.co "checkout"
git config --global alias.br "branch"
git config --global alias.cm "commit -m"
git config --global alias.unstage "restore --staged"
# 神级别名:一行一条、带颜色、带分支图的漂亮 log
git config --global alias.lg \
"log --graph --pretty=format:'%C(yellow)%h%Creset -%C(auto)%d%Creset %s %C(dim)(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
# 以后就可以:
git st # = git status -sb
git lg # = 那条又长又好看的 log
4.3 值得知道的周边进阶
- gitignore.io / GitHub gitignore 模板 —— 输入你的技术栈(Java、Node、Python…),自动生成一份靠谱的
.gitignore,别自己硬写。 - pre-commit 钩子(husky / lint-staged / pre-commit)—— 提交前自动跑格式化和 lint,把"代码风格"这种争论从 Code Review 里彻底赶出去。
- CI 流水线(GitHub Actions / GitLab CI / Jenkins)—— PR 一提交就自动跑测试和构建,红了就不让合。
- git bisect —— "这个 bug 是哪次提交引入的?" 用二分法几步就能揪出那次提交,排查历史问题的大杀器。
- git blame —— 看某一行代码是谁写的。注意用它是为了「找人问清楚当时的上下文」,不是为了追责。
05命令速查表
这一页建议截图存手机,或者打印贴在工位上。
日常必备(每天都用)
| 命令 | 作用 |
|---|---|
git status | 看当前状态(有疑问就敲它,无副作用) |
git diff / git diff --staged | 看工作区 / 暂存区的具体改动 |
git add . | 把改动放进暂存区 |
git commit -m "说明" | 提交到本地仓库 |
git log --oneline --graph --all | 看提交历史和分支图 |
git pull / git pull --rebase | 拉最新代码 |
git push | 推到远程 |
分支操作
git branch / git branch -a | 看本地分支 / 看全部含远程分支 |
git switch 分支名 | 切换分支 |
git switch -c 新分支名 | 新建并切换 |
git merge 分支名 | 把指定分支合并到当前分支 |
git rebase main | 把当前分支"垫"到 main 最新之上(仅限自己的分支) |
git branch -d 分支名 | 删除已合并的分支 |
git push -u origin 分支名 | 第一次推送新分支 |
撤销与后悔
git restore 文件 | 丢弃工作区改动 ⚠️不可恢复 |
git restore --staged 文件 | 把文件移出暂存区(改动保留) |
git commit --amend | 修改最后一次提交(说明或内容) |
git reset --soft/--mixed/--hard HEAD~1 | 撤销提交,三档力度递增 |
git revert 提交ID | 用一次新提交来抵消旧提交(公共分支专用) |
git reflog | 查 HEAD 走过的所有足迹 —— 终极后悔药 |
git merge --abort / git rebase --abort | 放弃正在进行的合并/变基 |
临时保存与查询
git stash push -m "说明" | 把当前改动收进抽屉 |
git stash list / git stash pop | 查看抽屉 / 取出最近一个 |
git blame 文件 | 看每一行是谁、哪次提交改的 |
git show 提交ID | 看某次提交的完整内容 |
git bisect start | 二分查找是哪次提交引入了 bug |
06给新人的六条忠告核心 · 收尾
- 养成"敲 git status"的条件反射
不知道自己现在处于什么状态,就敲
git status。它没有任何副作用,而且 Git 会在输出里直接告诉你下一步该干嘛。这是最便宜的安全带。 - 小步提交,别攒大招
一个功能点提交一次,别攒一整天一次性提交 50 个文件。提交越小,出问题时越好定位、越好回滚,Review 的人也越愿意认真看。
- 提交信息写人话
"三个月后的自己能看懂"是唯一标准。
update、fix、1这种等于没写。 - 危险操作前先存档
要 reset、rebase、force push 之前,先 commit 或 stash 一下。进过 Git 仓库的东西几乎都能捞回来,没进过的谁也救不了。
- 勤同步主线,别让分支长草
每天 pull,分支活过一周就该警惕了。冲突的痛苦程度,跟你多久没同步成正比。
- 不确定就问,别硬猜
Git 出问题时乱敲命令,很容易把"能救"变成"救不回"。截个图问一句,成本远低于恢复代价。顺便说:问问题不丢人,把代码搞没了才丢人。
Git 的命令有几百个,但你日常真正会用到的不超过 20 个。别想着一次学完,先把「三个区域 + 分支是便利贴」这两个模型刻进脑子里,剩下的命令用到哪个查哪个,一个月就成肌肉记忆了。
07附:30 分钟讲解节奏建议
这一节是给你(分享人)自己看的,正式讲的时候可以跳过不展示。
| 时间 | 讲什么 | 怎么讲 |
|---|---|---|
| 0–3 分 | 00 开场 | 直接放"论文_最终版"那张图,问一句"有没有人干过这事"。先笑起来,再讲技术。 |
| 3–10 分 | 1.3 三个区域 1.4 快照 1.5 分支是便利贴 | 本场最重要的 7 分钟。1.1/1.2/1.6 快速带过或直接跳。三个区域那张图一定要讲透,可以让大家跟着复述一遍"房间 / 纸箱 / 仓库 / 快递"。 |
| 10–18 分 | 2.2 四连招 2.4 后悔药 2.5 分支 2.6 stash | 建议开个终端现场敲 2.8 的实战流程,比念文档效果强十倍。2.4 那张后悔药表格是全场最实用的,多花点时间。2.3 / 2.7 一句话带过。 |
| 18–27 分 | 3.2 pull/push 3.3 分支策略 3.4 PR 流程 3.6 冲突 | 冲突一定要现场演示一遍(提前准备好一个必冲突的仓库),让实习生亲眼看到那几行标记不可怕。3.7 rebase 只讲比喻和黄金法则,不展开。 |
| 27–30 分 | 3.9 急救手册 06 六条忠告 | 快速过一遍急救表,让大家截图。忠告挑第 1、4、6 条重点说,收尾。 |
① 提前准备一个演示仓库:预置好 main 和一个会冲突的分支,现场不用临时造数据。
② 留 3–5 分钟 Q&A,超时就把 3.7 rebase 和第 04 章工具部分砍掉,它们最适合当课后自读材料。
③ 分享结束把这份文档链接发群里,标了「进阶」的部分正好让大家课后自己翻。