1.2.2 Git 核心操作

这一节开始把 Git 用起来。重点是掌握每天都会重复使用的 add、commit、status、log、diff 和撤销操作,形成“写一点代码、看一下状态、提交一次记录”的基本开发习惯。
- 熟练使用
git add、git commit、git status、git log - 学会用
git diff查看修改内容 - 会编写
.gitignore文件 - 掌握几种常用的撤销操作
我们用一个模拟的 AI 项目来练习所有操作。先创建项目:
mkdir ai-image-classifiercd ai-image-classifiergit init
# 创建基本的项目结构mkdir data models srctouch src/train.py src/model.py src/utils.pytouch README.md requirements.txt查看状态:git status
Section titled “查看状态:git status”git status 是你用得最多的命令,它告诉你当前仓库的状态:哪些文件被修改了?哪些在暂存区?哪些还没被 Git 跟踪?
git status输出:
On branch main
No commits yet
Untracked files: (use "git add <file>..." to include in what will be committed) README.md requirements.txt src/
nothing added to commit but untracked files presentUntracked files(未跟踪的文件):Git 看到了这些文件,但还没有管理它们。你需要用 git add 告诉 Git “请开始跟踪这些文件”。
添加到暂存区:git add
Section titled “添加到暂存区:git add”# 添加单个文件git add README.md
# 添加多个文件git add src/train.py src/model.py
# 添加整个文件夹git add src/
# 添加所有文件(最常用)git add .
# 添加所有修改过的已跟踪文件(不包括新文件)git add -u先给文件写点内容:
echo "# AI 图像分类器" > README.mdecho "torch>=2.0" > requirements.txt
cat > src/model.py << 'EOF'import torch.nn as nn
class SimpleCNN(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 16, 3, padding=1) self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(16 * 16 * 16, 10)
def forward(self, x): x = self.pool(torch.relu(self.conv1(x))) x = x.view(-1, 16 * 16 * 16) x = self.fc1(x) return xEOF现在添加所有文件并查看状态:
git add .git status输出:
On branch main
No commits yet
Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: README.md new file: requirements.txt new file: src/model.py new file: src/train.py new file: src/utils.py文件变成了绿色的 “Changes to be committed”,说明它们已经在暂存区里,准备好被提交了。
提交:git commit
Section titled “提交:git commit”git commit -m "初始化项目:添加模型定义和项目结构"输出:
[main (root-commit) a1b2c3d] 初始化项目:添加模型定义和项目结构 5 files changed, 18 insertions(+) create mode 100644 README.md create mode 100644 requirements.txt create mode 100644 src/model.py create mode 100644 src/train.py create mode 100644 src/utils.py提交信息怎么写?
Section titled “提交信息怎么写?”提交信息应该简洁、清晰,让人一看就知道这次改了什么。
好的提交信息:
git commit -m "添加 CNN 模型定义"git commit -m "修复训练循环中学习率未更新的 bug"git commit -m "添加数据增强:随机翻转和颜色抖动"git commit -m "更新 README:添加安装说明"不好的提交信息:
git commit -m "update" # 改了什么?git commit -m "fix" # 修了什么?git commit -m "aaa" # ???git commit -m "改了一些东西" # 等于没说查看修改:git diff
Section titled “查看修改:git diff”git diff 告诉你”上次提交之后,你改了什么”。
案例:修改模型代码
Section titled “案例:修改模型代码”# 给 model.py 添加一个新层cat > src/model.py << 'EOF'import torchimport torch.nn as nn
class SimpleCNN(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 16, 3, padding=1) self.conv2 = nn.Conv2d(16, 32, 3, padding=1) # 新增的卷积层 self.pool = nn.MaxPool2d(2, 2) self.fc1 = nn.Linear(32 * 8 * 8, 10)
def forward(self, x): x = self.pool(torch.relu(self.conv1(x))) x = self.pool(torch.relu(self.conv2(x))) # 新增 x = x.view(-1, 32 * 8 * 8) x = self.fc1(x) return xEOF现在查看变化:
git diff输出会用红色和绿色高亮显示:
--- a/src/model.py+++ b/src/model.py@@ -1,4 +1,5 @@+import torch import torch.nn as nn
class SimpleCNN(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 16, 3, padding=1)+ self.conv2 = nn.Conv2d(16, 32, 3, padding=1) # 新增的卷积层 self.pool = nn.MaxPool2d(2, 2)- self.fc1 = nn.Linear(16 * 16 * 16, 10)+ self.fc1 = nn.Linear(32 * 8 * 8, 10)- 红色(
-开头):被删除的行 - 绿色(
+开头):被新增的行
现在提交这次修改:
git add src/model.pygit commit -m "增加第二层卷积层,提升模型能力"diff 的几种用法
Section titled “diff 的几种用法”git diff # 查看工作目录中未暂存的修改git diff --staged # 查看暂存区中的修改(已 add 但未 commit)git diff HEAD~1 # 查看最近一次提交改了什么git diff abc1234 def5678 # 比较两次提交之间的差异查看历史:git log
Section titled “查看历史:git log”git log输出:
commit def5678... (HEAD -> main)Author: Zhang San <[email protected]>Date: Mon Feb 9 10:30:00 2026
增加第二层卷积层,提升模型能力
commit a1b2c3d...Author: Zhang San <[email protected]>Date: Mon Feb 9 10:00:00 2026
初始化项目:添加模型定义和项目结构更简洁的历史查看
Section titled “更简洁的历史查看”# 一行一条记录(最常用)git log --oneline# 输出:# def5678 增加第二层卷积层,提升模型能力# a1b2c3d 初始化项目:添加模型定义和项目结构
# 带文件变更统计git log --oneline --stat
# 图形化显示分支(有分支时很有用)git log --oneline --graph --all.gitignore:告诉 Git 忽略哪些文件
Section titled “.gitignore:告诉 Git 忽略哪些文件”有些文件不应该被 Git 管理:
- 数据文件(几个 GB 的训练数据)
- 模型权重文件(几百 MB)
- 虚拟环境文件夹
- 系统生成的临时文件
- API 密钥、密码等敏感信息
创建 .gitignore 文件来告诉 Git 忽略它们:
cat > .gitignore << 'EOF'# Python 缓存__pycache__/*.pyc*.pyo
# 虚拟环境venv/.venv/env/
# Jupyter Notebook 检查点.ipynb_checkpoints/
# 数据文件(太大了,不放进 Git)data/*.csvdata/*.jsondata/*.zip*.h5*.hdf5
# 模型权重文件models/*.ptmodels/*.pthmodels/*.onnx*.bin
# 环境变量文件(包含 API 密钥等敏感信息).env.env.local
# IDE 配置.vscode/.idea/
# 操作系统文件.DS_StoreThumbs.db
# 日志logs/*.log
# 分发/打包dist/build/*.egg-info/EOFgit add .gitignoregit commit -m "添加 .gitignore:忽略缓存、数据、模型权重和敏感文件"验证 .gitignore 生效
Section titled “验证 .gitignore 生效”# 创建一些应该被忽略的文件mkdir -p __pycache__touch __pycache__/model.cpython-311.pyctouch .envecho "OPENAI_API_KEY=your_api_key_here" > .env
# 查看状态——这些文件不会出现git status# 输出: nothing to commit, working tree clean.env 和 __pycache__/ 都被忽略了,不会被提交到 Git 里。你的 API 密钥是安全的。
撤销操作:后悔药
Section titled “撤销操作:后悔药”Git 提供了几种不同的”后悔药”,根据你后悔到哪一步来选择。
新手可以按这个顺序思考:
flowchart TD A["发现哪里不对"] --> B["运行 git status"] B --> C["运行 git diff"] C --> D{"是否已经提交?"} D -->|"没有,也没暂存"| E["git restore file<br/>丢弃本地修改"] D -->|"已暂存但未提交"| F["git restore --staged file<br/>保留修改,移出暂存区"] D -->|"已经提交"| G["优先用新提交修复<br/>reset 先只在练习仓库里用"]场景1:改了文件但还没 add,想恢复原样
Section titled “场景1:改了文件但还没 add,想恢复原样”# 你改了 src/utils.py,但改得不满意,想恢复到上次提交的状态git restore src/utils.py
# 恢复所有文件git restore .场景2:已经 add 了,想从暂存区撤回(但保留修改)
Section titled “场景2:已经 add 了,想从暂存区撤回(但保留修改)”# 你 add 了 model.py,但还不想提交它git restore --staged src/model.py
# 文件会从暂存区退回到工作目录,你的修改还在场景3:已经 commit 了,想修改提交信息
Section titled “场景3:已经 commit 了,想修改提交信息”# 刚提交完发现消息写错了git commit --amend -m "修正后的提交信息"场景4:已经 commit 了,想撤销整个提交
Section titled “场景4:已经 commit 了,想撤销整个提交”# 撤销最近一次提交,但保留文件修改(回到 add 之前)git reset HEAD~1
# 撤销最近一次提交,并且丢弃所有修改(彻底回退,慎用)git reset --hard HEAD~1前几周可以把 git reset --hard 当成应急命令,而不是日常命令。在团队项目里,改写历史还可能影响别人,所以更安全的习惯通常是新增一个修复提交。
案例:完整的后悔流程
Section titled “案例:完整的后悔流程”# 假设你不小心把 API 密钥提交了echo "API_KEY=your_api_key_here" > config.pygit add .git commit -m "添加配置文件"
# 糟糕!密钥不应该提交。撤销这次提交git reset HEAD~1
# 文件还在,但提交被撤销了。现在把它加入 .gitignoreecho "config.py" >> .gitignoregit add .gitignoregit commit -m "更新 .gitignore:忽略 config.py"撤销操作速查
Section titled “撤销操作速查”| 我想撤销什么 | 命令 | 文件修改还在吗 |
|---|---|---|
| 工作目录的修改(还没 add) | git restore 文件名 | ❌ 丢弃 |
| 暂存区的文件(已 add 未 commit) | git restore --staged 文件名 | ✅ 保留 |
| 最近的提交信息写错了 | git commit --amend -m "新信息" | ✅ 保留 |
| 最近的提交(保留修改) | git reset HEAD~1 | ✅ 保留 |
| 最近的提交(丢弃修改) | git reset --hard HEAD~1 | ❌ 丢弃 |
实操练习:模拟一次完整的开发过程
Section titled “实操练习:模拟一次完整的开发过程”# 1. 写训练脚本cat > src/train.py << 'EOF'import torchfrom model import SimpleCNN
model = SimpleCNN()optimizer = torch.optim.Adam(model.parameters(), lr=0.001)print("模型参数量:", sum(p.numel() for p in model.parameters()))EOF
git add src/train.pygit commit -m "添加基础训练脚本"
# 2. 写工具函数cat > src/utils.py << 'EOF'def accuracy(predictions, labels): """计算准确率""" correct = (predictions.argmax(dim=1) == labels).sum().item() return correct / len(labels)EOF
git add src/utils.pygit commit -m "添加准确率计算工具函数"
# 3. 更新 READMEcat > README.md << 'EOF'# AI 图像分类器
一个使用 CNN 的简单图像分类项目。
## 安装
```bashpip install -r requirements.txt```
## 使用
```bashpython src/train.py```EOF
git add README.mdgit commit -m "更新 README:添加安装和使用说明"
# 4. 查看完整历史git log --oneline你应该看到类似这样的 5 条提交记录:
f6g7h8i 更新 README:添加安装和使用说明d4e5f6g 添加准确率计算工具函数b2c3d4e 添加基础训练脚本9a0b1c2 添加 .gitignore:忽略缓存、数据、模型权重和敏感文件a1b2c3d 初始化项目:添加模型定义和项目结构每一条都是一个可以回退到的存档点。
项目交付参考与讲解
- 最后的
git log --oneline应该显示本练习的 3 个提交,以及前面初始化项目时留下的提交。 - 每个提交应该保存一个小想法:训练脚本、工具函数或 README 更新。
- 最后执行
git status应该是干净状态,或者只剩下你能解释清楚的未跟踪文件。 - 如果
src/train.py因为缺少torch或model运行失败,那是运行环境问题,不是 Git 流程问题。记录失败,但保留 Git 操作证据。 - 好的提交信息应该有动作和含义,例如
Add basic training script,而不是update stuff这类模糊信息。
学完这一页,至少保留这张证据卡:
- 仓库状态
- 操作前后的 git status
- 操作
- 使用了 init、add、commit、branch、merge、remote、pull 或 push 命令
- 历史
- 显示变更内容的 git log 或分支图
- 失败检查
- 未跟踪文件、错误分支、合并冲突,或远程/认证问题
- 期望产出
- 一份可供其他学习者安全复现的干净 Git 记录
| 命令 | 用途 | 使用频率 |
|---|---|---|
git status | 查看当前状态 | ⭐⭐⭐⭐⭐ |
git add . | 暂存所有修改 | ⭐⭐⭐⭐⭐ |
git commit -m "消息" | 提交 | ⭐⭐⭐⭐⭐ |
git log --oneline | 查看历史 | ⭐⭐⭐⭐ |
git diff | 查看修改内容 | ⭐⭐⭐⭐ |
git restore | 撤销工作目录修改 | ⭐⭐⭐ |
git reset | 撤销提交 | ⭐⭐ |