LewisQu
发布于 2026-03-08 / 8 阅读
0
0

git revert用法及原理

1. git revert 命令详解

git revert 是 Git 中用于安全撤销之前提交的更改的命令。它不会删除历史记录,而是创建一个新的提交来反向应用目标提交的变更,从而保留完整的项目演变轨迹。接下来介绍用法、原理及实际场景。

2. 基本用法

2.1.1. 撤销单个提交

git revert <commit-hash>

例如,撤销最近一次提交:

git revert HEAD

执行后,Git 会自动生成一个反向提交,并弹出编辑器让你填写提交信息(默认已包含 "Revert" 字样)。保存退出后,新的撤销提交就会创建成功。

2.1.2. 撤销多个提交

可以一次撤销多个连续的提交(按提交顺序反向应用):

git revert <oldest-commit>..<newest-commit>

例如,撤销从 abc123def456 之间的所有提交(不含 abc123,含 def456):

git revert abc123..def456

如果要包含起始提交,使用三个点:

git revert abc123...def456   # 包含 abc123 和 def456 之间的所有提交

也可以逐个列出多个提交:

git revert abc123 def456

Git 会依次为每个提交创建反向提交,如果中途有冲突,解决后使用命令 git revert --continue处理。

2.1.3. 撤销合并提交(merge commit)

撤销合并提交时,必须指定主线(mainline),即保留哪个父分支的代码。因为合并提交有两个父提交,Git 需要知道要以哪个父提交为基准生成反向变更。

git revert -m 1 <merge-commit-hash>
  • -m 1 表示保留第一个父提交的内容(通常是合并时所在的分支),撤销来自另一个分支的变更。

  • -m 2 则相反。

2.1.4. 常用选项

  • -e / --edit:编辑提交信息(默认行为)。

  • --no-edit:使用自动生成的提交信息,不打开编辑器。

  • -n / --no-commit:只将反向更改应用到工作区和暂存区,但不自动提交。这样你可以在提交前进一步修改。

  • --continue:解决冲突后继续执行 revert

  • --abort:取消当前的 revert 操作,恢复到操作前的状态。

  • --skip:跳过当前提交的撤销(很少用)。

3. 原理

3.1.1. 核心思想

git revert 的本质是通过创建一个新的提交来抵消指定提交的变更。它不会修改项目的历史记录,因此非常适合用于公共分支(如 maindevelop),因为它不会给其他协作者带来历史不一致的问题,不需git push --force

3.1.2. 内部工作流程

运行 git revert <commit> 时,Git 大致执行以下步骤:

1. 计算反向补丁

Git 会比较目标提交 <commit> 和它的父提交 <commit>^(如果是合并提交,则根据 -m 指定的父提交),得到一个差异(diff)。然后将这个差异反向应用:例如原提交中添加的行会被删除,删除的行会被恢复。

2. 应用反向补丁到工作区

将计算出的反向变更应用到当前工作目录和暂存区。类似于手动执行 git diff <commit>^ <commit> | git apply -R

3. 创建新的提交

Git 会暂存(stash) 这些变更,然后创建一个新的提交。会自动生成新提交的提交信息,通常以 Revert "原提交信息" 开头,并包含被还原的提交的哈希值。

3.1.3. 与 git reset 的区别

命令

行为

是否修改历史

适用场景

git reset

移动分支指针,丢弃指定提交之后的提交,可能丢失更改(除非用 --keep

本地未推送的分支,彻底删除错误提交

git revert

新建一个提交,反向应用指定提交的更改,保留所有历史记录

公共分支,需要安全地撤销提交

3.1.4. 冲突处理

如果反向补丁与当前分支的最新状态冲突(例如后续有其他提交修改了相同的代码行),Git 会暂停 revert 过程,提示手动解决冲突。解决后,用 git add 标记已解决,然后执行 git revert --continue 完成操作。

3.1.5. 撤销多个提交时的顺序

当撤销多个提交时,Git 会从命令行指定的最后一个提交开始,逐个向前生成反向提交。这样可以保证每个反向提交都能基于前一个反向提交后的状态的正确顺序来处理。

4. 实际示例

4.1.1. 场景:不小心推送了一个有 bug 的提交 abc123

# 1. 查看提交历史
git log --oneline

# 2. 撤销该提交
git revert abc123

# 3. Git 自动创建了一个新的提交 "Revert 'fix: 添加新功能'"
# 查看日志可以看到两条记录:原提交和还原提交
git log --oneline

4.1.2. 场景:撤销多个提交,但不立即提交,以便合并调整

git revert -n HEAD~2..HEAD   # 撤销最近两个提交,但只暂存更改

# 做一些额外修改
git add .
git commit -m "Revert two commits and also fix something"

4.1.3. 场景:撤销合并提交 merge-commit

加入在 main 分支上合并了 feature 分支(合并提交为 m1),之后想撤销这次合并但保留 main 上的其他更改。

git revert -m 1 m1

这样会生成一个新的提交,将 main 分支恢复到合并前的状态,但 feature 分支的历史依然存在。

5. 总结

  • 用途:安全地撤销已推送的提交,适合公共分支,保持项目历史的清晰和完整。

  • 原理:通过反向应用目标提交的变更,创建一个新提交来抵消原提交的影响。

  • 关键点:不重写历史,只追加新提交。

  • 注意:撤销合并(merge) 提交时需指定主线;撤销多个提交时按逆序处理。


评论