Git 从原理到工程实践:Python 后端开发中的版本管理指南
文章目录
1. 为什么需要 Git?
1.1 没有 Git 会发生什么?
没有Git,文件版本混乱难以整理。在没学 Git 之前,很多初学者会通过不同的文件名来区别代码版本:
final.py
final_new.py
final_new2.py
final_真正最终版.py
...
这种通过文件名管理版本的方式存在很多问题。
例如:
- 无法清晰追踪每次代码修改内容
- 修改历史容易丢失
- 多人协作时容易互相覆盖代码
- 当代码出现 Bug 时,很难快速回退到之前稳定版本
随着项目越来越复杂,
传统的文件复制方式已经无法满足开发需求。
这就是 Git 产生的原因。
Git 简介:
Git 是一种分布式版本控制工具,
能够帮助开发者管理代码历史、追踪文件修改、
实现多人协作开发,并支持快速回退历史版本。
1.2 Git 与 SVN 的区别
目前常见的版本控制工具主要有:
- SVN(集中式)
- Git(分布式)
SVN(集中式)
SVN 的核心特点是:
所有代码都依赖中央服务器进行管理。
开发者本地通常只保存当前项目代码,
真正完整的版本历史存放在远程服务器中。
因此:
- 如果服务器异常,可能无法提交代码
- 断网情况下,很多操作会受到限制
- 团队协作对中央服务器依赖较强
Git(分布式)
Git 采用分布式版本管理。
每个开发者本地都会保存完整仓库,
包括:
- 代码文件
- commit 历史
- branch 信息
因此即使在断网环境下:
- 依然可以 commit
- 依然可以查看历史版本
- 依然可以创建分支
Git 也因此更适合现代多人协作开发。
2. Git 核心概念
2.1 Git 四大区域
工作区 Working Directory
工作区指的是开发者当前真正编写和修改代码的目录。
例如:
project/
|— main.py
|- user.py
|- config.py
这些文件所在目录就是工作区。
你:
- 新建文件
- 修改代码
- 删除文件
都发生在工作区
但这里有一个重点:
工作区不代表 Git 已经记录。
很多初学者认为:
我保存文件了
=
Git 已经保存版本了
这是错误的。
Git 并不会在文件保存时自动记录版本,
因此开发者需要通过 git add
主动将修改加入暂存区。
git add
暂存区 Stage
暂存区是 Git 中非常经典的设计之一,
也是很多初学者最容易困惑的地方。
暂存区到底是什么?
你可以把它理解为:”待提交清单“。
例如,你修改了以下文件:
login.py
user.py
config.py
但你现在,只想提交login功能。
于是你执行了git add命令:
git add login.py
这可以看成是:
把 login.py 放进“下一个提交名单”
为什么 Git 不直接 commit ?
因为 Git 希望你能“选择性提交”。
例如:
你今天改了:
| 文件 | 是否完成 |
|---|---|
| login.py | ✅ 完成 |
| payment.py | ❌ 写一半 |
| test.py | ❌ 调试代码 |
如果没有暂存区:
commit 会把所有修改一起提交
这会很混乱。
所以暂存区解决了“精确控制提交内容”, 这也是 Git 能够支持高质量版本管理的重要原因之一。
本地仓库 Local Repository
本地仓库用于保存 Git commit 历史记录。
当你执行:
git commit
Git 会生成一个 commit 对象。
保存:
- 当前代码快照
- 作者
- 时间
- commit message
需要注意的是:
只有执行 git commit 后,Git 才会真正生成历史版本。
远程仓库 Remote Repository
例如:
- GitHub
- Gitee
- GitLab
通俗来说,它们就是代码同步中心。但远程仓库本质上仍然是 Git 仓库,只是托管在远程服务器中。
为什么需要远程仓库?
因为本地仓库只有你自己才能看到。
远程仓库可以:
- 多人协作
- 备份代码
- Pull Request
- Code Review
Git 四大区域流转
Git 的核心要领,就是掌握代码如何在四大区域流转。
2.2 Git 数据流
理解Git的数据流,能够帮助你快速理清 Git 工作原理。
Git 数据流本质
工作区
↓ git add
暂存区
↓ git commit
本地仓库
↓ git push
远程仓库
举个真实例子
假设你正在开发:
FastAPI 登录功能
step1:修改代码
def login():
return {"msg": "login success"}
现在代码只存在于工作区,
Git 还没有正式记录这次修改。
step2:git add
git add login.py
意思是:
“这个文件已经准备好提交”
此时文件会被加入暂存区。
step3:git commit
git commit -m "feat: add login api"
现在Git 才真正生成历史版本,并进入:
本地仓库。
step4:git push
git push
通过push,代码同步到远程仓库。
2.3 Git 为什么需要暂存区?
Git 设计暂存区,是为了让开发者能够“精确控制提交内容”。开发过程中,一个项目往往会同时修改多个文件。但有些功能可能已经完成,有些代码仍在开发中。
因此 Git 提供了暂存区(Stage),用于存放“已经确认准备提交”的代码,从而避免一次性提交所有修改内容。
举个工程例子
你修改:
login.py
payment.py
test.py
但现在只有 login.py 完成了。
你只要将 login.py 加入暂存区,然后完成提交。
git add login.py
git commit
这样 commit 只包含:
login 功能
这有什么好处?
- commit 更清晰:
每一次的 commit只做一件事,即把暂存区的文件提交。
- 更适合回滚:
如果 login功能有Bug,只需要回退 login 的commit,这样可以快速回退到之前稳定的版本。
- 更适合团队协作:
Git 的 版本管理使得 Code Review 更清晰。
2.4 Git 的快照机制
很多初学者误认为:Git 保存“文件变化”。
实际上:
对于未变化的文件,Git 会复用已有对象,从而减少存储空间占用。
每一次 commit,都代表项目在当前时间点的完整状态。
什么叫快照?
例如:
commit1
print("hello")
commit2
print("hello world")
Git 会认为:
这是两个时间点的完整状态
而不是:
"第二次只增加了 world"
这就是 Git 的快照思想。
为什么快照机制强?
因为:
- 回滚速度快:直接切换快照即可。
- branch 创建成本低:因为branch 本质只是一个 commit 指针,而不是复制整个项目。
2.5 commit、branch、HEAD 本质
commit 是什么?
很多初学者以为:
commit = 提交动作
其实不完整。
commit 本质是:“某一时刻代码状态的快照”。每个 commit 都会记录父 commit 信息,从而形成 Git 的版本链。
commit 里面保存:
- 文件状态
- 作者
- 时间
- message
- 父 commit
branch 是什么?
很多人误解:
创建 branch = 复制一份代码
实际上,Git 的 branch 本质上是:
branch 是指向 commit 的可移动指针
举例
main -> commit3
新增 commit:
main -> commit4
main 指针移动了。
所以:
Git 创建分支几乎没有成本,因为它只是个指针。
HEAD 是什么?
HEAD 本质上是一个特殊指针,
用于表示当前正在检出的 commit 或 branch。
通常情况下:
HEAD -> main
意思是:当前正在main 分支工作。
当 commit 时,HEAD 会和 main 一起移动。
例如:
HEAD -> main -> commit4
新增 commit 后:
HEAD -> main -> commit5
3. Git 基础操作
3.1 初始化仓库
在使用 Git 管理项目之前,都需要将当前目录初始化为 Git 仓库。
git init
执行完成后, 当前目录下会生成一个隐藏文件夹:

这个目录保存了 Git 的版本数据、commit历史、branch信息、暂存区文件等等。
此时完成目录的初始化后,Git 才会开始对当前目录进行版本管理。
我在git_demo目录下已经创建了一个空的 Git 仓库,可以看到命令行提示符末尾出现了 (master),说明当前在 master 分支上。
3.2 文件状态机制
Git 会持续追踪文件状态变化。
一个文件在 Git 中, 通常会经历以下几种状态:
| 状态 | 含义 |
|---|---|
| untracked | 未被 Git 跟踪 |
| modified | 文件已修改 |
| staged | 已加入暂存区 |
| committed | 已提交到本地仓库 |
Git 的很多命令,本质上就是在操作文件状态转换。
untracked - 未跟踪
例如,我在git_demo目录下新建login.py文件:
touch login.py
接着执行:
git status # 查看当前目录下所有文件状态
Git Bash会显示
untracked files

这说明 Git 发现了新文件,但是还没有正式追踪它。
modified - 已修改
如果一个已经被 Git 管理的文件发生修改,Git 会认为文件内容已经变化,此时文件进入modified 状态。但Git 仍然没有生成新版本,因为没有执行add和commit操作。
例如:
login.py 原本内容是:
def login():
return "git add success"
现在修改为:
def login():
return "modified"
使用git status命令查看当前状态,login.py文件已转入modified状态。![![[Pasted image 20260510012852.png]]](https://i-blog.csdnimg.cn/direct/5fcd27cecd684999a4cb716f2bc2b5e5.png)
staged - 已暂存
将login.py文件加入暂存区:
git add login.py
文件进入Stage暂存区,此时 Git 会认为login.py文件已经准备好提交。
committed - 已提交
将 login.py 的修改提交到本地仓库,生成Git历史版本:
git commit -m "feat: add login api"
提交之后,Git 返回:当前所在的分支名、这次提交的Commit ID前7位(即版本号)以及提交的信息。
注:(root -commit) 表示这是该仓库的第一个提交(根提交),没有父提交。1 file changed表示有 1 个文件发生了变化,0 insertions(+)表示插入了 0 行代码(因为 login.py 是空文件),0 deletions(-)表示删除了 0 行代码。100644是Linux 文件权限码,表示这是一个普通文件。- create mode表示文件被创建并加入版本控制
查询文件状态,Git 会告诉你,当前没有待提交的修改,工作区很干净,暂存区已清空。![![[Pasted image 20260510014158.png]]](https://i-blog.csdnimg.cn/direct/073cce07ee5f47019c0dae47ba5882d0.png)
3.3 查看状态与历史
在实际开发中,我们可能会想知道当前有哪些文件被修改、哪些文件已经加入暂存区、最近提交了哪些版本…
这些都需要通过 Git 提供的历史查看命令完成。
git status
在3.2文件状态机制,我们已经使用过。
git status
这个命令会告诉你:
- 当前所在分支
- 哪些文件发生修改
- 哪些文件已加入暂存区
- 是否存在未跟踪文件
git log
git log用于查看commit历史记录。
这里会显示:
- 完整的版本号- commit id
- 作者
- 提交时间
- commit message

git log 常用参数
–oneline
表示每次提交信息只占一行。
git log --oneline
Git 会以更简洁的方式返回日志:076b435:最新一次提交的 Commit ID(前7位)(HEAD -> master):HEAD 指向当前分支 master,表示我现在就在这个提交上feat: add register api:最新提交的信息f799369:上一次提交的 Commit ID(前7位)feat: add login api:第一次提交的信息
–online --graph --all
表示图形化显示提交数,以及显示所有分支。
git log --oneline --graph --all
目前只有一个 master 分支,所以图形化没有完整体现。
这个命令非常适合查看branch与merge结构,后面学习分支时会经常使用。
git reflog
git reflog用于记录 HEAD 指针移动历史。
以下操作,都会导致 HEAD 移动,如:
- 代码提交 commit
- 版本穿梭 reset
- 分支切换 checkout
- 分支合并 merge
而 reflog 会记录这些行为。
注:(HEAD -> master):指当前 HEAD 指向 master 分支的这个提交HEAD@{0}:这是最近一次 HEAD 移动的记录(编号从0开始)commit: feat: add register api:操作类型是提交,提交信息是这个f799369:上一个提交的 Commit IDHEAD@{1}:这是倒数第二次 HEAD 移动的记录commit (initial): feat: add login api:操作类型是初始提交(第一个提交)
git log VS git reflog
| 命令 | 显示内容 | 特点 |
|---|---|---|
git log |
commit 的提交历史(仓库的状态快照) | 只显示当前分支能追溯到的提交 |
git reflog |
HEAD 的操作历史(HEAD 的移动记录) | 显示所有本地操作,包括被 reset、checkout 等操作引用的提交 |
git reflog可以帮助我们找回丢失的commit。
举例,我通过:
git reset --hard 版本号
或者
git reset 版本号
撤回 commit,回到register.py没有被提交的版本。
再使用:
git reflog
查看所有操作,找到原先的版本号,最后在回到rehgister.py被提交了的版本。
3.4 文件比较与撤销
Git 不仅可以管理版本,还可以帮助开发者对比修改与撤销错误操作。
git diff - 文件比较
git diff 用于查看文件修改内容。
返回结果包括:
- 哪些代码发生变化
- 代码的变换位置
- 哪些内容被删除
- 哪些内容被新增
举例:
我在 register.py添加了register()方法:
def register():
return{"success"}
再使用
git diff register.py
查看修改内容:![![[Pasted image 20260510150248.png]]](https://i-blog.csdnimg.cn/direct/748d24fd94864d0b9de29213fbc5fd4c.png)
Git 对比了暂存区中的版本(a/register.py)和工作区的版本(b/register.py),告诉我-0,0原文件中从第0行开始,共0行(空文件),+1,2新文件中从第1行开始,共2行,发现我在空文件添了那样两行代码。
必须要注意的是git diff比较的是:工作区 与 暂存区。
而git diff --cached 则比较的是 暂存区 与 本地仓库。
举例:
register修改完后,我没有将其加入暂存区,所以此时比较暂存区与本地仓库没有任何输出。

当我将 register.py 加入暂存区后,输入:
git diff --cached register.py
Git 才会返回比对结果:![![[Pasted image 20260510151524.png]]](https://i-blog.csdnimg.cn/direct/95b731f12e6d40a3ae18226e79c36128.png)
工作区撤销
如果文件还没有加入暂存区,可以使用:
git restore
撤销对工作区的修改。
例如:
将register.py文件内容修改为:
def register():
return{"bug"}
但我们想要将文件恢复到上一次的转态时间,就可以执行:
git restore register.py
同时 register.py 的状态变为modified:![![[Pasted image 20260510152404.png]]](https://i-blog.csdnimg.cn/direct/91d3f5ee49dd4f4d89bbc9145b8ba438.png)
实际上,restore就是用最近版本覆盖当前工作区。
暂存区撤销
如果文件已经执行add操作,可以使用:
git restore --staged
来将文件移出暂存区。
举例,我们将 register.py 将入暂存区,可以看到它是绿色,当前文件在暂存区,等待提交。![![[Pasted image 20260510153403.png]]](https://i-blog.csdnimg.cn/direct/83af8a20b8104f4ab7866c050c5bbe22.png)
接着执行移出暂存区操作:
git restore --staged register.py
register.py 变为红色,文件不在暂存区了,只在工作区。![![[Pasted image 20260510154122.png]]](https://i-blog.csdnimg.cn/direct/6cf2f8b2bef940d5903d482446883cbe.png)
commit 回退
即前文提到过的版本穿梭。
git reset --hard 版本号
或者
git reset 版本号
可以配合git reflog使用,帮助你快速回到版本。
版本穿梭是 Git 中最容易误操作的命令之一,它会直接影响:
- HEAD
- branch
- 暂存区
- 工作区
不过 Git 提供了reset 的三种模式,避免全部修改。
| 模式 | HEAD | 暂存区 | 工作区 |
|---|---|---|---|
| soft | 回退 | 保留 | 保留 |
| mixed | 回退 | 清空 | 保留 |
| hard | 回退 | 清空 | 清空 |
–sotf
只移动 HEAD。
git reset --soft 版本号
它会使得 commit 消失,但保留了暂存区和工作区。
适用场景是,你需要修改你的commit message。
–mixed
默认模式
git reset --mixed 版本号
等价于
git reset 版本号
它会使 commit 消失,暂存区清空,但工作区保留。
这是最常用的 reset 模式。
–hard
这是一个很危险的模式。
git reset --hard 版本号
它会使 commit 消失,暂存区清空,工作区恢复。
也就是说,工作区代码也会被覆盖,修改会直接丢失。
更多推荐

所有评论(0)