跳转到内容

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. 入门(第1天):git init/clone → add → commit → push → pull。能单人推送代码即可
  2. 核心(第1周):分支(branch/switch/merge) → 冲突解决 → 回退(reset/revert)。能在团队中正常协作
  3. 进阶(第1个月):rebase → cherry-pick → stash → reflog → 交互式rebase。能优雅地管理提交历史
  4. 精通(持续积累):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