HOWTO · Git
撤消本地仓库中的最后一次 Git 提交
你可以撤消最后一次 git 提交并保留文件更改。
本页内容
要撤销本地提交,请根据你希望如何处理其中已跟踪的更改,使用 git reset 的相应模式:保留暂存状态、保留为未暂存状态,或丢弃更改。重置会将当前分支移回较早的提交。如果该提交已经共享,建议使用 git revert,以保留共享历史。
选择重置模式
提交记录一个快照,索引保存下一个待提交的快照,工作区则包含当前检出的文件。git reset 会将当前分支指针移到选定的目标提交。所用模式决定是否同时更改索引和工作区:
--soft移动分支指针,但保持索引和工作区不变。--mixed移动分支指针,并将索引重置到目标提交,同时保留工作区文件。这是默认模式。--hard移动分支指针,并将索引和已跟踪的工作区文件都重置到目标提交。这可能会丢弃已跟踪的工作成果。
假设提交历史为 A — B — C,当前检出的是 C。重置到 HEAD~1 会将分支移回 B;如何处理 C 引入的更改,取决于所用模式。
撤销最近一次提交并保留暂存的更改
如果你想撤销提交,同时让其中的更改继续保留在索引中,以便再次提交或修改后重新提交,请使用 --soft:
命令为 git reset --soft HEAD~1。
执行后,HEAD 指向前一个提交,被撤销提交中的更改仍处于暂存状态。创建替代提交之前,可以用 git diff --cached 检查这些更改。
撤销最近一次提交并保留未暂存的更改
使用 --mixed 撤销提交,并将其中已跟踪的更改保留在工作区,但从索引中移除:
命令为 git reset --mixed HEAD~1。
这些文件仍然是已跟踪文件;相对于新的 HEAD,它们的差异会在 git status 中显示为未暂存的修改。由于 --mixed 是默认模式,git reset HEAD~1 的效果相同。如果你想重新检查这些更改或选择性地暂存它们,这种方式很有用。
撤销最近一次提交并丢弃已跟踪的更改
只有在确定要从索引和工作区中丢弃已提交的更改时,才使用 --hard。它会将已跟踪文件重置为与目标提交一致;这些文件中尚未提交的更改也可能丢失。普通的未跟踪文件通常会保留,但如果未跟踪文件或目录阻碍了目标提交中已跟踪路径的写入,它们也可能被删除。运行命令前,请检查 git status 并保存可能还需要的内容。
命令为 git reset --hard HEAD~1。
选择提交目标并验证结果
HEAD~1 表示当前提交的第一个父提交;HEAD~2 表示向前两个提交。请谨慎选择目标,因为重置会将当前分支移到该位置。可以使用 git log --oneline --graph -5 查看最近的提交历史。
然后重置到预期目标,例如 git reset --mixed HEAD~2。使用 git log --oneline -3 和 git status 检查分支及文件状态。
运行以下示例:
本节中的代码以及显示的标签或输出仍为英文。
#!/usr/bin/env bash
set -eu
repo=$(mktemp -d)
trap 'rm -rf "$repo"' EXIT
cd "$repo"
git init -q
git config user.name Example
git config user.email example@example.com
printf 'first\n' > note.txt
git add note.txt
git commit -qm 'Add note'
printf 'second\n' >> note.txt
git commit -qam 'Extend note'
git reset --mixed HEAD~1 >/dev/null
git status --short
输出中的状态标记保持英文;它表示文件已修改,且更改尚未暂存。
M note.txt
该脚本会创建一个临时仓库,进行两次提交,然后重置到较早的提交,并将最近一次更改保留为未暂存状态,最后显示状态信息。脚本退出时,清理陷阱会删除临时仓库。
如果提交已经共享
如果其他人已经获取了该提交,重置会改写分支历史。推送重置后的分支时,协作者可能需要协调并同步各自的副本,普通推送也可能被拒绝。对于已经发布到共享分支的提交,git revert <commit> 会创建一个新提交来撤销先前的更改,而不会将其从历史中删除。改写共享分支历史之前,请先与协作者协调。