我们假设你正在开发一个项目,里面有三个文件:index.html(主页)、style.css(样式)和app.js(逻辑)。
🎬 初始状态 (Commit A)
你刚建好项目,提交了初始版本。
- 文件状态:
index.html:空文件style.css:空文件app.js:空文件
🎬 第一次提交 (Commit B)
提交信息:“添加网页标题”
你做了什么:你在index.html里写了一行代码。
- Commit B 的改动(补丁):
index.html:+1行<h1>欢迎来到我的网站</h1>
当前文件状态:
index.html:包含<h1>欢迎来到我的网站</h1>style.css:空app.js:空
🎬 第二次提交 (Commit C)
提交信息:“添加红色样式”
你做了什么:你在style.css里写了样式,并且修改了index.html引入了这个样式。
- Commit C 的改动(补丁):
style.css:+1行body { color: red; }index.html:+1行<link rel="stylesheet" href="style.css">
当前文件状态(HEAD):
index.html:包含<h1>...和<link...>style.css:包含body { color: red; }app.js:空
🎬 第三次提交 (Commit D)
提交信息:“添加点击弹窗”
你做了什么:你在app.js里写了逻辑,并且再次修改了index.html引入脚本。
- Commit D 的改动(补丁):
app.js:+1行alert('Hello!');index.html:+1行<script src="app.js"></script>
当前文件状态(HEAD):
index.html:包含<h1>...、<link...>和<script...>style.css:包含body { color: red; }app.js:包含alert('Hello!');
🔄 现在,执行git revert C
你的意图:你不想要“红色样式”了,想撤销 Commit C。
Git 的内心独白:
“Commit C 做了两件事:1. 在style.css加了红色代码;2. 在index.html加了 link 标签。
我要反向操作:1. 删掉style.css里的红色代码;2. 删掉index.html里的 link 标签。”
生成的新提交 (Commit E - Revert C):
style.css:-1行body { color: red; }index.html:-1行<link rel="stylesheet" href="style.css">
执行后的文件状态:
index.html:包含<h1>...和<script...>(注意:<link>标签消失了,但<script>还在!)style.css:空文件 (红色代码消失了)app.js:包含alert('Hello!');(弹窗逻辑还在!)
🔄 紧接着,执行git revert D
你的意图:你连弹窗也不想要了,想撤销 Commit D。
Git 的内心独白:
“Commit D 做了两件事:1. 在app.js加了 alert;2. 在index.html加了 script 标签。
我要反向操作:1. 删掉app.js里的 alert;2. 删掉index.html里的 script 标签。”
生成的新提交 (Commit F - Revert D):
app.js:-1行alert('Hello!');index.html:-1行<script src="app.js"></script>
最终文件状态:
index.html:只包含<h1>欢迎来到我的网站</h1>style.css:空文件app.js:空文件
📌 总结:文件是怎么变回去的?
表格
| 文件 | 初始 (A) | 提交B后 | 提交C后 | 提交D后 | Revert C 后 | Revert D 后 |
|---|---|---|---|---|---|---|
| index.html | 空 | 有标题 | 有标题+样式链接 | 有标题+样式+脚本 | 有标题+脚本(样式链接被删) | 有标题(脚本也被删) |
| style.css | 空 | 空 | 有红色代码 | 有红色代码 | 空(红色代码被删) | 空 |
| app.js | 空 | 空 | 空 | 有弹窗代码 | 有弹窗代码 | 空(弹窗代码被删) |
核心逻辑:
Revert 就像“橡皮擦”,它只擦除特定那一次提交留下的痕迹,完全不管其他提交做了什么。即使你撤销了中间的 C,后面的 D 依然稳如泰山,直到你专门去撤销 D。
就是说revert是反向操作具体选择的那一次的内容