“git reset”和“git checkout”有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3639342/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 09:02:33  来源:igfitidea点击:

What's the difference between "git reset" and "git checkout"?

gitgit-checkoutgit-reset

提问by prosseek

I've always thought of git resetand git checkoutas the same, in the sense that both bring the project back to a specific commit. However, I feel they can't be exactly the same, as that would be redundant. What is the actual difference between the two? I'm a bit confused, as the svn only has svn coto revert the commit.

我一直认为git resetgit checkout是一样的,从某种意义上说,两者都将项目带回到特定的提交。但是,我觉得它们不能完全相同,因为那是多余的。两者之间的实际区别是什么?我有点困惑,因为 svn 只svn co需要恢复提交。

ADDED

添加

VonC and Charles explained the differences between git resetand git checkoutreally well. My current understanding is that git resetreverts all of the changes back to a specific commit, whereas git checkoutmore or less prepares for a branch. I found the following two diagrams quite useful in coming to this understanding:

VonC和查尔斯解释之间的差异git resetgit checkout真的很好。我目前的理解是git reset将所有更改还原回特定的提交,而git checkout或多或少地为分支做准备。我发现以下两个图表对于理解这种理解非常有用:

http://a.imageshack.us/img651/1559/86421927.pnghttp://a.imageshack.us/img801/1986/resetr.png

http://a.imageshack.us/img651/1559/86421927.pnghttp://a.imageshack.us/img801/1986/resetr.png

ADDED 3

添加 3

From http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html, checkout and reset can emulate the rebase.

http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html,结帐和重置可以模拟变基。

enter image description here

在此处输入图片说明

git checkout bar 
git reset --hard newbar 
git branch -d newbar 

enter image description here

在此处输入图片说明

采纳答案by VonC

  • git resetis specifically about updating the index, moving the HEAD.
  • git checkoutis about updating the working tree(to the index or the specified tree). It will update the HEAD only if you checkout a branch (if not, you end up with a detached HEAD).
    (actually, with Git 2.23 Q3 2019, this will be git restore, not necessarily git checkout)
  • git reset特别是关于更新索引,移动 HEAD。
  • git checkout是关于更新工作树(到索引或指定的树)。只有当您签出分支时,它才会更新 HEAD(如果没有,您最终会得到一个分离的 HEAD)。
    (实际上,对于 Git 2.23 Q3 2019,这将是git restore,不一定是git checkout

By comparison, since svn has no index, only a working tree, svn checkoutwill copy a given revision on a separate directory.
The closer equivalent for git checkoutwould:

相比之下,由于 svn 没有索引,只有一个工作树,svn checkout将在单独的目录中复制给定的修订。
更接近的等价物是git checkout

  • svn update(if you are in the same branch, meaning the same SVN URL)
  • svn switch(if you checkout for instance the same branch, but from another SVN repo URL)
  • svn update(如果你在同一个分支,意思是同一个SVN URL)
  • svn switch(例如,如果您签出相同的分支,但来自另一个 SVN 存储库 URL)

All those three working tree modifications (svn checkout, update, switch) have only one command in git: git checkout.
But since git has also the notion of index (that "staging area" between the repo and the working tree), you also have git reset.

所有这三个工作树修改(svn checkout, update, switch)在 git 中只有一个命令:git checkout.
但是由于 git 也有索引的概念(repo 和工作树之间的“暂存区”),你也有git reset.



Thinkeyementions in the commentsthe article "Reset Demystified ".

Thinkeye在评论中提到了文章“重置揭秘”。

For instance, if we have two branches, 'master' and 'develop' pointing at different commits, and we're currently on 'develop' (so HEAD points to it) and we run git reset master, 'develop' itself will now point to the same commit that 'master' does.

On the other hand, if we instead run git checkout master, 'develop' will not move, HEADitself will. HEADwill now point to 'master'.

So, in both cases we're moving HEADto point to commit A, but how we do so is very different. resetwill move the branch HEADpoints to, checkout moves HEADitself to point to another branch.

例如,如果我们有两个分支,' master' 和 ' develop' 指向不同的提交,并且我们当前在 ' develop'(所以 HEAD 指向它)并且我们运行git reset master,' develop' 本身现在将指向相同的提交,' master' 做。

另一方面,如果我们改为运行git checkout master, ' develop' 不会移动,HEAD它本身会移动。HEAD现在将指向“ master”。

所以,在这两种情况下,我们都HEAD指向 commit A,但我们这样做的方式却大不相同。reset将分支HEAD点移动到,结帐将HEAD自身移动到另一个分支。

http://git-scm.com/images/reset/reset-checkout.png

http://git-scm.com/images/reset/reset-checkout.png

On those points, though:

不过,在这些方面:

LarsHadds in the comments:

LarsH在评论中补充道:

The first paragraph of this answer, though, is misleading: "git checkout... will update the HEAD only if you checkout a branch (if not, you end up with a detached HEAD)".
Not true: git checkoutwill update the HEAD even if you checkout a commit that's not a branch (and yes, you end up with a detached HEAD, but it still got updated).

git checkout a839e8f updates HEAD to point to commit a839e8f.

但是,此答案的第一段具有误导性:“ git checkout...仅当您签出分支时才会更新 HEAD(如果没有,您最终会得到一个分离的 HEAD)”。
不正确:git checkout即使您签出一个不是分支的提交,也会更新 HEAD(是的,您最终得到了一个分离的 HEAD,但它仍然得到了更新)。

git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novoconcurs in the comments:

De Novo在评论中表示同意:

@LarsH is correct.
The second bullet has a misconception about what HEAD is in will update the HEAD only if you checkout a branch.
HEAD goes wherever you are, like a shadow.
Checking out some non-branch ref (e.g., a tag), or a commit directly, will move HEAD. Detached head doesn't mean you've detached from the HEAD, it means the head is detached from a branch ref, which you can see from, e.g., git log --pretty=format:"%d" -1.

  • Attached head states will start with (HEAD ->,
  • detached will still show (HEAD, but will not have an arrow to a branch ref.

@LarsH 是正确的。
第二个项目符号对 HEAD 的内容存在误解,只有在您检出分支时才会更新 HEAD。
HEAD 无处不在,就像影子一样。
检出一些非分支引用(例如,标签)或直接提交,将移动 HEAD。分离的头部并不意味着你已经从 HEAD 分离,这意味着头部与分支引用分离,你可以从例如git log --pretty=format:"%d" -1.

  • 附加的元首状态将以(HEAD ->
  • detached 仍会显示(HEAD,但不会有指向分支引用的箭头。

回答by CB Bailey

In their simplest form, resetresets the index without touching the working tree, while checkoutchanges the working tree without touching the index.

最简单的形式是reset在不接触工作树的情况下重置索引,而checkout在不接触索引的情况下更改工作树。

Resets the index to match HEAD, working tree left alone:

将索引重置为 match HEAD,单独留下工作树:

git reset

Conceptually, this checks out the index into the working tree. To get it to actually do anything you would have to use -fto force it to overwrite any local changes. This is a safety feature to make sure that the "no argument" form isn't destructive:

从概念上讲,这会将索引检出到工作树中。为了让它真正做任何事情,你必须使用-f它来强制它覆盖任何本地更改。这是一项安全功能,可确保“无参数”表单没有破坏性:

git checkout

Once you start adding parameters it is true that there is some overlap.

一旦开始添加参数,确实存在一些重叠。

checkoutis usually used with a branch, tag or commit. In this case it will reset HEADand the index to the given commit as well as performing the checkout of the index into the working tree.

checkout通常与分支、标签或提交一起使用。在这种情况下,它会将HEAD索引重置为给定的提交,并将索引检出到工作树中。

Also, if you supply --hardto resetyou can ask resetto overwrite the working tree as well as resetting the index.

此外,如果您提供--hardreset您可以要求reset覆盖工作树以及重置索引。

If you current have a branch checked out out there is a crucial different between resetand checkoutwhen you supply an alternative branch or commit. resetwill change the current branch to point at the selected commit whereas checkoutwill leave the current branch alone but will checkout the supplied branch or commit instead.

如果您当前有一个分支被检出,那么在您提供替代分支或提交之间resetcheckout何时提供一个关键的不同。reset将更改当前分支以指向选定的提交,而checkout将保留当前分支,但会检出提供的分支或提交。

Other forms of resetand commitinvolve supplying paths.

其他形式的resetcommit涉及供应路径。

If you supply paths to resetyou cannot supply --hardand resetwill only change the index version of the supplied paths to the version in the supplied commit (or HEADif you don't specify a commit).

如果您提供路径,reset则无法提供,--hard并且reset只会将提供的路径的索引版本更改为提供的提交中的版本(或者HEAD如果您未指定提交)。

If you supply paths to checkout, like resetit will update the index version of the supplied paths to match the supplied commit (or HEAD) but it will always checkout the index version of the supplied paths into the working tree.

如果您提供路径checkout,就像reset它会更新所提供路径的索引版本以匹配所提供的提交(或HEAD),但它会始终将所提供路径的索引版本检出到工作树中。

回答by John Doe

One simple use case when reverting change:
1. Use reset if you want to undo staging of a modified file.
2. Use checkout if you want to discard changes to unstaged file/s.

还原更改时的一个简单用例:
1. 如果要撤消修改文件的暂存,请使用重置。
2. 如果要放弃对未暂存文件的更改,请使用 checkout。

回答by LarsH

The key difference in a nutshell is that resetmoves the current branch reference, while checkoutdoes not (it moves HEAD).

简而言之,关键区别在于reset移动当前分支引用,而checkout不会(它移动 HEAD)。

As the Pro Git book explains under Reset Demystified,

正如 Pro Git 书在Reset Demystified下解释的那样,

The first thing resetwill do is move what HEAD points to. This isn't the same as changing HEAD itself(which is what checkoutdoes); resetmoves the branchthat HEAD is pointing to. This means if HEAD is set to the masterbranch (i.e. you're currently on the masterbranch), running git reset 9e5e6a4will start by making masterpoint to 9e5e6a4. [emphasis added]

首先reset要做的是移动 HEAD 指向的内容。这与更改 HEAD 本身不同(这是这样checkout做的);reset移动HEAD 指向的分支。这意味着如果 HEAD 设置为master分支(即您当前在master分支上),运行git reset 9e5e6a4将通过master指向 9e5e6a4. [强调]

See also VonC's answer for a very helpful text and diagram excerptfrom the same article, which I won't duplicate here.

另请参阅 VonC 的回答以获取来自同一篇文章的非常有用的文本和图表摘录,我不会在此处重复。

Of course there are a lot more details about what effects checkoutand resetcan have on the index and the working tree, depending on what parameters are used. There can be lots of similarities and differences between the two commands. But as I see it, the most crucial difference is whether they move the tip of the current branch.

当然,根据使用的参数,还有更多关于索引和工作树的影响checkoutreset可能产生的详细信息。这两个命令之间可能有很多相似之处和不同之处。但在我看来,最关键的区别是它们是否移动了当前分支的尖端。

回答by wiki1000

The two commands (reset and checkout) are completely different.

这两个命令(reset 和 checkout)是完全不同的。

checkout XIS NOT reset --hard X

checkout X不是 reset --hard X

If X is a branch name, checkout Xwill change the current branch while reset --hard Xwill not.

如果 X 是分支名称, checkout X则将更改当前分支而reset --hard X不会。

回答by Филя Усков

brief mnemonics:

简短的助记符:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD