版本控制基础:Git原理、工作区与仓库、常用命令
说到版本控制,我觉得这是每个软件工程师的必修课。不管你是在做Pipeline构建,还是写普通的业务代码,Git都能帮你把项目管得明明白白。我自己干了这么多年,见过太多因为没用好版本控制而翻车的案例。
一句话说透:Git不是备份工具,是协作和追溯的基石。
Git的核心原理
Git跟SVN最大的区别是什么?
它是分布式的。每个开发者本地都有一份完整的仓库。你想想看,就算服务器挂了,你手里还有完整的历史记录。
Git的核心是“快照”而非“差异”。每次提交,Git都会拍下所有文件的状态快照。如果文件没变,它只存一个链接,不会浪费空间。
我个人最欣赏Git的一点——它是内容寻址的。每个对象都有一个SHA-1哈希值,内容变了,哈希就变。这就保证了数据完整性。我在项目中遇到过有人误改历史记录,哈希对不上,立刻就被发现了。
Git的三种对象:Blob(文件内容)、Tree(目录结构)、Commit(提交快照)。
理解这三者的关系,你就懂了一半。
工作区与仓库
Git的工作流程其实就三个区域:工作区、暂存区、仓库。说白了,就是你干活的地方、你挑东西的地方、你存东西的地方。
- 工作区(Working Directory):你看到的那些文件。随便改,没关系。
- 暂存区(Staging Area / Index):一个中间层。你想把哪些改动提交,就先git add进去。
- 仓库(Repository / .git):所有历史记录和元数据都存在这里。
为什么会设计暂存区?嗯,这里要注意。如果每次改完直接提交,你没法精细控制。比如你改了两个无关的bug,想分两次提交,暂存区就能帮你做这件事。
常用命令实践
命令就那几个,背住就行。我按使用频率排了个序,你看一遍就能上手。
| 命令 | 作用 | 常用场景 |
|---|---|---|
| git init | 初始化仓库 | 新建项目时跑一次 |
| git add | 添加到暂存区 | 每次改完代码后 |
| git commit -m "msg" | 提交到本地仓库 | 完成一个功能点 |
| git status | 查看当前状态 | 随时看改了啥 |
| git log | 查看提交历史 | 排查问题或回顾 |
| git diff | 查看具体改动 | 提交前确认内容 |
1. git init
进入项目目录,敲这一句,Git就开始接管了。目录下会多一个.git文件夹,别手贱删掉。
cd my-pipeline-project
git init
跑完之后,你可以看看到底生成了什么。
ls -la .git
# 你会看到:
# HEAD
# config
# description
# hooks/
# info/
# objects/
# refs/
小技巧:git init 后面可以加 --bare,用来创建纯远程仓库。我常用的裸仓库初始化命令:
git init --bare /path/to/repo.git
裸仓库没有工作区,只能用来 push 和 pull,很适合做中央仓库。
2. git add
把改动从工作区挪到暂存区。你可以挑文件加,也可以全部加。
# 加单个文件
git add main.py
# 加所有改动(小心点,别加进来不该加的文件)
git add .
# 交互式挑选(我推荐这个,避免失误)
git add -p
我记得有一次,同事直接git add .,把几个大的日志文件也加进来了,结果仓库体量暴涨。从那以后,我教团队都用git add -p,逐块审查,心里踏实。
3. git commit
暂存区的内容,正式存到仓库里。每次commit都会生成一个唯一的SHA-1哈希。
# 常规提交
git commit -m "feat: add CMake presets for Windows build"
# 如果忘记写-m,会弹出编辑器(默认vim)
# 我个人习惯用 -m,短提交信息够用了
注意:提交信息请遵循规范格式。推荐使用 Conventional Commits:
<type>: <description>
类型有:feat(新功能)、fix(修bug)、docs(文档)、refactor(重构)、test(测试)、chore(杂务)。
我经历过几次因为提交信息写得不清不楚,三个月后没人能看懂当时为什么改。血的教训。
4. git status
这个命令我每天用几十次。它能告诉你工作区、暂存区、仓库之间的差异。
git status
# 输出示例:
# On branch main
# Changes not staged for commit:
# modified: CMakeLists.txt
# Untracked files:
# new_script.py
三种文件状态:
- Untracked:Git还没跟踪过的新文件。需要先git add。
- Modified:已经跟踪过的文件,内容改了,但还没暂存。
- Staged:已添加到暂存区,准备提交。
5. git log
翻历史记录。我排查bug的时候经常用,看看到底是哪次提交引入了问题。
# 完整历史
git log
# 一行显示(简洁)
git log --oneline
# 带图形分支(看合并历史)
git log --oneline --graph --all
# --oneline 的输出示例:
# a1b2c3d (HEAD -> main) feat: add CI pipeline config
# e4f5g6h fix: correct output path in build script
# i7j8k9l chore: update dependencies
# m0n1o2p docs: add getting-started guide
核心要点:Git 记录的永远是你做了什么(commit),而不是你想做什么。每次 commit 都要保持原子性——一个改动一个提交,不要混在一起。这样以后用 git bisect 查问题才能精准定位到具体变更。
避坑指南
我入行头两年,在这些坑里摔过。写出来给你提个醒。
坑1:.gitignore
我曾经把一个含有API密钥的配置文件提交到了仓库,还push到了远程。等发现的时候,密钥已经在Git历史里了。删掉文件没用,历史里还留着。
正确的做法:项目初始化时就把 .gitignore 写好,把敏感文件、编译产物、IDE配置都忽略掉。
# .gitignore 示例
build/
*.o
*.exe
__pycache__/
.env
*.log
.vscode/
.idea/
如果你已经提交了敏感文件,需要用 git filter-branch 或 BFG Repo-Cleaner 彻底重写历史。但最好还是别走到那一步。
坑2:大文件
别把二进制文件、数据集、安装包直接往Git里塞。Git不适合管理大文件,仓库会越来越臃肿,clone和pull都变慢。
真有大文件需求,用 Git LFS(Large File Storage)。它可以帮你存指针文件,实际文件存在远端。
git lfs track "*.zip"
git lfs track "*.pth"
git add .gitattributes
好了,基础部分就到这。Git的原理、三个区域、五个常用命令,你掌握这些就能处理80%的日常工作了。实际做项目的时候多练练,慢慢就变成肌肉记忆了。