Git恢复,签出和重置之间的区别是什么?

我正在学习如何恢复或回滚文件和项目到以前的状态,不理解git revertcheckoutreset之间的区别。为什么会有3个看起来相同的命令,什么时候人们应该选择其中一个而不是另一个?

169366 次浏览

如果你破坏了树但没有提交代码,你可以使用git reset,如果你只想恢复一个文件,你可以使用git checkout

如果你打破树并提交代码,你可以使用git revert HEAD

http://book.git-scm.com/4_undoing_in_git_-_reset,_checkout_and_revert.html

  • git checkout修改你的工作树,
  • git reset修改你所指向的分支的引用,
  • git revert添加一个提交撤销更改。
  • git revert用于撤销之前的提交。在git中,你不能修改或删除之前的提交。(实际上你可以,但这会带来问题。)因此,与编辑之前的提交不同,revert引入了一个新的提交,该提交反转了之前的提交。
  • git reset用于撤销尚未提交的工作目录中的更改。
  • git checkout用于将文件从其他提交复制到当前工作树。它不会自动提交文件。

这三个命令有完全不同的目的。它们一点都不相似。

git revert

此命令创建一个新的提交,该提交将撤消上一次提交的更改。这个命令向项目添加新的历史记录(它不会修改现有的历史记录)。

git checkout

这个命令从存储库中签出内容,并将其放入工作树中。它还可以产生其他效果,具体取决于调用命令的方式。例如,它还可以更改当前正在处理的分支。该命令不会对历史进行任何更改。

git reset

这个命令稍微复杂一些。它实际上做了一些不同的事情,这取决于它是如何被调用的。它修改索引(所谓的“暂存区域”)。或者它改变了当前所指向的分支头。这个命令可能会改变现有的历史记录(通过改变分支引用的提交)。

使用这些命令

如果在项目历史的某个地方进行了提交,然后你决定提交是错误的,不应该执行,那么git revert是该工作的工具。它将撤销错误提交所带来的更改,并在历史记录中记录“撤销”。

如果你已经在工作树中修改了一个文件,但还没有提交修改,那么你可以使用git checkout来签出该文件的新存储库副本。

如果你已经做了一个提交,但还没有与任何人共享它,并且你决定不想要它,那么你可以使用git reset重写历史记录,使它看起来好像你从未做过那次提交。

这些只是一些可能的使用场景。还有其他命令在某些情况下也很有用,上面三个命令还有其他用途。

<强>重置- 在提交级别,重置是一种将分支的尖端移动到不同提交的方法。这可以用来从当前分支中删除提交

< >强还原- 还原通过创建一个新的提交来撤销一个提交。这是一种安全的撤销更改的方法,因为它没有机会重写提交历史。 相比之下,git重置会改变现有的提交历史。因此,应该使用git revert来撤销公共分支上的更改,而应该保留git reset来撤销私有分支上的更改 你可以在这个链接上看看 重置,签出和恢复 < / p >

假设你有commit:

C
B
A

git revert B将创建一个撤销B中的更改的提交。

git revert A将创建一个撤销A中的更改的提交,但不会触及B中的更改

注意,如果B中的变化依赖于A中的变化,则不可能恢复A

git reset --soft A,将改变提交历史和存储库;暂存和工作目录将仍然处于C状态。

git reset --mixed A,将改变提交历史、存储库和staging;工作目录仍然处于C的状态。

git reset --hard A,将改变提交历史,存储库,暂存和工作目录;你会完全回到A的状态。

我将尝试用git restore来回答这个问题

假设你有以下提交历史记录:

D
C
B
A

git revert:

生成reverse-commitgit revert commit-hash不会改变你的提交历史,而是做出一个新的提交,该提交将还原作为提交的一部分所提交的更改

git revert B将创建一个撤销B中的更改的提交。Git历史帖子将是

reverse-B
D
C
B
A

如果提交C依赖于提交Bgit revert B将导致合并冲突

建议:git revert是用来还原公共提交的。所有其他撤销更改的方法都有可能更改提交历史记录,这可能会与项目的其他参与者产生问题。git revert是在不干扰提交历史的情况下撤销更改的方法

git restore:

git restore帮助你将文件从提交/暂存区域移动到工作树/暂存区域

命令为git restore[——source=commit-hash][——worktree][——staging][——]文件

  • ——worktree表示还原到工作树
  • - staging表示将恢复到- staging。
  • 同时指定——staging和——工作树,以便从——source恢复到工作树和staging区域
  • 当指定——source时,始终从源进行恢复
  • 当没有指定——source并且给出——staging时,将从HEAD恢复
  • 当既没有指定——source也没有指定——staging时,将从staging区域恢复到工作树

建议-使用git restore

  • 将blob提交到staging区域和/或工作树。
  • 舞台区域到工作树

git checkout commit-hash:

请注意,虽然有一个文件级的git checkout实现,它可以帮助你将文件从提交区拉到暂存区或工作树中,但我们不会讨论这个,因为现在这是git restore命令的责任,它被精确地设计为整理并使git checkout命令保持一致。

  • git checkout commit-hash -头被移动到指向提交哈希。总是让你处于一种超然的头脑状态。
  • git checkout branch - Head被移动到指向指定的分支,现在它不是处于分离状态

建议:使用git checkout查看树周围的各种提交,并在分支之间切换

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 checkoutgit branch -Dgit restore的组合来复制,除了没有简单的方法来控制工作树和停滞区的内容,除非你不使用git重置

建议:您是否做了一些不应该做的提交,并且没有将更改推到公共回购?如果这些提交从未存在过是不是最好的呢?使用git reset。如果你已经将更改推到public repo,那么正如前面讨论的,你想使用git revert