Git
Git是程序员必须精通的核心技能。本文从底层原理到企业实践,覆盖:Git核心概念、完整命令体系、分支策略、团队协作规范、常见事故处理、GitHub/GitLab工作流、CI/CD集成等,力求成为一份真正可用的Git参考手册。
第一章:Git是什么,为什么需要它
1.1 没有Git时的灾难
想象你在写论文:论文_v1.doc → 论文_v2_导师修改.doc → 论文_v3_最终版.doc → 论文_v3_最终版_真的最终.doc。多人协作时更是灾难:张三改了第一章,李四改了第二章,你怎么合并?
Git解决的核心问题:
- 版本回溯:任何历史版本都可以恢复,不怕改坏
- 多人协作:多人同时修改不同文件(甚至同一文件的不同位置),自动合并
- 分支隔离:新功能开发不影响正在运行的代码
- 审计追溯:谁在什么时候改了什么,一目了然
1.2 Git的三个区域 + 远程仓库
理解这四个区域是掌握Git的关键。很多新手搞不清楚"为什么我commit了别人还看不到",就是没理解这四个区域的关系。
一句话总结:你在工作目录写代码 → git add告诉Git"这些改动我要跟踪" → git commit把改动正式记录到本地仓库 → git push把本地仓库同步到GitHub/GitLab,这样别人也能看到。
1.3 Git如何存储数据:快照,不是差异
Git每次commit保存的是整个项目的快照(snapshot),而不是文件差异。这与SVN等旧版本控制系统截然不同。好处是:切换分支、回退版本几乎是瞬间完成。
1.4 安装与初始配置
第二章:Git核心概念深度解析
2.1 .git目录:Git的一切
当你执行git init后,项目根目录下会生成一个.git隐藏文件夹。Git的所有数据都存在这里——每一次commit、每一个分支、每一个tag、暂存区内容、配置信息。整个项目的工作目录就是围绕.git展开的。
2.2 三种Git对象:Blob、Tree、Commit
Git底层是一个内容寻址的文件系统——可以根据内容计算出唯一的SHA-1哈希值作为地址。所有数据以三种对象类型存储。
|
对象类型 |
存储内容 |
类比 |
|---|---|---|
|
Blob |
文件的内容(不含文件名)。文件名存在Tree对象中 |
文件的快照 |
|
Tree |
目录结构,包含:文件名 → Blob的哈希映射、子目录 → Tree的哈希映射 |
文件夹的快照 |
|
Commit |
指向一个Tree对象(项目根目录快照)、父Commit引用、提交者信息、提交信息 |
一次保存的快照 |
2.3 HEAD、分支、引用是什么关系
关键理解:分支只是一个指向某个commit的指针(一个40位哈希值的文本文件)。创建分支就是创建一个新指针,切换分支就是移动HEAD指针。
第三章:日常Git操作详解
3.1 创建仓库的两种方式
3.2 核心操作:git add 深入理解
git add不仅仅是将文件添加到暂存区,它实际上做了两件事:(1)计算文件内容的SHA-1哈希,创建Blob对象存入.git/objects;(2)将文件路径和哈希写入.git/index(暂存区)。
3.3 核心操作:git commit 深入理解
git commit会创建Commit对象,包含:当前暂存区的Tree对象哈希、父Commit哈希、作者和时间、提交信息。小步提交原则:每次commit只做一件事,提交信息说清楚做了什么。
3.4 查看历史:git log 完全指南
3.5 .gitignore:告诉Git忽略什么
重要:.gitignore只对未跟踪文件生效。如果文件已被Git跟踪,需要先git rm --cached移除跟踪,再添加到.gitignore。
第四章:分支管理—Git的灵魂
4.1 什么是分支,为什么要用
分支的本质:一个指向某次commit的可移动指针。创建新分支只需要41字节(一个40位哈希+换行符)。有了分支,你可以同时进行"修复线上bug"和"开发新功能",互不干扰。
4.2 合并分支:merge vs rebase
这是Git最常引发讨论的话题。简单说:merge保留真实历史,rebase创造线性历史。各有适用场景,没有绝对的对错。
merge:保留完整分支历史
rebase:线性化历史
rebase黄金法则:永远不要rebase已经push到远程的公共分支!rebase会改写历史,如果别人基于你的旧commit做了开发,会导致严重混乱。只对自己的私有功能分支使用rebase。
4.3 合并冲突:如何解决
冲突的本质:两个分支修改了同一文件的同一行(或相邻行),Git无法判断以哪个为准。
第五章:撤销与回退—救命技能
5.1 四种级别的撤销
|
级别 |
情况 |
命令 |
|---|---|---|
|
工作区撤销 |
改了文件但还没git add,想扔掉改动 |
git restore file.txt |
|
暂存区撤销 |
git add了但还没commit,想从暂存区取回 |
git restore --staged file.txt |
|
本地commit撤销 |
commit了但还没push |
git reset --soft HEAD~1 |
|
已push的撤销 |
已经推送到远程了 |
git revert abc1234 |
5.2 git reset 详解
reset有三种模式,区别在于对工作区和暂存区的处理方式不同。
5.3 git revert:安全的回退方式
revert不会删除历史,而是创建一次新的commit来"反向操作"目标commit的改动。这是回退已push代码的最安全方式。
5.4 git reflog:最后的救命稻草
如果你执行了git reset --hard后后悔了,reflog是你的救命稻草!reflog记录了HEAD的所有移动历史(包括被reset丢弃的commit),默认保留90天。
第六章:远程仓库与团队协作
6.1 SSH Key配置(一劳永逸)
6.2 远程仓库管理
6.3 同步操作:push / pull / fetch
6.4 标签(Tag):标记发布版本
第七章:企业Git工作流(重点)
7.1 Git Flow(经典分支模型)
适用于有明确发布周期的项目,分支类型多但职责清晰。
7.2 GitHub Flow(简化分支模型,推荐大多数团队)
比Git Flow简单得多,适合持续部署的Web项目。主线永远可部署,功能分支短生命周期。
7.3 企业开发完整日常操作流程
这是一个程序员每天的标准Git操作,描述详尽,可照做。
7.4 Pull Request / Merge Request 最佳实践
PR不只是提个请求合并。高质量的PR描述能让Reviewer快速理解你的代码。
7.5 分支保护规则
|
规则 |
作用 |
|---|---|
|
禁止直接push到main |
所有人必须通过PR合并,不能直接推 |
|
需要Review通过 |
至少1-2人Review并Approve后才能合并 |
|
CI通过才能合并 |
单元测试/构建/代码检查必须全部通过 |
|
分支必须最新 |
PR分支必须与main保持同步才能合并(避免合并后出问题) |
|
要求签名提交 |
所有commit需要GPG签名验证身份 |
第八章:高级Git技能
8.1 git stash:临时保存工作现场
8.2 git cherry-pick:摘取特定commit
8.3 git bisect:二分法定位bug
8.4 git blame:查看代码是谁写的
8.5 子模块(Submodule)
第九章:常见事故与解决
|
事故 |
解决方案 |
|---|---|
|
commit到了错误的分支 |
git log记下错误commit的hash → git reset HEAD~1 → git switch 正确分支 → git cherry-pick 记下的hash |
|
push了敏感信息(密码/密钥) |
立即修改密码(因为已经泄露)→ 用git filter-branch或BFG Repo-Cleaner从历史中彻底删除 → force push |
|
merge错了分支 |
git reset --hard HEAD~1 撤销最近一次merge commit |
|
git pull冲突太多想放弃 |
git merge --abort 回到pull之前状态 |
|
Git操作卡住了 |
Ctrl+C终止 → git status确认状态 → 必要时删.git/index.lock |
|
分支混乱不知道在哪 |
git status + git log --oneline --graph -10 看清当前状态 |
Git学习路线建议:
- 入门(第1天):git init/clone → add → commit → push → pull。能单人推送代码即可
- 核心(第1周):分支(branch/switch/merge) → 冲突解决 → 回退(reset/revert)。能在团队中正常协作
- 进阶(第1个月):rebase → cherry-pick → stash → reflog → 交互式rebase。能优雅地管理提交历史
- 精通(持续积累):bisect定位bug → submodule → hooks自动化 → 设计团队Git工作流
日常Top 10命令:git status · git add · git commit -m · git push · git pull · git switch · git branch · git merge · git log --oneline · git stash