前言
在 Git 的世界里,我们都有过这样的时刻:看着刚刚提交的代码,突然意识到——"糟糕,我不该提交这个!" 或者 "这个改动有问题,需要撤回!"。代码回退是每个开发者都会遇到的常见需求。Git 提供了两种主要的回退方式:reset 和 revert。虽然它们都能实现代码回退,但背后的机制和适用场景却截然不同。
核心概念
git reset:历史重写式回退
git reset 通过移动 HEAD 指针和分支引用来实现回退,本质上是重写提交历史。reset又有三种不同的模式,分别是soft,mixed,hard。下面我对三种情况的做具体说明。
--soft:保留工作区与暂存区
# 回退到指定提交,保留所有更改在暂存区
git reset --soft <commit-hash>
适用场景:重新组织提交记录,将多个提交合并为一个。
--mixed:默认模式,保留工作区更改
# 回退到指定提交,更改变为未暂存状态
git reset --mixed <commit-hash>
适用场景:重新审查代码,选择性提交部分更改。
--hard:彻底回退
# 彻底回退到指定提交,丢弃所有后续更改
git reset --hard <commit-hash>
风险提示:此操作会永久删除未提交的更改,使用前务必确认。
git revert:安全撤销式回退
git revert 通过创建新的提交来抵消指定提交的更改,保持历史记录完整性。
# 撤销单个提交
git revert <commit-hash>
# 撤销多个连续提交
git revert <oldest-commit>..<latest-commit>
# 撤销提交但不自动创建提交(便于修改)
git revert --no-commit <commit-hash>
对比reset和revert
以一个很简单的例子来说明
假设有初始提交历史:
A -- B -- C -- D (HEAD)
现在我们想回退到B提交,执行git reset B 后:
A -- B (HEAD)
(提交 C、D 从分支历史中移除)
那我们不执行reset,而是执行git revert B :
A -- B -- C -- D -- E (HEAD)
(提交 E 包含抵消提交 B 的更改)