Git 是现代软件工程的基础工具。它不仅用于 “保存代码历史”,更重要的是提供了一套管理变化、协作开发、追踪责任和控制风险的方法。

学习 Git 不应从背命令开始,而应先理解它解决什么问题,以及它背后的设计哲学。

# 没有版本控制会发生什么

最朴素的版本管理方式通常长这样:

1
2
3
4
report.docx
report-final.docx
report-final-v2.docx
report-final-v2-really-final.docx

写代码时也可能变成:

1
2
3
4
5
main.py
main_backup.py
main_old.py
main_before_refactor.py
main_fixed.py

这种方式有几个明显问题:

  • 不知道每次改了什么。
  • 不知道为什么修改。
  • 不知道谁修改。
  • 多人同时修改时容易互相覆盖。
  • 想回退到某个稳定版本很困难。
  • 不能可靠地并行开发多个功能。
  • 出现 bug 后很难定位是哪次变更引入的。

Git 解决的核心问题是:把文件变化变成可追踪、可比较、可回退、可协作的历史记录

# 版本控制的核心价值

# 记录历史

Git 会把一次有意义的修改保存为一次提交,也就是 commit

每次提交通常包含:

  • 修改了哪些文件。
  • 每个文件改了哪些内容。
  • 作者是谁。
  • 提交时间。
  • 提交说明。
  • 指向上一个提交的引用。

这让项目历史成为一条可阅读的演化记录,而不是一堆散乱备份。

# 支持回退

当新代码引入问题时,Git 可以帮助你:

  • 查看历史版本。
  • 比较两个版本差异。
  • 回退某个文件。
  • 撤销某次提交。
  • 把整个项目切换到旧版本。

这使得修改代码的风险降低。不是因为不会犯错,而是犯错后更容易恢复。

# 支持多人协作

多人开发时,Git 可以把不同人的修改合并起来,并在冲突发生时明确指出冲突位置。

常见协作流程:

  1. 从远程仓库拉取最新代码。
  2. 在本地分支开发功能。
  3. 提交本地修改。
  4. 推送到远程仓库。
  5. 发起代码评审。
  6. 合并进入主分支。

Git 让协作从 “互相传文件” 变成 “围绕提交历史协作”。

# 支持实验

软件开发中经常需要试验:

  • 尝试新架构。
  • 重构旧模块。
  • 验证某个 bug 修复方案。
  • 开发一个不确定能否上线的功能。

使用分支后,可以在不影响主线的情况下进行实验:

1
git switch -c experiment/cache-layer

如果实验成功,可以合并;如果失败,可以丢弃分支。主线历史不会被混乱修改污染。

# Git 的哲学

Git 的设计与传统集中式版本控制系统不同。它的哲学可以概括为几个关键词:快照、分布式、本地优先、内容寻址、分支廉价、显式历史。

# 快照,而不是差异补丁

很多人直觉上以为 Git 保存的是一组组 diff。更准确地说,Git 的核心模型是保存项目在某个时刻的快照。

每次提交都指向一棵文件树:

1
2
3
4
5
commit
└── tree
├── src/main.py
├── README.md
└── tests/test_main.py

如果某个文件没有变化,Git 不会重复保存一份完整内容,而是复用已有对象。因此 Git 既像是在保存快照,又能高效存储。

这带来一个重要理解:commit 不是 “一个补丁文件”,而是项目状态的一个命名快照

# 分布式,而不是依赖中央服务器

Git 是分布式版本控制系统。每个开发者本地都有完整仓库历史。

这意味着:

  • 没有网络也可以提交。
  • 可以在本地查看完整历史。
  • 可以在本地创建分支、合并、回退。
  • 远程仓库只是协作节点,不是唯一真相。

常见远程平台如 GitHub、GitLab、Gitee,本质上是托管 Git 仓库并提供协作功能的平台。

Git 仓库可以没有远程仓库,也可以有多个远程仓库。

1
git remote -v

常见远程名 origin 只是约定,不是 Git 的硬性规则。

# 本地优先

Git 的大多数操作都在本地完成:

1
2
3
4
5
6
7
git status
git log
git diff
git commit
git branch
git merge
git rebase

只有与远程同步时才需要网络:

1
2
3
git fetch
git pull
git push

本地优先带来的好处:

  • 操作速度快。
  • 可以离线工作。
  • 可以先整理本地历史,再公开给团队。
  • 可以在本地进行风险较高的实验。

# 内容寻址

Git 使用对象内容计算哈希值,并用哈希值标识对象。

提交哈希示例:

1
9fceb02f55c9f23b9967f8c55d0c542c1f6b1a6e

如果内容不同,哈希就不同。因此 Git 历史具有很强的完整性校验能力。

这解释了为什么提交 ID 看起来像一串随机字符。它不是随机数,而是由提交内容、作者、时间、父提交等信息计算出的标识。

# 分支廉价

在 Git 中,分支本质上是指向某个提交的可移动指针。

创建分支并不会复制整个项目:

1
git branch feature/login

它只是创建了一个新的引用,成本很低。这就是 Git 鼓励频繁使用分支的原因。

分支适合表达不同工作线:

  • main :稳定主线。
  • develop :开发集成分支。
  • feature/* :功能分支。
  • fix/* :缺陷修复分支。
  • release/* :发布准备分支。
  • hotfix/* :线上紧急修复分支。

# 显式历史

Git 不只关心最终文件内容,也关心历史如何形成。

一个好提交应该回答:

  • 这次改了什么?
  • 为什么要改?
  • 影响范围是什么?
  • 是否能独立回退?

差的提交:

1
2
3
4
update
fix
misc
改一下

好的提交:

1
2
3
fix(auth): reject expired login tokens
docs(linux): add filesystem hierarchy notes
refactor(api): isolate request validation

提交信息是未来排查问题时给自己和队友看的,不是给 Git 机器看的。

# Git 管的是变化,不是最终文件夹

Git 关注的是工作区相对于仓库历史发生了什么变化。

常用观察命令:

1
2
3
git status
git diff
git log --oneline

git status 回答:

  • 当前在哪个分支。
  • 哪些文件被修改。
  • 哪些修改已暂存。
  • 哪些文件未跟踪。

git diff 回答:

  • 具体改了哪些行。

git log 回答:

  • 历史上发生过哪些提交。

# Git 不能替代工程纪律

Git 很强,但不能自动保证项目质量。它不能替你决定:

  • 需求是否正确。
  • 代码是否设计良好。
  • 测试是否充分。
  • 提交粒度是否合理。
  • 分支策略是否适合团队。

Git 只是提供历史和协作机制。真正的工程质量来自:

  • 小步提交。
  • 清晰提交信息。
  • 合理分支策略。
  • 代码评审。
  • 自动化测试。
  • 持续集成。
  • 发布流程控制。

# 什么时候需要 Git

几乎所有长期维护的代码项目都应该使用 Git。

适合使用 Git 的场景:

  • 软件项目。
  • 博客文章和技术笔记。
  • 配置文件。
  • 脚本工具。
  • 论文或文档的 Markdown / LaTeX 源文件。
  • 可文本化的数据处理流程。

不适合直接用 Git 管理的内容:

  • 体积很大的二进制文件。
  • 频繁变化的大型数据集。
  • 编译产物。
  • 缓存目录。
  • 密钥、密码、令牌等敏感信息。

这些内容通常应通过 .gitignore 排除,或使用 Git LFS、对象存储、制品仓库等方式管理。

# 学 Git 的正确顺序

建议顺序:

  1. 理解工作区、暂存区、本地仓库。
  2. 掌握 statusdiffaddcommit
  3. 掌握 logshowrestore
  4. 理解分支和 HEAD。
  5. 掌握 branchswitchmerge
  6. 再学习远程协作: fetchpullpush
  7. 最后学习 rebaseresetrevertcherry-pick 等历史操作。

不要一开始就依赖图形界面。图形界面很方便,但命令行能迫使你理解 Git 的真实模型。

# 一句话总结

Git 的本质是一个分布式快照数据库。它把项目历史组织成一张提交图,让开发者可以安全地记录变化、并行开发、协作合并、定位问题和回退风险。

更新于

请我喝[茶]~( ̄▽ ̄)~*

梦前辈 微信支付

微信支付

梦前辈 支付宝

支付宝