如何修复 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
我们想要撤消 sha 19f2583 的提交,因此我们使用git revert
:
$ git revert 19f2583
在您的终端中,系统将提示您提交的详细信息,您可以使用退出:wq
并使用推送由 revert 生成的提交git push
。
到目前为止,你让约翰很高兴,但是有一个问题,那就是你失去了所有宝贵的劳动成果!或者也许不是。
深呼吸并切换到您的分支,然后使用git cherry-pick
命令将您恢复到当前分支的提交中的更改应用到您的当前分支:
$ git cherry-pick 19f2583
事情可能有点复杂,但这只是我们之间的友好冲突!根据你之前在自己的分支中是否有过修改,你可能会遇到一个或多个冲突。
在我的例子中,它显示文件 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
为了解决此类情况下的合并冲突,我发现了两个简单的规则:
-
如果编辑了文件并且您在文件中看到冲突标记,只需选择您想要的更改
-
如果它显示文件已被删除并且导致冲突,只需听取以下消息
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.
#
接受消息或更改它(它只是在您的终端中打开的 Vim 文档)并退出编辑:wq
。
别忘了追赶git push
这个。
切换分支前忘记提交暂存的变更
你做了一些修改并暂存它们,然后不小心强行切换到了另一个分支!没错,当你过度依赖命令历史记录时,就会发生这种情况。
首先使用git fsck
来查找变化:
$ git fsck --lost-found
Checking object directories: 100% (256/256), done.
dangling blob 98a727d446286e784a6d64a82e719ea6b626d53e
切换回你的分支并使用git show <id>
查看你丢失的内容:
$ git switch my-branch
$ git show 98a727d446286e784a6d64a82e719ea6b626d53e
hoy
This is a cool change by me
something
现在您已经获得了更改并可以将其放回原来的位置。
撤销错误的合并冲突
您将一个分支合并到另一个分支,两个分支中相同的文件中有一行或多行发生了更改,并且遇到了合并冲突。到目前为止一切顺利,您通过保留更改解决了问题,提交合并并推送。代码已部署,但您意识到您不应该合并这些更改(可能是您的分支存在错误或导致了一些问题)。
我们先来模拟一下这种情况。
git log
在分支1中:
[branch1]$ git log
ec0cf4e (HEAD -> branch1) add bye
701ae1d (origin/main, main, branch2) initial commit
git log
在分支2中:
[branch2]$ git log
073e46d (HEAD -> branch2) add yo
701ae1d (origin/main, main) initial commit
现在我们合并它们并且💥:
$ 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.
我们接受一些改变,并假装它不是我们想要的。
我们现在就修复它。
首先,让我们使用以下方法查找提交历史记录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
现在,我们可能面临两种不同的情况:
-
合并后没有任何更改合并到目标分支
-
合并后还有其他更改合并到目标分支
如果您足够幸运地处于情况 1,只需使用git reset
(不是revert
)重写历史记录并将 Head 移动到您想要的提交:
$ git reset --Hard 073e46d
此后,您撤消了更改并保留了干净的历史记录:
$ git log --oneline
073e46d (HEAD -> branch2) add yo
701ae1d (origin/main, main) initial commit
如果您继续在分支上工作以确保其状态良好以便再次合并(尽管 Git 会将其视为您第一次合并它们),这将特别有用。
如果你不那么幸运,更改后有一些变化,你需要撤消你的更改(git rever -m 1 <merge commit sha>
):
$ git revert -m 1 4e5278e
(* 我再次合并了分支,这就是合并提交 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
现在一切都恢复正常,唯一的问题是,如果您想继续在您的分支上工作并修复它并稍后再次合并它,您必须恢复此恢复提交。
意外删除分支
是的,有人会这么做!实际上,如果你正在读这篇文章,你可能已经删除了你的分支,所以这种情况确实会发生。
让我们通过删除之前创建的 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
...
现在使用git cherry-pick
包含您丢失的工作的任何提交。
$ git cherry-pick 0d49d3d
按照前面描述的步骤完成挑选,您将恢复丢失的更改。
恢复到你不想恢复的旧版本代码
无论出于何种原因,你回滚了代码,但这不是你想要恢复的提交。现在有两种情况:
-
您尚未推送恢复提交
-
您已推动恢复提交
首先,我们来模拟一下这种情况。我创建了一个分支,其历史记录如下:
$ git log --oneline
e9f0ccf (HEAD -> bad-revert) Revert "Add yo"
d7b0df1 Add yo
8929a21 Add hoy
701ae1d (origin/main, main, branch3) initial commit
现在,如果您处于第一种情况,只需运行git reset
:
$ git reset --hard Head^
如果从未发生过恢复,那么历史记录就是干净的。
$ git log
d7b0df1 (HEAD -> bad-revert) Add yo
8929a21 Add hoy
701ae1d (origin/main, main, branch3) initial commit
请记住,这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
(* 我重置了更改并尝试使用 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
意外提交敏感信息(例如密码、个人数据)
哎呀!
您是否知道这是黑客攻击组织的最常见/最有效的方法之一?
好吧,你做了不该做的事,我们还是先别写辞职信,先把问题解决了再说吧。
顺便说一句,使用类似这样的工具来避免提交敏感信息确实是个好主意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
主分支上的历史记录如下:
$ 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
现在让我们使用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
此命令将过滤器应用于存储库中的所有提交,并从历史记录中删除指定的文件。我们使用--force
flag 覆盖现有历史记录,并使用--prune-empty
flag 删除由于过滤器而创建的空提交。
让我们看看它是如何改变历史的:
$ 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
正如您所看到的,不仅秘密文件被删除,同时保留了其他所有内容(在所有分支中),历史记录也没有被修改。
不要忘记使用 来推动改变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