# 看懂 AI 改了什么：用 git 管住改动

> 智能体改得快，你得看得清、退得回。这一课教你最小够用的 git：状态、差异、提交、回滚，让智能体帮你写提交信息，并搞清 Claude Code 自带的回退和 git 各管什么。

- 网址：https://coding.chengyu.dev/learn/start/read-and-verify/
- 学习路径：起步：第一次让 AI 写出能跑的东西
- 预计用时：35 分钟；核实日期：2026-10-25
- 官方来源：[Checkpointing（Claude Code 官方文档）](https://code.claude.com/docs/en/checkpointing)，[Quickstart（Claude Code 官方文档）](https://code.claude.com/docs/en/quickstart)，[Interactive mode（Claude Code 官方文档）](https://code.claude.com/docs/en/interactive-mode)，[Best practices for Claude Code（Claude Code 官方文档）](https://code.claude.com/docs/en/best-practices)，[git restore（Git 官方文档）](https://git-scm.com/docs/git-restore)，[git revert（Git 官方文档）](https://git-scm.com/docs/git-revert)，[Installing Git（Pro Git）](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)，[First-Time Git Setup（Pro Git）](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup)

## 学习目标

- 能说清为什么用智能体写代码时必须配合 git
- 能用 git status、diff、add、commit、log 查看和保存改动
- 能在改坏时把文件或整次提交退回到之前的状态
- 能区分 Claude Code 的回退功能和 git 的适用范围，并养成每完成一小步就提交的习惯

想象这样的场景：番茄钟已经能用了，你让智能体再加一个「统计今日完成数」。它改了三个文件，页面却坏了。你想退回到刚才好用的版本，可是……刚才的版本在哪里？

如果没有存档，答案是「没了」。你只能指望它记得自己改过什么，然后让它反着改一遍，而它改的时候又可能引入新问题。

这一课解决的就是这件事：**给你的项目装一个「存档」系统，让智能体怎么折腾，你都能看清、能退回。** 这个系统叫 git。别被它的名声吓到：入门只需要七八条命令，而且大多数时候你可以让智能体替你敲。

## 为什么必须配合 git

用智能体写代码，有三个现实：

1. **它改得很快、很多。** 你很难凭记忆知道它动了哪些文件。
2. **它会犯错。** 有时是小错，有时是把没问题的地方也「顺手优化」坏了。
3. **你需要随时能退。** 越敢放手让它试，越需要一个安全网。

git 能给你的是：**每次改动都留下可对比、可恢复的记录**。

Claude Code 自己也有回退能力（后面会讲），但官方文档明确说明它不能替代 git：它主要是为了在一次会话里快速撤销，而 git 才是长期的版本历史。两者配合使用最稳妥。

## 先装好 git

在终端里运行：

```bash
git --version
```

能看到版本号就已经装好了。没装的话：

- **macOS**：运行 `git --version`，系统会弹窗提示安装「命令行开发者工具」，按提示安装；
- **Windows**：去 [git-scm.com/downloads/win](https://git-scm.com/downloads/win) 下载 Git for Windows，安装时一路下一步（也是第 3 课推荐的）；
- **Linux**：Debian、Ubuntu 用 `sudo apt install git-all`，Fedora 用 `sudo dnf install git-all`。

第一次使用，要告诉 git 你是谁，每台电脑只需做一次。把引号里换成你自己的名字和邮箱：

```bash
git config --global user.name "你的名字"
git config --global user.email "you@example.com"
```

每个提交都会记录这两项，所以要填你愿意留在记录里的信息。

## 最小 git：七条命令

用上一课的 pomodoro 文件夹来练习。下面的操作都在终端里，先 `cd` 进入这个文件夹。

| 命令 | 作用 | 一句话理解 |
|---|---|---|
| `git init` | 在当前文件夹启用 git | 「开始做存档」，一个项目只需做一次 |
| `git status` | 看现在是什么状态 | 「哪些文件变了，哪些还没存」 |
| `git diff` | 看具体改了哪几行 | 「改动的细节」，还没 add 的 |
| `git add 文件` | 把改动放进待保存区 | 「这些我想存进下一个存档」 |
| `git commit -m "说明"` | 生成一个存档 | 「存档点，并写一句说明」 |
| `git log --oneline` | 看存档历史 | 「我存过哪些档」 |
| `git restore 文件` | 丢掉未保存的改动 | 「这个文件退回到上次存档」，会丢数据 |

### 做第一个存档

```text
$ git init
  Initialized empty Git repository in .../pomodoro/.git/
$ git status
  Untracked files:
    app.js  index.html  style.css
$ git add .
$ git commit -m "完成番茄钟基础版：开始、暂停、重置、阶段切换"
  3 files changed, 142 insertions(+)
$ git log --oneline
  a1b2c3d 完成番茄钟基础版：开始、暂停、重置、阶段切换
```

这里 `git add .` 中的点号表示「当前文件夹里所有改动」。`a1b2c3d` 是这个存档的编号（你的会不一样），后面回退时会用到。

> **先想想有没有不该存的东西**
>
> 密码、API 密钥、`.env` 文件、个人隐私数据，都**不要**提交进 git，一旦提交，即使以后删掉，历史里仍然能找到。如果项目里有这类文件，要先让智能体创建 `.gitignore` 把它们排除。这个番茄钟项目没有，可以放心。

### 看懂 git diff

假设你让智能体加了「今日完成数」，改完后在终端里运行 `git diff`，会看到类似这样的内容：

```diff
diff --git a/app.js b/app.js
--- a/app.js
+++ b/app.js
@@ -12,6 +12,9 @@ const BREAK_MINUTES = 5;
 let mode = 'focus';
 let remaining = FOCUS_MINUTES * 60;
+let doneToday = Number(localStorage.getItem('doneToday') || 0);
+
 function render() {
-  timeEl.textContent = format(remaining);
+  timeEl.textContent = format(remaining);
+  countEl.textContent = '今日完成：' + doneToday;
 }
```

读法很简单，不需要懂编程：

- `---` 是旧版本，`+++` 是新版本，涉及的文件名在这两行里；
- **以 `+` 开头、通常显示为绿色的行是新增的**，**以 `-` 开头、红色的行是删除的**；
- 没有符号的行是上下文，帮你定位；
- `@@` 开头那一行告诉你这是文件的第几行附近。

你不必理解每一行代码，但**要能回答三个问题**：改了哪几个文件？大概改了多少？有没有改到我没让它碰的东西？最后一个问题最重要，如果它在改「完成数」时顺便动了计时核心逻辑，你应该起疑。

在 Claude Code 里，你也可以直接输入 `/diff`，不离开会话就能看到工作区的所有改动，包括它刚刚改的。

另外，`git diff` 默认只显示**还没 add 的**改动。已经 add 但没提交的，用 `git diff --staged` 看。

### 回滚的三种场景

**场景 1：改了还没提交，想丢掉对某个文件的修改。**

```bash
git restore app.js
```

这会让 app.js 回到上一次存档时的样子。注意：**未提交的改动会被直接丢弃，通常无法找回**，所以先用 `git status` 和 `git diff` 确认你要丢掉的就是这些。

**场景 2：想把某个文件恢复到更早的某个存档。** 先用 `git log --oneline` 找到编号，然后：

```bash
git restore --source=a1b2c3d app.js
```

**场景 3：已经提交了，才发现这次提交不对。**

```bash
git revert HEAD
```

它不会删除历史，而是新建一个提交，把上一个提交的改动反着做一遍。因为历史完整保留，这是最安全的撤销方式。执行时需要工作区没有未提交的改动。想不打开编辑器直接用默认说明，可以加 `--no-edit`。

> **不要乱用 git reset --hard**
>
> 网上很多教程会教你用 `git reset --hard` 回退。它会直接丢弃未提交的改动并移动历史指针，官方文档也提醒要小心。在你还没完全理解它之前，用上面三种就够了。更保险的做法，是出手之前让智能体帮你检查。

## 让智能体帮你提交

这些命令你知道有它们就好，**日常大部分时间，你可以直接让 Claude Code 做**。官方快速入门里就给了现成的说法：让它看看改了哪些文件，再用有描述性的信息提交。

**审阅并提交一次改动**

```text
请帮我检查并提交当前的改动：
1. 先运行 git status 和 git diff，用中文告诉我：改了哪些文件，每个文件大致改了什么；
2. 如果有任何改动看起来超出了我最近这次要求的范围，请单独指出来，先不要提交；
3. 确认没有密码、密钥之类的敏感内容；
4. 然后提交，提交信息用中文，第一行不超过 30 字，说清做了什么；必要时空一行补充原因；
5. 提交完成后运行 git log --oneline -3，让我看到结果。
```

它在执行 `git commit` 时，手动模式下会请求你的许可，这是个很好的**最后检查点**。养成习惯：

1. 提交前，自己扫一眼它总结的改动清单；
2. 提交后，看一眼 `git log --oneline`，确认提交说明写得对，不夸大也不遗漏。

好的提交信息，是未来的你（或者另一个智能体）读历史时的路标。比较两种写法：

| 差 | 好 |
|---|---|
| `更新` | `加入今日完成数统计，保存在 localStorage` |
| `fix` | `修复切换标签页后倒计时变慢：改用结束时间点计算` |
| `改了很多东西` | `把计时逻辑抽成独立函数，便于测试` |

## Claude Code 自带的回退：/rewind

Claude Code 在你发每条消息之前，会自动记录它用文件编辑工具要改的文件状态（官方称为检查点，checkpoint）。当智能体走偏了，你有两种办法回退：

- 在输入框为空时**连按两次 `Esc`**；
- 或输入 **`/rewind`**。

它会列出你在这次会话里发过的消息，选中一个时间点后，可以选择：

- **恢复代码和对话**：两者都退回那个点；
- **只恢复对话**：代码保持现状；
- **只恢复代码**：对话保留，文件退回；
- **从这里开始总结**：压缩对话，释放上下文空间（与回退代码无关）。

官方文档里写明了它的**边界**，你要记住，因为这正是 git 要接手的地方：

- 通过 Bash 命令（比如它运行 `rm` 或 `sed`）改动的、而之前没用文件编辑工具改过的文件，**不会被跟踪**；
- 你自己在编辑器里手动改的内容、别的会话里的改动，通常不会被捕获；
- 部分子智能体的改动不会被恢复；
- 检查点会过期清理（默认大约 30 天后）。

所以分工是这样的：

| | Claude Code 回退 | git |
|---|---|---|
| 范围 | 本次会话中它用编辑工具做的改动 | 你提交过的所有版本 |
| 适合 | 刚才那一两轮聊偏了，马上撤销 | 长期保存、对比历史、永久回退 |
| 局限 | 不跟踪命令行造成的改动，会过期 | 只保存你提交过的，没提交就没有 |

一个实用的比方：`/rewind` 像编辑器里的「撤销」，git 像「另存为一个版本」。

## 把它变成习惯：每完成一小步就提交

最值钱的一个习惯：

> **每完成一个可以独立验证的小步骤，就提交一次。**

具体做法是一个小循环：

1. 确认工作区干净（`git status` 显示没有未提交的改动）；
2. 给智能体一个小任务；
3. 在浏览器里验证，看 `/diff`，确认没有越界；
4. 满意，就让它提交；不满意，`git restore` 或 `/rewind` 回到第 1 步；
5. 开始下一个任务。

这样，你的历史会变成一串可以任意回头的存档点。哪怕某次大胆的尝试彻底搞砸了，最坏的结果也只是回到上一个存档。**这才是敢于放手让它做的底气。**

还有两条小提醒：

- 提交只是在你自己的电脑上存档。把代码上传到 GitHub 之类的远程仓库（push）是另一件事，涉及别人能不能看到，这一步先别急，等你理解了再做；
- 开启一个新任务之前先提交或丢弃旧改动，别让不同任务的改动混在一起，否则 `git diff` 会变得很难读。

> 小测：你让智能体加了新功能，页面坏了，你还没有提交。想把 app.js 退回到上一次提交的状态，应该用？

> 小测：智能体通过运行 Bash 命令（例如 sed）批量改了一个它此前没用编辑工具碰过的文件。要撤销这个改动，下面哪个最可靠？

## 动手试一试

用你的番茄钟项目，完整走一遍存档与回滚：

- [ ] 运行 git --version 确认已安装，并配置好 user.name 与 user.email
- [ ] 在 pomodoro 文件夹里执行 git init，并完成第一次提交（git add . 然后 git commit）
- [ ] 让智能体加一个小功能，先用 git status 和 git diff（或 /diff）读懂它改了什么
- [ ] 用上面的「审阅并提交」提示词，让它帮你提交，并检查 git log --oneline 里的提交说明
- [ ] 故意让它做一次你不满意的改动，用 git restore 把文件退回去
- [ ] 再做一次满意的改动并提交，然后用 git revert HEAD 撤销它，观察 git log 里多了什么
- [ ] 再试一次 /rewind：让它改一处，用连按两次 Esc 回退代码，体会它和 git 的区别

到这里，「起步」路径就完成了：你已经选好了工具，装好了环境，做出了第一个项目，学会了和智能体沟通，并且有了随时能退回的底气。接下来，推荐进入[Claude Code 精通](/learn/claude-code/how-it-works/)路径，从它内部怎么工作开始，系统掌握记忆、权限、上下文等进阶功能。
