Git 版本控制的核心用法
为什么需要版本控制
写代码最怕的不是写错,是改不回去。上周能跑的版本,今天突然挂了;同事在另一个分支改的接口,你这边还是旧签名。
版本控制解决三件事:
- 回得去:任何一次提交都能一秒还原
- 合得拢:多人改同一份代码,机器告诉你哪里撞了
- 说得清:谁、什么时候、为什么改了这一行
一句话理解
版本控制 = 给文件做带时间线的快照,并让多人在同一份快照上协作。
四个区,三类对象
Git 的世界里只有三类对象——commit、tree、blob——但日常打交道的是四个区。把四个区分清楚,九成的命令就不再神秘。
Git 四个区 Mermaid
- 工作区:你看到的文件,改动还没被记录
- 暂存区:下次提交要带什么,精确控制粒度
- 本地仓库:你的历史,已经提交但还没推出去
- 远程仓库:队友的历史,已经共享
常见误解
git commit 不是「保存」,是「把暂存区生成一个快照」。忘 git add 就 commit,会发现改的东西没进版本。
起步:建仓与首次提交
# 新项目
git init
git add .
git commit -m "feat: init project"
# 接老项目
git clone <url>
cd <dir>
git remote -v # 确认远程地址
首次提交前先配身份,否则 commit 会用系统用户名:
git config --global user.name "你的名字"
git config --global user.email "you@example.com"
日常开发:增、改、查
git status # 当前在哪个区动了什么
git diff # 工作区 vs 暂存区
git diff --staged # 暂存区 vs 上次 commit
git log --oneline -10 # 最近 10 条提交(一行一条)
git log --graph --all # 可视化分支
撤销三连(按危险程度递增,越往后越要谨慎):
git restore <file> # 丢弃工作区改动(未暂存)
git restore --staged <file> # 取消暂存,文件改动保留
git revert <commit> # 产生一个反向 commit,安全可推
硬性规则
已经推上远程的 commit,不要用 git reset 改写。改写历史是协作灾难,需要时用 git revert。
分支策略
分支是 Git 的灵魂。一人开发也建议开分支——主分支永远保持「能跑」的状态。
三种主流模型
主干开发,所有人往
main 上合,靠 CI 和 feature flag 控制风险。适合高频发布的小团队。 main 永远可部署,任何新功能从 main 开 feature 分支,PR 合回。开源项目最常见。 main + develop 双长分支,加 feature/* release/* hotfix/* 三类短分支。适合有明确发布窗口的产品。 命令速查
git switch -c feat/login # 新建并切换分支
git switch main # 切回主分支
git branch -d feat/login # 已合并才允许删
git branch -D feat/login # 强制删(未合并也删)
git push -u origin feat/login # 首次推送 + 关联上游
合并 vs 变基
两个分支各改了一边,怎么收口?
merge vs rebase Mermaid
| 操作 | 历史形状 | 何时用 |
|---|---|---|
git merge | 保留分叉节点 | 公共分支、提 PR、合主线 |
git rebase | 拉成直线 | 本地私有分支、未推送前整理 commit |
黄金法则
永远不要对已经推上公共分支的提交做 rebase。 会让队友的本地历史瞬间错位,比 merge 冲突难排查十倍。
冲突解决
冲突的本质:同一段代码,两边改得不一样,Git 不知道留哪份。
git merge feat/login
# Auto-merging src/auth.ts
# CONFLICT (content): Merge conflict in src/auth.ts
# Automatic merge failed; fix conflicts and then commit the result.
打开文件,看到这种标记:
<<<<<<< HEAD
const ttl = 3600;
=======
const ttl = 7200;
>>>>>>> feat/login
手动选一边、删掉标记符、再提交。VS Code 等编辑器会高亮冲突块,一键选「current / incoming / both」。
git add src/auth.ts
git commit # Git 已经写好默认 commit message,直接保存
减少冲突的三个习惯
- 小步提交:改一点就 commit,冲突粒度变小
- 频繁拉取:
git pull --rebase让自己始终基于最新主干 - 明确分工:同一文件不同模块各改各的,最后合一次
远程协作
git fetch origin # 拉取远程更新,不合并
git pull --rebase # 拉取 + 变基(推荐)
git push # 推送本地提交
git push -f # 强制推送(慎用!只在 rebase 后用)
PR / Code Review 是远程协作的灵魂:先发 PR,再合主线。哪怕只有你一个人,写 PR description 也是给自己写 changelog。
概念关系图
把上面所有概念串起来,看一眼就知道谁依赖谁。
知识图谱 可拖拽
演进时间线
2005
Git 诞生
Linus 为 Linux 内核开发,两周写出首版
2008
GitHub 上线
社交化托管,PR 工作流成为事实标准
2014
GitLab CI
CI/CD 与仓库同平台,DevOps 一体化
2020
主干开发回归
trunk-based + feature flag 成主流
2024
AI 辅助提交
Copilot 等工具开始生成 commit message 和 PR 描述
常见坑清单
commit 信息写成 'update'
半年后没人记得这次提交改了什么。坚持
type(scope): subject 格式,type 用 feat / fix / docs / refactor / test / chore。把 node_modules / 编译产物提交进库
.gitignore 第一时间配好,否则仓库体积几天就破 GB。仓库大 = 克隆慢 = CI 慢。在主分支直接开发
main 一旦污染,回滚成本极高。新功能一律从分支开始,哪怕只是 5 分钟的实验。commit 前不跑测试 / 不看 diff
git diff --staged 走一遍,能挡掉 80% 的低级错误。CI 慢,本地眼睛快。强制推送覆盖了同事的提交
git push -f 永远要三思。已经合入主线的提交一旦被强推,所有下游都要重新拉取。速查表
| 场景 | 命令 |
|---|---|
| 撤销工作区单个文件 | git restore <file> |
| 撤销全部暂存 | git restore --staged . |
| 改最近一次 commit | git commit --amend |
| 看某行是谁改的 | git blame <file> |
| 找回被 reset 掉的提交 | git reflog |
| 临时藏起当前改动 | git stash |
| 恢复 stash | git stash pop |
| 给当前 commit 打标签 | git tag v1.0.0 |
| 只克隆最近一次 | git clone --depth 1 <url> |
一句话收尾
分支不是负担,是给未来的自己留的退路。
add 时多想一秒、commit 时写清楚动机、push 前确认没把临时调试代码带上去——这三条习惯做到,Git 就从「咒语大全」变成「顺手的记事本」。