如何修复 Git 中最常见的错误 - 保存此信息以备不时之需 将更改推送到错误的分支 忘记在切换分支之前提交暂存的更改 撤消错误的合并冲突 意外删除分支 恢复到您不想恢复的旧版本代码 意外提交敏感信息(例如密码、个人数据)

2025-06-09

如何修复 Git 中最常见的错误 - 保存此内容以备不时之需

将更改推送到错误的分支

切换分支前忘记提交暂存的变更

撤销错误的合并冲突

意外删除分支

恢复到你不想恢复的旧版本代码

意外提交敏感信息(例如密码、个人数据)

我们都知道 Git 在跟踪变化、简化多个开发人员之间的协作以及简化 DevOps 操作方面非常出色,并且它以最简单的方式完成所有这些工作。

然而,Git 中的一切都不是那么简单,或者至少看起来不那么简单,直到您知道如何使用 Git 来处理它们。

在本教程中,我们采用了一种非常不同的方法,假设您了解 Git 的基础知识,我们尝试了解如何修复在由 Git 控制的项目版本上工作时可能犯的常见错误。

我描述每个场景,然后向您展示如何解决问题。

在继续之前,请记住,您可以免费 使用DoTenX快速构建您的网站、Web 应用API落地页等等 。请务必试用,甚至可以提名您的作品进行展示。DoTenX 是开源的,您可以在这里找到它的仓库:github.com/dotenx/dotenx


让我们开始吧。

将更改推送到错误的分支

你做了一些修改,甚至可能删除了一些文件,还可能添加了新文件,提交了修改并推送。突然间,你意识到你检出了同事的分支!哎呀!

让我们修复它。

假设我们在 John 的分支上有这些文件:

并且您在 b.txt 中添加了一行并删除了 a.txt。

首先,使用git log命令找到我们要撤消的提交:

$ git log
19f2583 (HEAD -> john-branch, origin/john-branch) bad commit
a0cd48e add hoy
701ae1d (origin/main, main) initial commit
Enter fullscreen mode Exit fullscreen mode

我们想要撤消 sha 19f2583 的提交,因此我们使用git revert

$ git revert 19f2583
Enter fullscreen mode Exit fullscreen mode

在您的终端中,系统将提示您提交的详细信息,您可以使用退出:wq并使用推送由 revert 生成的提交git push

到目前为止,你让约翰很高兴,但是有一个问题,那就是你失去了所有宝贵的劳动成果!或者也许不是。

深呼吸并切换到您的分支,然后使用git cherry-pick命令将您恢复到当前分支的提交中的更改应用到您的当前分支:

$ git cherry-pick 19f2583
Enter fullscreen mode Exit fullscreen mode

事情可能有点复杂,但这只是我们之间的友好冲突!根据你之前在自己的分支中是否有过修改,你可能会遇到一个或多个冲突。

在我的例子中,它显示文件 b.txt 已被删除,而我们只是在该文件中添加了一行。让我们使用以下命令查看更改git status

$ git status
On branch my-branch
You are currently cherry-picking commit 19f2583.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
        deleted:    a.txt

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
        deleted by us:   b.txt
Enter fullscreen mode Exit fullscreen mode

为了解决此类情况下的合并冲突,我发现了两个简单的规则:

  • 如果编辑了文件并且您在文件中看到冲突标记,只需选择您想要的更改

  • 如果它显示文件已被删除并且导致冲突,只需听取以下消息git status:(使用“git add/rm <file>...”适当标记解决方案)

我只需运行git add b.txt,冲突就解决了。

$ git add b.txt
$ git cherry-pick --continue

bad commit

# Conflicts:
#       b.txt
#
# It looks like you may be committing a cherry-pick.
# If this is not correct, please run
#       git update-ref -d CHERRY_PICK_HEAD
# and try again.


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
#
# On branch my-branch
# You are currently cherry-picking commit 19f2583.
#
Enter fullscreen mode Exit fullscreen mode

接受消息或更改它(它只是在您的终端中打开的 Vim 文档)并退出编辑:wq

别忘了追赶git push这个。

切换分支前忘记提交暂存的变更

你做了一些修改并暂存它们,然后不小心强行切换到了另一个分支!没错,当你过度依赖命令历史记录时,就会发生这种情况。

首先使用git fsck来查找变化:

$ git fsck --lost-found
Checking object directories: 100% (256/256), done.
dangling blob 98a727d446286e784a6d64a82e719ea6b626d53e
Enter fullscreen mode Exit fullscreen mode

切换回你的分支并使用git show <id>查看你丢失的内容:

$ git switch my-branch
$ git show 98a727d446286e784a6d64a82e719ea6b626d53e
hoy
This is a cool change by me

something
Enter fullscreen mode Exit fullscreen mode

现在您已经获得了更改并可以将其放回原来的位置。

撤销错误的合并冲突

您将一个分支合并到另一个分支,两个分支中相同的文件中有一行或多行发生了更改,并且遇到了合并冲突。到目前为止一切顺利,您通过保留更改解决了问题,提交合并并推送。代码已部署,但您意识到您不应该合并这些更改(可能是您的分支存在错误或导致了一些问题)。

我们先来模拟一下这种情况。

git log在分支1中:

[branch1]$ git log
ec0cf4e (HEAD -> branch1) add bye
701ae1d (origin/main, main, branch2) initial commit
Enter fullscreen mode Exit fullscreen mode

git log在分支2中:

[branch2]$ git log
073e46d (HEAD -> branch2) add yo
701ae1d (origin/main, main) initial commit
Enter fullscreen mode Exit fullscreen mode

现在我们合并它们并且💥:

$ git checkout branch1
$ git merge branch1
Auto-merging a.txt
CONFLICT (content): Merge conflict in a.txt
Automatic merge failed; fix conflicts and then commit the result.
Enter fullscreen mode Exit fullscreen mode

我们接受一些改变,并假装它不是我们想要的。

我们现在就修复它。

首先,让我们使用以下方法查找提交历史记录git log

$ git log --oneline
4bf3368 (HEAD -> branch2) Merge branch 'branch1' into branch2
073e46d add yo
ec0cf4e (branch1) add bye
701ae1d (origin/main, main) initial commit
Enter fullscreen mode Exit fullscreen mode

现在,我们可能面临两种不同的情况:

  1. 合并后没有任何更改合并到目标分支

  2. 合并后还有其他更改合并到目标分支

如果您足够幸运地处于情况 1,只需使用git reset(不是revert)重写历史记录并将 Head 移动到您想要的提交:

$ git reset --Hard 073e46d
Enter fullscreen mode Exit fullscreen mode

此后,您撤消了更改并保留了干净的历史记录:

$ git log --oneline
073e46d (HEAD -> branch2) add yo
701ae1d (origin/main, main) initial commit
Enter fullscreen mode Exit fullscreen mode

如果您继续在分支上工作以确保其状态良好以便再次合并(尽管 Git 会将其视为您第一次合并它们),这将特别有用。

如果你不那么幸运,更改后有一些变化,你需要撤消你的更改(git rever -m 1 <merge commit sha>):

$ git revert -m 1 4e5278e
Enter fullscreen mode Exit fullscreen mode

(* 我再次合并了分支,这就是合并提交 sha 改变的原因)

提交更改后,历史记录将如下所示:

$ git log --oneline
0d49d3d (HEAD -> branch2) Revert "Merge branch 'branch1' into branch2"
4e5278e Merge branch 'branch1' into branch2
073e46d add yo
ec0cf4e (branch1) add bye
701ae1d (origin/main, main) initial commit
Enter fullscreen mode Exit fullscreen mode

现在一切都恢复正常,唯一的问题是,如果您想继续在您的分支上工作并修复它并稍后再次合并它,您必须恢复此恢复提交。

意外删除分支

是的,有人会这么做!实际上,如果你正在读这篇文章,你可能已经删除了你的分支,所以这种情况确实会发生。

让我们通过删除之前创建的 branch2 来模拟这种情况。

首先运行git reflog命令来查找包含丢失工作的提交:

$ git reflog
701ae1d (HEAD -> main, origin/main) HEAD@{0}: checkout: moving from branch2 to main
0d49d3d HEAD@{1}: commit: Revert "Merge branch 'branch1' into branch2"
4e5278e HEAD@{2}: commit (merge): Merge branch 'branch1' into branch2
073e46d HEAD@{3}: reset: moving to 073e46d
4bf3368 HEAD@{4}: reset: moving to 4bf3368
4bf3368 HEAD@{5}: commit (merge): Merge branch 'branch1' into branch2
073e46d HEAD@{6}: checkout: moving from branch2 to branch2
073e46d HEAD@{7}: commit: add yo
701ae1d (HEAD -> main, origin/main) HEAD@{8}: checkout: moving from branch1 to branch2
...
Enter fullscreen mode Exit fullscreen mode

现在使用git cherry-pick包含您丢失的工作的任何提交。

$ git cherry-pick 0d49d3d
Enter fullscreen mode Exit fullscreen mode

按照前面描述的步骤完成挑选,您将恢复丢失的更改。

恢复到你不想恢复的旧版本代码

无论出于何种原因,你回滚了代码,但这不是你想要恢复的提交。现在有两种情况:

  1. 您尚未推送恢复提交

  2. 您已推动恢复提交

首先,我们来模拟一下这种情况。我创建了一个分支,其历史记录如下:

$ git log --oneline
e9f0ccf (HEAD -> bad-revert) Revert "Add yo"
d7b0df1 Add yo
8929a21 Add hoy
701ae1d (origin/main, main, branch3) initial commit
Enter fullscreen mode Exit fullscreen mode

现在,如果您处于第一种情况,只需运行git reset

$ git reset --hard Head^
Enter fullscreen mode Exit fullscreen mode

如果从未发生过恢复,那么历史记录就是干净的。

$ git log 
d7b0df1 (HEAD -> bad-revert) Add yo
8929a21 Add hoy
701ae1d (origin/main, main, branch3) initial commit
Enter fullscreen mode Exit fullscreen mode

请记住,这Head^意味着直系亲属,是的缩写Head^1

现在,如果您在还原后推动了提交,那么您可以使用以下方式还原还原git revert <revert commit sha>或使用git cherry-pick <commit before bad revert>更清晰的历史记录 IMO:

$ git revert c92103a
2e74087 (HEAD -> bad-revert) Revert "Revert "Add yo""
c92103a Revert "Add yo"
d7b0df1 Add yo
8929a21 Add hoy
701ae1d (origin/main, main, branch3) initial commit
Enter fullscreen mode Exit fullscreen mode

(* 我重置了更改并尝试使用 cherry-pick)

$ git cherry-pick cb174c0
bf188c6 (HEAD -> bad-revert) Add yo
cb174c0 Revert "Add yo"
d7b0df1 Add yo
8929a21 Add hoy
701ae1d (origin/main, main, branch3) initial commit
Enter fullscreen mode Exit fullscreen mode

意外提交敏感信息(例如密码、个人数据)

哎呀!

您是否知道这是黑客攻击组织的最常见/最有效的方法之一?

好吧,你做了不该做的事,我们还是先别写辞职信,先把问题解决了再说吧。

顺便说一句,使用类似这样的工具来避免提交敏感信息确实是个好主意git secrets。它的设置和使用并不难,但如果您希望我写一个教程,请在评论区告诉我。

我们先来模拟一下这种情况。

$ git checkout -b b1
$ echo secrets > .env.production
$ echo randomchange >> a.txt
$ git add .
$ git commit -m "some good and bad changes"
$ git checkout main
$ git merge b1
$ git checkout -b b2
$ echo secrets2 >> .env.production
$ echo randomchange2 >> a.txt
$ git add .
$ git commit -m "again some good and bad changes"
$ git checkout main
$ git merge b2
Enter fullscreen mode Exit fullscreen mode

主分支上的历史记录如下:

$ git log --oneline
f136e55 (HEAD -> main, b2) again some good and bad changes
659b0c0 (b1) some good and bad changes
701ae1d (origin/main, branch3) initial commit
Enter fullscreen mode Exit fullscreen mode

现在让我们使用git filter-branch命令来修复它,从存储库的历史记录中删除敏感信息:

$ git filter-branch --force --index-filter \                                                 
  "git rm --cached --ignore-unmatch .env.production" \       
  --prune-empty --tag-name-filter cat -- --all

WARNING: git-filter-branch has a glut of gotchas generating mangled history
         rewrites.  Hit Ctrl-C before proceeding to abort, then use an
         alternative filtering tool such as 'git filter-repo'
         (https://github.com/newren/git-filter-repo/) instead.  See the
         filter-branch manual page for more details; to squelch this warning,
         set FILTER_BRANCH_SQUELCH_WARNING=1.
Proceeding with filter-branch...

Rewrite 659b0c01f0295d64ba199cc33e9fd2af8862e088 (11/13) (4 seconds passed, remaining 0 predicted)    rm '.env.production'
Rewrite f136e557fbc7359444f2154457c2bef54ea5d489 (11/13) (4 seconds passed, remaining 0 predicted)    rm '.env.production'

Ref 'refs/heads/b1' was rewritten
Ref 'refs/heads/b2' was rewritten
WARNING: Ref 'refs/heads/bad-revert' is unchanged
WARNING: Ref 'refs/heads/branch3' is unchanged
WARNING: Ref 'refs/heads/john-branch' is unchanged
Ref 'refs/heads/main' was rewritten
WARNING: Ref 'refs/heads/my-branch' is unchanged
WARNING: Ref 'refs/remotes/origin/john-branch' is unchanged
WARNING: Ref 'refs/remotes/origin/main' is unchanged
WARNING: Ref 'refs/remotes/origin/my-branch' is unchanged
Ref 'refs/stash' was rewritten
Enter fullscreen mode Exit fullscreen mode

此命令将过滤器应用于存储库中的所有提交,并从历史记录中删除指定的文件。我们使用--forceflag 覆盖现有历史记录,并使用--prune-emptyflag 删除由于过滤器而创建的空提交。

让我们看看它是如何改变历史的:

$ git log --oneline
87c7e80 (HEAD -> main, b2) again some good and bad changes
c772ec0 (b1) some good and bad changes
701ae1d (origin/main, branch3) initial commit
Enter fullscreen mode Exit fullscreen mode

正如您所看到的,不仅秘密文件被删除,同时保留了其他所有内容(在所有分支中),历史记录也没有被修改。

不要忘记使用 来推动改变git push


Git 是开发者最好的朋友,虽然它能帮我们避免很多问题,但犯错在所难免。作为开源项目DoTenX的维护者,我时不时会遇到各种与 Git 相关的挑战,但最终,除非你真的搞砸了,否则 Git 总能为你提供解决方案。

最后,我再次邀请您查看 DoTenX 及其代码库,将其作为基于无服务器架构的 Wordpress 的现代替代方案,并具有前后端分离的特性。请记住,支持开源是免费的,并且从为您想要发展的项目添加⭐️开始。

错误修复链接:https://dev.to/mohsenkamrani/how-to-fix-the-most-common-mistakes-in-git-learn-it-by-breaking-it-286m
PREV
第二部分:软件开发中的设计原则
NEXT
无服务器开发人员的经验教训