错误!这些在软件开发中不是必需的。但他们总是想方设法玷污软件开发之美。
所以,错误是不可避免的。你如何从错误中恢复过来?
版本控制系统的一个有用功能是撤消功能。
Git 是一个极好的安全网,可以让你在错误的行动中再次获得机会。
摘要:在本文中,我概述了您可能会遇到的错误场景以及可以让您从错误中解脱出来的 Git 技术。
1、停止跟踪跟踪的文件
您有一个node_modules不希望被 git 跟踪的文件夹。
您提交node_modules了文件夹,现在您意识到您忘记使用.gitignore文件忽略它。您添加.gitignore文件并列出其中的node_modules文件夹,然后提交。
但 Git 仍在跟踪它(node_modules)。这是因为,一旦文件被添加并提交到 Git 数据库,Git 将继续跟踪对它的更改。
所以你想阻止 Git 跟踪node_modules文件夹。
赶紧跑:
git rm -r --cached node_modules
2、修改Last Commit
您已提交到本地 Git 数据库。此后,您意识到您忘记在该提交中包含文件更改(您可能尚未保存文件)。或者您添加一个新文件,您希望它与您最近提交的同一提交相关联。
Git 可以解锁先前的提交并允许您添加新文件。
只需这样做:
首先,您使用以下命令添加丢失的文件:
git add newfile.ts
然后,运行:
git commit --amend --no-edit
该--no-edit标志在不更改提交消息的情况下修改提交。
3、修改Last Commit Message
这种情况与上述情况类似。但是这一次,你已经提交到 git并且你对你指定的提交信息不是很满意。您希望消息具有更多的含义来描述您所做的事情。
再次,Git 允许您修复之前糟糕的提交消息。
只需运行:
git commit --amend -m "Phew! A better commit message this time"
4、丢弃工作目录中的所有更改
您正在处理您的项目。例如,您可能正在重构代码以遵循更好的模式和简洁的代码原则。在重构时,您破坏了应用程序中的功能,并且无法弄清楚真正出了什么问题。您现在想要返回到应用程序正常工作的先前状态(提交),以便您可以再次找到您的方位。
因此,您想丢弃所有未提交的更改,并将 Git 工作树恢复到上次提交时的状态。
使用命令:
git restore .
注意:此命令将您的工作副本恢复到本地 git 数据库中的最新提交。您未提交的更改将永久丢失。
5、放弃对文件所做的所有更改
您已在本地 git 存储库中修改了文件。您稍后会意识到您对特定文件(connect.js)所做的更改并不那么智能,应该被丢弃。但是您想保留对其他文件所做的更改。
因此,您希望文件connect.js恢复到上一次提交时的状态。
这可以通过 Git 实现:
git restore connect.js
6、将文件及时恢复到旧版本
与上述命令不同,在这种情况下,您希望项目中的特定文件返回到比上一次提交更早的状态。
因此,例如,如果版本 3 是您之前的提交,您希望此特定文件显示为早于版本 3 的版本 2。
使用 Git:及时查找并复制提交哈希:
git log
然后:
git restore --source <commit-hash> <filename>
就这么简单,对吧?
7、恢复已删除的文件(以前提交)
您正在对项目进行新的更改,并看到一个过时的文件。您继续删除文件,以便释放空间。一段时间后,您意识到您需要刚刚删除的文件。
要恢复您的文件:
git restore deleted-file.css
这会将文件呈现给您,就像它在上一次提交中一样。
8、将本地仓库中的所有更改丢弃到远程的确切状态
您已经在本地 repo 分支中进行了一些更改和提交。你已经重新布线,现在你问自己,“我为什么一开始就做出这些改变?”
因此,您希望忘记当前本地分支上的所有内容,并使其与远程主分支中的内容完全相同。
只需撤消:
git reset --hard origin/main
注意:未提交的更改将永久丢失。
9、删除未跟踪的文件
您在项目中创建了几个新文件并修改了一些文件。您已经改变了方法,现在决定不再需要您创建的任何这些新文件,而是坚持修改后的文件更改。
Git 为您提供了删除未跟踪文件的命令:
git clean -f
该git clean命令需要一个-f暗示强制指令的标志(也--force)。由于此操作需要删除未跟踪的文件,因此它必须要求您确定自己在做什么,因为在 Git 中摆脱未提交的工作是undoable。
默认情况下,此命令不会删除由.gitignore. 指定-x导致删除被忽略文件的选项。
也不git clean会对目录进行递归操作。这是防止意外永久删除的另一种安全机制。
要同时删除目录,请使用-d如下标志:
git clean -df
这将清除未跟踪的文件和目录,但不会删除文件中列出的文件和目录.gitignore。
10、将提交切换到不同的分支
该项目已经发展,您目前正在开发两个功能:添加时事通讯和微调页脚布局。您已经创建了两个独立的分支:newsletter和footer-layout,将每个分支专用于相关的功能:分别为时事通讯和页脚布局。
您当前正在添加时事通讯功能newsletter并从分支进行一些提交。下次你回到你的项目时,你想要处理页脚布局功能并且你忘记切换到相关的footer-layout分支。您从错误的分支添加页脚布局newsletter功能并提交给它。
后来,您注意到您添加到newsletterfooter-branch分支的提交实际上属于.
因此,您希望将添加页脚布局功能的提交从newsletter分支移至其正确的footer-layout分支。
这是在 Git 中要做的事情:
签出newsletter分支:
git checkout newsletter
查找并复制添加了页脚布局功能的提交的提交哈希。运行命令:
git log
签出您要使用此提交应用的合法分支。在我们的例子中:
git checkout footer-layout
然后应用提交:
git cherry-pick <commit-hash>
然后签出newsletter分支:
git checkout newsletter
并将它从这个不需要的提交中剥离,这是添加页脚布局的提交:
git reset HEAD~1 --hard
HEAD~1意味着我们正在重置我们的newsletter分支以将一个提交移到最近的提交之后,并删除我们已经移出的提交。newsletter请记住,在我们的案例中,此分支上的最新提交是具有footer-layout 功能的提交。
11、复活已删除的分支
您认为您不再需要功能分支并且您在其上摆动垃圾桶(删除它)。下次,您会担心删除它是一个错误。现在你处于“恐慌模式”。你想不可能回到过去并把它找回来。
因此,您想取回已删除的分支。
这是恢复已删除分支的方法:
查找并复制已删除分支的提交哈希,当您运行命令时将列出该哈希:
git reflog
然后将您的分支重新创建为:
git branch <branch-name> <deleted-branch-commit-hash>
这将重新创建一个分支,其中包含<deleted-branch-commit-hash>之前的所有工作。如果<deleted-branch-commit-hash>不是已删除分支中的最新作品,您仍然可以找到新的提交哈希,直到您获得最新作品。键入git branch,您将再次看到之前删除的分支。即使分支在原点(远程)中被删除,这也有效。
此外,如果<branch-name>不是您想要的名称,只需将其重命名为git branch -m <branch-name> <new-branch-name>.
不用说,成功恢复已删除分支的关键是找到正确的提交哈希,因此智能地命名您的提交;它有很大帮助。
12、回退/撤消错误的提交
您的团队推出了一个新版本的项目。你们都确信添加的所有新功能绝对是大师级的。片刻之后,来自团队领导的紧急电话表明推出的新版本存在严重缺陷,需要立即修复。工程团队需要紧急行动,坐下来发现缺陷并不是对紧急事件的及时响应。
最快的响应之一是撤消对容易出错的版本所做的更改。
因此,您想要撤消对提交所做的更改。
这是如何在 Git 中进行的:
查找并复制要撤消更改的提交的提交哈希(损坏的提交):
git log
恢复该提交指定的更改:
git revert <broken-commit-hash>
git revert使用还原(反向)更改创建新提交。在损坏的提交中指定的所有更改都将在新提交中回滚(撤消)。例如,在损坏的提交中删除的任何内容都将添加到新的提交中,而在损坏的提交中添加的任何内容都将在新的提交中删除。将弹出一个默认编辑器,其中包含即将创建的“恢复提交”的默认提交消息。你可以修改是你的愿望。
13、撤消 Git 合并
feature您对分支中的新更改感到满意。您感觉准备好将feature分支合并到您的main分支。因此,您可以从您的main分支合并feature分支并将新更改推送到远程存储库。
片刻之后,您意识到合并根本不是一个漂亮的举动。
所以你想撤消合并。Git 已为您服务。
首先检查main分支:
git checkout main
然后运行git log以获取合并提交的提交哈希。
git log
然后像这样还原:
git revert -m 1 <merge-commit-hash>
合并中的分支是该合并的父级。
通常您无法恢复合并,因为git不知道合并的哪一侧(父级)应该被视为主线。git revert -m 1指定主线的父编号,并允许 revert 反转相对于指定 parent 的更改。
通常,在 a 期间首先记录的父级git merge是您合并时所在的分支。在我们的错误案例中,我们feature在分支上签出时合并了main分支。所以-m 1指定main分支。
14、回滚到旧版本
您可以及时将项目回滚到某个版本。这也可能是对错误提交的响应:您希望返回到最近中断提交之前正常工作的版本。
警告:此处显示的 git 命令会重写历史记录。这不适用于与他人合作完成软件项目。
因此,您希望通过回溯存储库的历史来获得项目的先前版本。
在 git 中:
查找并复制您希望项目回退到的提交哈希:
git log
将您的存储库重置为提交哈希指定的状态:
git reset --hard <commit-hash>
git reset将HEAD指针(以及您的工作树)移动到旧版本(<commit-hash>)。
此版本之后的提交将从项目的历史记录中删除。
该--hard标志将重置暂存区和工作树。
使用--mixed类似的标志:git reset --mixed <commit-hash>, 会将您的 repo 重置为工作树中指定的提交哈希保留文件。在以后的提交中但不在我们重置的提交中的文件将成为untracked文件。
该--mixed标志有一个近亲--soft,不同之处在于它们处理索引(暂存区)的方式。
该--mixed标志将重置暂存区(索引),但不会重置工作树。因此,要在下一次提交中添加未跟踪的文件,您必须git add在git commit.
该--soft标志既不会重置暂存区,也不会重置工作树。因此,要在下一次提交中添加未跟踪的文件,您只需git commit.
15、修改旧的提交信息
您对项目的进展感到高兴。您正在浏览您的项目历史。您注意到一条明显含糊的提交消息。
因此,您希望将此消息更改为描述逻辑语义的更好消息(只是具有更好解释的消息)。
在 Git 中,您可以使用交互式 rebase编辑更深入的历史提交消息:
查找并复制要更改其提交消息的提交的提交哈希:
git log
打开一个 rebase 交互式会话:
git rebase -i <commit-hash>
将弹出一个编辑器。
从上面的示例交互式 rebase 会话中,您可以看到第 1 行有一个错字:pick 21c21b6 udating。让我们修正这个错字并提供更好的描述性信息。
在编辑器中只指定要执行的操作。现在可能很想重写提交消息,但这行不通;rebase -i忽略 SHA(commit hash) 列之后的所有内容。之后的文本实际上只是为了帮助您记住提交哈希的全部内容。
由于您要保留提交的内容但要编辑提交消息,reword请针对要更改其消息的提交指定操作命令;只需pick将第一列中的单词替换为单词reword(或只是r),如下所示:
然后保存并关闭编辑器。
最后 git 会打开一个编辑器让你更改提交信息。将提交消息更改为更好的消息:
你终于可以保存并关闭你的编辑器了。提交将使用新的提交消息进行更新。
16、删除旧的提交
旧的提交可能会困扰您,您希望将其从项目历史中删除。
因此,您希望此提交不再出现在您的项目历史记录中。
您可以删除此提交,例如:
首先,找到并复制注定提交的提交哈希。
git log
然后:
git rebase -i <commit-hash>
指定drop删除提交的动作动词:
保存并关闭编辑器。注定的提交从项目历史中剔除。
17、编辑旧提交以添加新更改
可能会出现您想要向项目添加更改的情况。但是,当您处理由该提交的提交消息更好地描述的特定更改时,此更改与及时提交有关。
例如,您的项目已经通过多次提交演变,并且可能将最近的提交标记为您项目的版本 5。您创建了一个file.html. 您希望此文件成为历史更深的先前提交的一部分,可能在项目的第 2 版中。
在 Git 中,您可以及时将新更改合并到提交中,从而编辑旧提交。
这些是步骤:
查找并复制要标记以进行编辑的提交的提交哈希:
git log
启动一个 rebase 交互式会话:
git rebase -i "<commit-hash>^"
请注意我们如何在<commit-hash>^的末尾附加插入符号()。通过这种方式,我们告诉 Git 在编辑完这个标记的提交后,我们想回到原来的提交年表。因为当你运行时git rebase -i "<commit-hash>^",git log会将标记的<commit-hash>显示为最近的提交。
运行此命令,将弹出一个默认编辑器。将动作动词修改pick为edit在提到我们的<commit-hash>的行中,如图所示:
保存并关闭编辑器。
您的工作树和项目历史现在处于您之前提交此提交时的状态。运行git log,您将看到<commit-hash>现在是您最近的提交。您的工作树中仍然有您创建的文件 ( file.html),这是将其修改为最新提交的好机会。请记住,最近的提交是您要编辑的提交。
所以继续修改如下:
git add file.html
git commit --amend --no-edit
现在将项目历史恢复到正常顺序:
git rebase --continue
这样,您已经编辑了<commit-hash>通过添加指定的提交file.html。
注意:这将重写从那时起的历史记录。在团队环境中开展项目时,这不是一个好主意。
总结
这就是你可以扭转错误的方法。
只是一些注意事项:
- 在团队环境中处理项目时,建议避免使用重写历史的命令。但是,您可以在您自己的专用分支中重写历史记录,该分支仅存在于您的本地存储库中。规则是不要重写其他人在其中工作的分支的历史记录。事情可能会变得复杂。
- 您可能熟悉该git log命令,该命令显示提交列表。git reflog类似,但显示HEAD更改时的时间列表。
- 您的 reflog 对您来说是个人的。Reflog 跟踪自克隆存储库以来对每个分支的任何更改或提交。
- Git 默认在 90 天内不会删除你的提交;您可以在 reflog 中找到它们。因此,您的错误还有另一个机会。