【发布时间】:2012-01-11 13:59:46
【问题描述】:
我正在尝试学习如何将文件和项目恢复或回滚到之前的状态,但不了解git revert、checkout 和reset 之间的区别。为什么有 3 个不同的命令用于看似相同的目的,什么时候应该选择一个而不是另一个?
【问题讨论】:
标签: git git-checkout git-reset git-revert
我正在尝试学习如何将文件和项目恢复或回滚到之前的状态,但不了解git revert、checkout 和reset 之间的区别。为什么有 3 个不同的命令用于看似相同的目的,什么时候应该选择一个而不是另一个?
【问题讨论】:
标签: git git-checkout git-reset git-revert
这三个命令的用途完全不同。它们甚至一点都不相似。
git revert此命令创建一个新的提交,用于撤消先前提交的更改。此命令向项目添加新历史记录(它不会修改现有历史记录)。
git checkout此命令从存储库中签出内容并将其放入您的工作树中。它还可以具有其他效果,具体取决于调用命令的方式。例如,它还可以更改您当前正在处理的分支。此命令不会对历史记录进行任何更改。
git reset这个命令有点复杂。根据调用方式,它实际上做了几件不同的事情。它修改索引(所谓的“暂存区”)。或者它会更改分支头当前指向的提交。此命令可能会更改现有历史记录(通过更改分支引用的提交)。
如果在项目历史的某个地方进行了提交,而您后来认为该提交是错误的并且不应该进行,那么git revert 就是完成这项工作的工具。它将撤消由错误提交引入的更改,将“撤消”记录在历史记录中。
如果您修改了工作树中的文件,但尚未提交更改,则可以使用 git checkout 签出该文件的新存储库副本。
如果您已提交,但尚未与其他任何人共享,并且您决定不想要它,那么您可以使用 git reset 重写历史记录,使其看起来好像您从未提交过提交。
这些只是一些可能的使用场景。还有其他一些命令在某些情况下很有用,以上三个命令也有其他用途。
【讨论】:
git reset 和 git checkout 可以做同样的事情。说它们“甚至一点都不相似”不仅仅是夸大其词:它甚至都不是真的。这两个命令可以做很多不同的事情,其中一些完全重叠。示例:git reset --hard 和 git checkout -- . 将执行完全相同的操作。从逻辑上讲,git reset --hard <path> 和 git checkout <path> 也应该做同样的事情——但是 git 会阻止你这样做。混淆这两个命令非常容易。
git checkout <path> 那样做git reset --hard <path>,因为这两个命令做的事情完全不同。 git reset 告诉 Git 将 HEAD 移动到不同的提交。另一方面,git checkout 根本不要求 Git 对 HEAD 做任何事情。它只留下 HEAD 并仅签出一个文件。是的,您可以以具有相似效果的方式制作它们。但他们实际上做的却完全不同。
假设你有提交:
C
B
A
git revert B,将创建一个撤消B 中更改的提交。
git revert A,将创建一个撤消A 中的更改的提交,但不会触及B 中的更改
请注意,如果B 的更改依赖于A 的更改,则无法恢复A。
git reset --soft A,将更改提交历史和存储库;暂存和工作目录仍将处于C 的状态。
git reset --mixed A,将更改提交历史、存储库和暂存;工作目录仍将处于C 的状态。
git reset --hard A,将更改提交历史、存储库、暂存和工作目录;你会完全回到A的状态。
【讨论】:
git revert 用于撤消先前的提交。在 git 中,您不能更改或删除较早的提交。 (实际上可以,但它可能会导致问题。)因此,revert 不是编辑之前的提交,而是引入了一个新的提交来反转之前的提交。git reset 用于撤消工作目录中尚未提交的更改。git checkout 用于将文件从其他提交复制到您当前的工作树。它不会自动提交文件。【讨论】:
git reset --soft 仅重置 HEAD,git reset --hard 重置 HEAD 和您的工作目录。
git checkout 修改你的工作树,git reset 修改你所在分支的引用,git revert 添加撤销更改的提交。【讨论】:
git reset 不只是修改分支指向的提交,它还用于从索引中取消暂存文件,并且可以使用git reset --mixed修改工作副本(默认)。
重置 - 在提交级别,重置是一种将分支尖端移动到不同提交的方法。这可用于从当前分支中删除提交。
还原 - 还原通过创建新提交来撤消提交。这是撤消更改的安全方法,因为它没有机会重写提交历史记录。 将此与 git reset 进行对比,后者确实会改变现有的提交历史。出于这个原因,应该使用 git revert 来撤消公共分支上的更改,而 git reset 应该保留用于撤消私有分支上的更改。
您可以查看此链接- Reset, Checkout and Revert
【讨论】:
如果你破坏了树但没有提交代码,你可以使用git reset,如果你只想恢复一个文件,你可以使用git checkout。
如果你破坏了树并提交了代码,你可以使用git revert HEAD。
http://book.git-scm.com/4_undoing_in_git_-_reset,_checkout_and_revert.html
【讨论】:
我将尝试添加git restore 来回答问题
假设您有以下提交历史记录:
D
C
B
A
git revert:
进行反向提交。 git revert commit-hash 不会更改您的提交历史记录,但会进行新的提交,以还原作为提交的一部分提交的更改
git revert B,将创建一个撤消B 更改的提交。 Git历史发布它会是
reverse-B
D
C
B
A
如果提交 C 依赖于提交 B git revert B 将导致合并冲突
建议:git revert 旨在恢复公共提交。所有其他撤消更改的方法都有可能更改提交历史,这可能会导致项目其他参与者出现问题。 git revert 是在不干预提交历史的情况下撤消更改的方法
git restore:
git restore 帮助您将文件从 commit/staging-area 移动到 worktree/staging-area
命令是 git restore [--source=commit-hash] [--worktree] [--staged] [--] 文件
建议 - 使用 git restore 将文件从
git checkout commit-hash:
请注意,虽然git checkout 的文件级实现可以帮助您将文件从提交中拉到暂存区或工作树中,但我们不会讨论它,因为现在这是git restore 命令的责任它的设计旨在使git checkout 命令保持一致。
git checkout commit-hash - 头部被移动以指向提交哈希。总是让你处于超脱的状态。git checkout branch - 头部被移动到指定的分支,现在不处于分离状态建议:使用git checkout看看树周围的各种commits并在分支之间切换
git reset commit-hash:
git reset 会将 HEAD 移动到指定的 commit-hash。就像git checkout commit-hash
git reset 会将整个 (HEAD -> branch) 移动到指定的 commit-hash。如果这导致commits 之前没有分支,那么这些提交将从 git 历史记录中删除git reset也有--soft、--mixed、--hard三个选项。将 HEAD 移动到不同的提交后,您的工作树和索引(暂存区域)应该是什么样子?
--hard - 工作树和索引都与您移动到的新提交中的文件匹配--mixed(默认)- 工作树保持在您运行 git reset 之前的状态,并且索引与您移动到的新提交中的文件匹配--soft - 工作树和索引都保持在您运行之前的状态git reset
git reset 在大多数情况下可以使用git checkout、git branch -D 和git restore 的组合来复制,除了没有简单的方法来控制工作树和暂存区的内容,除非你不要使用 git reset
建议:您是否进行了一些不应该进行的提交并且没有将更改推送到公共 repo?最好只是让这些提交从未存在过?使用git reset。如果您已将更改推送到公共仓库,那么如前所述,您想使用git revert
【讨论】: