Git 中的撤消:如何修复常见错误

2025-06-10

Git 中的撤消:如何修复常见错误

偶尔,或许并非总是如此,你可能会在提交工作流程中犯错。你忘记修复 Lint 错误,你的测试没有通过所以你需要先修复它,或者你忘记添加文件,也许你还没有准备好提交,也许你还没有打算推送。无论哪种情况,错误都会发生,你需要一种方法来撤销这些错误。以下是一些当这些错误发生时可以遵循的简单工作流程。

如何更改上一次提交

假设你在第一次提交时想要添加一些代码。于是你输入git status

nyxtom@enceladus: git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        index.css
        index.html
        load.js
        load2.js

nothing added to commit but untracked files present (use "git add" to track)

您继续使用 git add 添加这些文件。

nyxtom@enceladus$ git add index.css index.html load.js
~/libvar/map
nyxtom@enceladus$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   index.css
        new file:   index.html
        new file:   load.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        load2.js

~/libvar/map
nyxtom@enceladus$ git commit -m 'Adding initial project'
[master (root-commit) 9e5fc8f2] Adding initial project
 3 files changed, 187 insertions(+)
 create mode 100644 index.css
 create mode 100644 index.html
 create mode 100644 load.js

但是哎呀!你之前的提交有问题。你想修改一行代码。于是你修改了文件,然后使用git add -p

nyxtom@enceladus$ git add -p
diff --git a/load.js b/load.js
index 888a7fbd..f0cc06b3 100644
--- a/load.js
+++ b/load.js
@@ -28,6 +28,8 @@ function setup() {
     let text = [''];

     function draw() {
+        context.clearRect(0, 0, window.innerWidth, window.innerHeight);
+
         let offset = 100;
         let tokens = parse(text);
         tokens.forEach(token => {
(1/1) Stage this hunk [y,n,q,a,d,e,?]? y

您无需进行另一次提交,只需修改之前的提交即可!使用git commit --amend

nyxtom@enceladus$ git commit --amend -m 'Adding initial project'
[master 5923dfe9] Adding initial project
 Date: Fri Aug 28 11:40:45 2020 -0500
 3 files changed, 188 insertions(+)
 create mode 100644 index.css
 create mode 100644 index.html
 create mode 100644 load.js

太棒了!现在我们通过这个修改修复了上次提交的问题!

如何重置提交

现在假设您忘记添加一个文件,那么您可以继续进行另一次提交,如下所示:

nyxtom@enceladus$ git add load2.js
~/libvar/map (master)+
nyxtom@enceladus$ st
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   load2.js

~/libvar/map (master)+
nyxtom@enceladus$ git commit -m 'Test'
[master a1bf0355] Test
 1 file changed, 147 insertions(+)
 create mode 100644 load2.js

但是假设你暂时不需要这个提交。你运行了git push吗?没有?好的,太好了。你可以使用以下命令取消暂存 HEAD 处的最后一个提交:git reset --soft

nyxtom@enceladus$ git reset --soft HEAD^
~/libvar/map (master)+
nyxtom@enceladus$ st
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   load.js

现在之前的提交仍然处于暂存状态。这意味着它已准备好再次提交。如果你想取消暂存,请输入git restore --staged <file>

如何 rebase 和 squash 提交

假设您进行了几次类似下面的提交。

nyxtom@enceladus$ git log --oneline
9f44611c (HEAD -> master) Fix tests
2dd82c2b Better comments
5171bfac Fix spacing
ffda820e [#3203] Fixes input validation prior to user api requests

你意识到最后3 个提交实际上属于原始的错误修复提交。别担心!你可以利用git rebase这一点。让我们重新定位最后 4 个提交。

nyxtom@enceladus$ git rebase -i HEAD~4

你会注意到,使用 rebase 时,-i它​​是以交互方式进行的。这意味着你在此模式下所做的更改可以一次提交完成(前提是你要对多个提交进行更改)。弹出的编辑器将为你提供一些选项,如下所示:

pick ffda820e [#3203] Fixes input validation prior to user api requests
pick 5171bfac Fix spacing
pick 2dd82c2b Better comments
pick 9f44611c Fix tests

# Rebase 5923dfe9..9f44611c onto 9f44611c (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

由于我们关心的是将最后 3 个提交合并到第一个提交中,因此我们可以将它们全部更改pickfixup。这会将提交“压缩”到历史记录中的下一个提交中,并忽略该日志消息。这里有许多选项可供选择,因此我建议您仔细查看每个选项。

pick ffda820e [#3203] Fixes input validation prior to user api requests
fixup 5171bfac Fix spacing
fixup 2dd82c2b Better comments
fixup 9f44611c Fix tests

我的内置编辑器是vim这样的,当我输入时,:wqrebase 将完成,并且以下内容将输出到终端。

Successfully rebased and updated refs/heads/master.

太棒了!现在输入git log --oneline,你应该只看到一条提交!

nyxtom@enceladus$ git log --oneline
40122c65 (HEAD -> master) [#3203] Fixes input validation prior to user api requests

如何重新设置基准并再次推送这些更改

假设你正在处理一个拉取请求的分支,并且已经使用 推送到远程分支git push。你做了一些更改,并使用 撤消了提交历史记录git rebase。不幸的是,现在你的提交树与远程提交历史记录不同步了。你随时可以git push --force。这将强制远程历史记录与你当前的历史记录匹配。

如果其他人进行了远程更改,会发生什么?实际上,您可以运行以下命令--force-with-lease来确保不会覆盖其他人的更改。虽然这个方法不太为人所知,但绝对有用!

如何撤消 git rebase

假设你搞砸了 rebase,需要修复错误并恢复到之前的状态。git 的提交永远不会丢失,所以你可以使用它git reflog来查看 rebase 之前的提交历史记录。

nyxtom@enceladus$ git reflog
40122c65 (HEAD -> master, origin/master) HEAD@{0}: checkout: moving from 8115f1e263eeeee4bf8f75e90bbb6cca1a78cfbe to master
8115f1e2 HEAD@{1}: checkout: moving from master to 8115f1e263eeeee4bf8f75e90bbb6cca1a78cfbe
40122c65 (HEAD -> master, origin/master) HEAD@{2}: rebase (finish): returning to refs/heads/master
40122c65 (HEAD -> master, origin/master) HEAD@{3}: rebase (fixup): [#3203] Fixes input validation prior to user api requests
0b378bf2 HEAD@{4}: rebase (fixup): # This is a combination of 3 commits.
e3dc38ab HEAD@{5}: rebase (fixup): # This is a combination of 2 commits.
ffda820e HEAD@{6}: rebase (start): checkout HEAD~4
9f44611c HEAD@{7}: commit: Fix tests
2dd82c2b HEAD@{8}: commit: Better comments
5171bfac HEAD@{9}: commit: Fix spacing
ffda820e HEAD@{10}: commit: [#3203] Fixes input validation prior to user api requests

太棒了!让我们回到 rebase 发生之前的提交。

nyxtom@enceladus$ git reset 9f44611c
nyxtom@enceladus$ git log --oneline
9f44611c (HEAD -> master) Fix tests
2dd82c2b Better comments
5171bfac Fix spacing
ffda820e [#3203] Fixes input validation prior to user api requests
5923dfe9 Adding initial project

太棒了!你又可以正常营业了!

结论

如果你遇到麻烦,请记住,一切实际上都不会永远丢失git fsck --lost-found。即使你发现自己有一些孤立提交,这些提交实际上并没有附加到提交树中,你也可以使用它。请务必阅读git-scm了解更多信息!

和往常一样,如果你喜欢这篇文章,请点赞并关注我。如果你感兴趣,也可以关注我的推特!

干杯!🍻


如果您喜欢这篇文章,您可能还会对以下内容感兴趣:

再次感谢!

鏂囩珷鏉ユ簮锛�https://dev.to/nyxtom/how-to-undo-in-git-workflows-for-fixing-mistakes-4m02
PREV
如何构建 Vue CLI 插件
NEXT
在 Docker-Compose 中使用变量简介使用环境选项使用 .env 文件使用 env-file 选项结论