撤消 Git 中的更改 - git checkout、stash、reset、clean、revert、rebase -i、amend 的备忘单
目录
原帖发布于michaelzanggl.com。订阅我的新闻通讯,不错过任何新内容。
Git 是那种需要循序渐进学习的东西。你从git add .
暂存文件开始,git commit -m “message”
在本地提交,最终git push
推送到远程仓库。
但随着时间的推移,你会犯错。如果你总是在 Google 上搜索,然后随意粘贴命令,你可能会很容易被大量的命令搞晕,比如、 、 、 、git reset
等等git revert
。git clean
让git checkout .
我们一一了解一下!git rebase -i
git commit --amend
目录
- 理解关键术语
- 不要撤消:保存更改以供日后使用
- 不要撤消:在最新提交中添加内容或更改消息
- 取消暂存文件(预提交)
- 恢复更改(预提交)
- 删除新的/未跟踪的文件和目录
- 在新的提交中恢复提交
- 删除没有新提交的最新提交
- 变更历史记录
- 删除本地分支
- 删除远程分支
- 结论
理解关键术语
您总是可以在这里找到更多帮助,但了解一些关键术语很重要。
-
索引:使用索引暂存文件时,
git add
会将文件添加到索引文件中。因此,暂存与索引相同。 -
未跟踪:如果您创建一个新文件,它将不会被跟踪,直到您将其暂存为止。
-
HEAD:HEAD 指向当前分支的最新提交。这就是为什么有时
detached HEAD
在检出旧提交时会看到一个奇怪的选择。 -
点号 in
git add .
表示当前目录。因此,当前目录及其所有子目录中的所有文件都将被暂存。我们将学习更多使用点号的命令。
不要撤消:保存更改以供日后使用
git stash -u
这将保存每个未跟踪的文件(-u 标志)、暂存和未暂存的修改。
要再次检索最新的存储,请运行
git stash apply
为了保持存储列表整洁,您也可以git stash pop
改为执行。它会执行与应用相同的操作,但还会从存储列表中删除已应用的存储。
用于git stash list
检索所有储藏物的列表。
用例:您正在处理某件事,但突然需要更改分支(例如,为突然出现的紧急错误创建修补程序)
奖励:要知道哪个储藏属于什么,您可以通过运行以下命令为您的储藏添加注释:git stash push -u -m "your message"
不要撤消:在最新提交中添加内容或更改消息
git commit --amend -m "added file and changed message to this"
amend
允许您向最新提交添加更多文件。
用例:您忘记暂存本应作为提交一部分的某个文件。
奖励:即使没有添加文件,您仍然可以使用“修改”选项来简单地更改消息。
如果其他人正在你的分支上工作:请注意不要在最新提交已经发布(推送)的情况下进行修改。否则需要git push --force
取消暂存文件(预提交)
git reset .
也常常被视为git reset
例子:
echo "code code code" >> index.js
git add .
git reset .
它只会取消暂存index.js
并将更改放回你的工作树中。你可以应用该--hard
标志来彻底删除你的更改。
用例:出于习惯,您使用暂存所有修改git add .
,但想要取消暂存某些文件以单独提交它们。
额外提示:要取消暂存特定文件,你可以使用与git add
git add User.js UserController.js UserService.js
git reset UserService.js User.js
这种情况一直在UserController.js
上演。
恢复更改(预提交)
git checkout .
git checkout
用于更改分支,但如果您检出文件路径,它就会有不同的用途。
如果您在本地更改了任何文件,这将使用索引或提交中的内容还原您的更改。稍后会详细介绍。
例子:
echo -n "1" >> newfile
git add .
git commit -m "added newfile"
echo -n "2" >> newfile
因此,我们创建了一个新文件,暂存并提交了它,然后将文本“2”附加到该文件。
如果你现在运行git checkout newfile
它,它将删除所有本地更改,在本例中为“2”。你的工作树将再次变得干净。
让我们看看当你开始在中间进行暂存时会发生什么。这将为你提供新的视角git add
,使命令比以往任何时候都更加强大。
echo -n "1" >> newfile
git add .
git commit -m "added newfile"
echo -n "2" >> newfile
git add .
echo -n "3" >> newfile
这是不同状态下的文件内容
- 头:“1”
- 索引:“12”
- 工作树:“123”
如果您现在运行,git checkout newfile
它只会删除3
您本地更改的内容。换句话说,如果它在索引中找到该文件,它会根据索引中的内容(而不是 HEAD 中的内容)还原更改。它仍然会newfile
暂存内容“12”。
要删除“2”,您必须先按照我们所了解的方式取消暂存文件,然后再次检查它。
git reset
git checkout .
因为它只用索引/HEAD 中的文件替换文件,所以
git checkout
不会对未跟踪的文件执行任何操作。
用例:您对文件 A 进行了修改,当修改文件 B 时,您意识到文件 A 中的更改实际上是不必要的,最好再次检查一下。
奖励:如果您想要检出的文件不幸与分支同名,则必须像这样检出git checkout -- master
以避免检出主分支。
删除新的/未跟踪的文件和目录
git clean -f
类似于,git checkout .
不同之处在于它仅适用于未跟踪的文件。您可以运行git clean --dry-run
或git clean -n
查看哪些文件将被永久删除。添加-d
标志以包含目录。
touch newfile
git clean -d -n
输出将是Would remove newfile
奖励:用于git clean -i
启动交互式清理,为您提供更多关于如何处理每个文件的选项。
在新的提交中恢复提交
git 恢复
commit-id
恢复提交 ID 的更改并为其创建一个新的提交。
用例:已推送的提交导致错误并且必须恢复。
额外提示:使用-e
或--edit
标志可以修改提交信息。例如,你可以添加此提交必须被撤销的原因。
删除没有新提交的最新提交
git 重置 HEAD^
假设你意外提交了某个提交,现在想要撤消该提交。它git reset HEAD^
会将最新的提交还原为从未发生过,并将修改放回到你的本地工作树中。它不会创建新的提交,最新的提交也会从历史记录中消失。
我们git reset
之前已经了解过如何取消暂存文件。但是,当你传递提交时,你实际上可以将 HEAD 重置为你想要的任何提交。假设你有提交 A、B 和 C。如果git reset A
A 成为最新的提交,那么git log
你将找不到 B 和 C。
我们之前说过,这git reset HEAD^
会将更改保留在工作树中。换句话说,git reset HEAD^
这会重置 HEAD 和索引。
使用--soft
标志仅重置 HEAD,这意味着更改将保留staged
。
使用--hard
标志重置 HEAD、索引和工作树,这意味着更改将被完全删除。
您也git reset HEAD^
可以写git reset HEAD^1
,git reset HEAD~1
或git reset HEAD~
。
如果其他人正在你的分支上工作:请注意,如果你重置的提交已经发布,不要将 HEAD 重置为之前的提交。这需要git push --force
用例:您在本地提交了修改,但意识到您提交到了错误的分支。
奖励:除了最新的提交之外,总共有四种方法可以重置。
这四行代码重置了最后两次提交
git reset HEAD^2
git reset HEAD^^
git reset HEAD~2
git reset HEAD~~
额外福利2:git reset
它实际上不会删除最新的提交,只是将 HEAD 回滚到你想要的提交。B 和 C 仍然会保存 30 天。
变更历史记录
让我们快速了解一下交互式变基。我们之前学习过git reset HEAD~1 --hard
它是一种移除最新提交的方法。交互式变基也能实现同样的效果,只是它的功能更强大。rebase
这次它实际上改变了提交对象,而不仅仅是将 HEAD 指向特定的提交。
git rebase -i HEAD~4
我们看到的内容HEAD~4
与git reset
之前相同。4 指的是您要重新设定的提交次数。
这将打开一个编辑器(vim?),其中包含以下内容
pick 123a44b0 your latest commit
pick C23a44b0 commit 3
pick B23a44b0 commit 2
pick A23a44b0 commit 1
# Rebase ...
#
# 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
让我们替换
pick 123a44b0 your latest commit
pick C23a44b0 commit 3
pick B23a44b0 commit 2
pick A23a44b0 commit 1
经过
pick 123a44b0 your latest commit
fixup C23a44b0 commit 3
f B23a44b0 commit 2
drop A23a44b0 commit 1
如您所见,在这种情况下,您可以写出选项fixup
,也可以使用缩写f
。
C23a44b0
这会将和压缩(合并)B23a44b0
为123a44b0
,从而生成一个提交。至于A23a44b0
,此提交将被完全删除。因此,一旦 rebase 完成,您将只剩下一个提交123a44b0
。
如果其他人正在你的分支上工作:请注意,当你想 rebase 的提交已经发布时,不要 rebase。这需要git push --force
用例:您正在自己的分支上独自工作,并希望拥有 PR/MR 的干净提交列表。
奖励:您甚至可以通过更改提交在列表中出现的顺序来移动提交。
删除本地分支
git checkout master
git branch -D branch-to-delete
用例:有时,删除本地分支并再次检查会更快,而不是恢复一堆提交。
删除远程分支
git push origin branch-to-delete --delete
用例:推送后,您意识到所选的名称没有意义,并且想要更改它(奖励:使用 执行此操作git branch -m "new-name"
)
结论
Git 确实很难掌握,我相信肯定还有其他方法可以完成其中一些任务。如果您知道任何方法,请留言,我会将它们添加到列表中。
如果这篇文章对您有帮助,我这里还有更多关于简化编写软件的提示。
文章来源:https://dev.to/michi/undo-changes-in-git-cheat-sheet-for-git-checkout-stash-reset-clean-revert-rebase-i-amend-2h1h