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,直接保存
💡
减少冲突的三个习惯
  1. 小步提交:改一点就 commit,冲突粒度变小
  2. 频繁拉取git pull --rebase 让自己始终基于最新主干
  3. 明确分工:同一文件不同模块各改各的,最后合一次

远程协作

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 .
改最近一次 commitgit commit --amend
看某行是谁改的git blame <file>
找回被 reset 掉的提交git reflog
临时藏起当前改动git stash
恢复 stashgit stash pop
给当前 commit 打标签git tag v1.0.0
只克隆最近一次git clone --depth 1 <url>

一句话收尾

分支不是负担,是给未来的自己留的退路。

add 时多想一秒、commit 时写清楚动机、push 前确认没把临时调试代码带上去——这三条习惯做到,Git 就从「咒语大全」变成「顺手的记事本」。

目录

图表