“git重置”和“git重置”有什么区别?和“git checkout”?

发布于 2024-09-17 19:30:14 字数 1154 浏览 10 评论 0 原文

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

ADDED

VonC 和 Charles 很好地解释了 git reset 和 git checkout 之间的区别。我目前的理解是 git reset 将所有更改恢复到特定提交,而 git checkout 或多或少为分支做准备。我发现以下两个图表对于理解这一点非常有用:

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

添加了 3 个

来自 http ://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html,签出并重置可以模拟rebase。

输入图像描述此处

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

在此处输入图像描述

I've always thought of git reset and git checkout as 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 co to revert the commit.

ADDED

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

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

ADDED 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.

enter image description here

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

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

云巢 2024-09-24 19:30:14
  • git reset 专门用于更新索引< /strong>,移动头部。
  • git checkout 是关于更新工作树< /strong> (到索引或指定的树)。仅当您检出分支时,它才会更新 HEAD(如果没有,您最终会得到一个分离的 HEAD)。
    (实际上,对于 Git 2.23 Q3 2019,这将是 git Restore,不一定是 git checkout)

相比之下,由于 svn 没有索引,只有工作树, svn checkout 会将给定的修订版本复制到单独的目录中。
与 git checkout 更接近的等效项是:

  • svn update(如果您在同一个分支,表示相同的 SVN URL)
  • svn switch (如果您签出同一分支,但来自另一个 SVN 存储库 URL )

所有这三个工作树修改(svn checkoutupdateswitch)在 git 中只有一个命令:git checkout.
但由于 git 也有索引的概念(存储库和工作树之间的“暂存区域”),因此您还可以使用 git Reset。


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

例如,如果我们有两个分支“master”和“develop”指向不同的提交,并且我们当前处于“develop<” /code>'(因此 HEAD 指向它),然后我们运行 git reset master,'develop' 本身现在将指向与 'master< 相同的提交/code>' 确实如此。

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

因此,在这两种情况下,我们都会将 HEAD 移动到指向提交 A 的位置,但我们的操作方式却截然不同。 reset 将移动 HEAD 指向的分支,checkout 将 HEAD 本身移动到指向另一个分支。

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

在这些点上,不过:

LarsH< /a> 在评论

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

git checkout a839e8f 更新 HEAD 以指向提交 a839e8f。

De Novo 同意在评论中

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

  • 附加的头部状态将以 (HEAD ->,
  • 开头

  • 分离仍会显示 (HEAD,但不会有指向分支引用的箭头。
  • git reset is specifically about updating the index, moving the HEAD.
  • git checkout is 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)

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

  • 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)

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.


Thinkeye mentions in the comments the article "Reset Demystified ".

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, HEAD itself will. HEAD will now point to 'master'.

So, in both cases we're moving HEAD to point to commit A, but how we do so is very different. reset will move the branch HEAD points to, checkout moves HEAD itself to point to another branch.

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

On those points, though:

LarsH adds in the comments:

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 checkout will 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.

De Novo concurs in the comments:

@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.
惟欲睡 2024-09-24 19:30:14

在最简单的形式中,reset 重置索引而不触及工作树,而 checkout 更改工作树而不触及索引。

重置索引以匹配 HEAD,单独保留工作树:

git reset

从概念上讲,这会将索引签入工作树。要让它真正执行任何操作,您必须使用 -f 来强制它覆盖任何本地更改。这是一项安全功能,可确保“无参数”形式不会具有破坏性:

git checkout

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

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

另外,如果您为 reset 提供 --hard,您可以要求 reset 覆盖工作树并重置索引。

如果您当前签出了一个分支,那么当您提供替代分支或提交时,重置和签出之间存在重大差异。 reset 将更改当前分支以指向选定的提交,而 checkout 将保留当前分支,但会签出提供的分支或提交。

其他形式的重置和提交涉及提供路径。

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

如果您提供 checkout 的路径,例如 reset ,它将更新所提供路径的索引版本以匹配所提供的提交(或 HEAD),但是它总是将所提供路径的索引版本签入工作树。

In their simplest form, reset resets the index without touching the working tree, while checkout changes the working tree without touching the index.

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

git reset

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

git checkout

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

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

Also, if you supply --hard to reset you can ask reset to overwrite the working tree as well as resetting the index.

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

Other forms of reset and commit involve supplying paths.

If you supply paths to reset you cannot supply --hard and reset will only change the index version of the supplied paths to the version in the supplied commit (or HEAD if you don't specify a commit).

If you supply paths to checkout, like reset it 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.

软糖 2024-09-24 19:30:14

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

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.

爱的故事 2024-09-24 19:30:14

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

正如 Pro Git 书籍 Reset Demystified 中所解释的那样,

reset 要做的第一件事是移动 HEAD 指向的内容。这不是
更改 HEAD 本身相同(这就是 checkout 的作用); 重置
移动 HEAD 指向的分支。这意味着如果设置了 HEAD
master 分支(即您当前位于 master 分支),
运行 git reset 9e5e6a4 将使 master 指向
9e5e6a4。 [已添加强调]

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

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

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

As the Pro Git book explains under Reset Demystified,

The first thing reset will do is move what HEAD points to. This isn’t
the same as changing HEAD itself (which is what checkout does); reset
moves the branch that HEAD is pointing to. This means if HEAD is set
to the master branch (i.e. you’re currently on the master branch),
running git reset 9e5e6a4 will start by making master point to
9e5e6a4. [emphasis added]

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

Of course there are a lot more details about what effects checkout and reset can 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.

蝶舞 2024-09-24 19:30:14

简短的助记符:

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

brief mnemonics:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
星光不落少年眉 2024-09-24 19:30:14

这两个命令(重置和检出)完全不同。

checkout X 不是 reset --hard X

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

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

checkout X IS NOT reset --hard X

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

掩饰不了的爱 2024-09-24 19:30:14

git重置 ->从暂存区域删除所有文件,即撤消git add

git reset ->撤消提交并暂存指定提交后的所有文件。

如果使用重置命令添加--hard,则它会删除暂存区域中的文件以及删除 从您的目录中获取。

git checkout ->您将恢复到指定的提交状态,但您不在任何分支中。

如果你输入gitbranch-a,你会看到你在

(HEAD 在 处分离)

根据控制台:

您处于“分离 HEAD”状态。你可以环顾四周,做出
实验性更改并提交它们,并且您可以放弃任何提交
您在这种状态下进行切换不会影响任何分支
返回分支。

您将获得两个选项:

  1. git switch -c :将从该提交创建一个新分支,并将成为您当前的分支。
  2. git switch -c ->它基本上是撤消结帐命令,将您带回旧分支。

git reset -> removes all the files from the staged area i.e it undos git add <files>

git reset <commit_ID> -> undos commits and staging of all files after the specified commit.

if added --hard with the reset command, then it removes the files from the staged area as well as deletes it from your directory.

git checkout <commit_ID> -> you are reverted back to that specified commit state but you are not in any branch.

if you type git branch -a, you will see that you are in

(HEAD detached at <commit_ID>)

.

as per the console:

You are in 'detached HEAD' state. You can look around, make
experimental changes and commit them, and you can discard any commits
you make in this state without impacting any branches by switching
back to a branch.

and you will be given two options:

  1. git switch -c <new-branch-name>: a new branch will be created from that commit and it will become your current branch.
  2. git switch -c -> it is basically undoing the checkout command which brings you back to your old branch.
黑色毁心梦 2024-09-24 19:30:14

这是对歧义的澄清:

  • git checkout 会将 HEAD 移动到另一个提交(也可能使用分支名称进行更改),但是无论你在哪个分支,指针该分支的尖端(例如,“主”)将保持不变(因此您可能最终处于分离头状态)。此外,工作目录将更改为指定提交的状态,但是,对其中(工作目录中)文件的本地修改将保持不变。 (~感谢Géry Ogam。)

示例:

git checkout 3ad2bcf <--- checkout to another commit
git checkout another-branch <--- checkout to another commit using a branchname
  • git reset 也移动 HEAD,但是,有两个区别< /强>:

    1. 它也会移动指向当前分支尖端的提交的指针。例如,假设指向当前分支的指针名为“main”,然后执行 git-reset,现在,主指针将指向另一个提交,并且 HEAD 也将指向该提交(基本上, HEAD 通过指向主指针间接指向该提交,它仍然是一个附加头(!),但在这里没有任何区别)。 p>

    2. Git-reset 不一定使暂存区域和工作目录保持在执行重置之前的相同状态。如您所知,重置分为三种类型:软重置、混合重置(默认)和硬重置:

      • 通过软重置,暂存区域和工作目录都保持重置前的状态(在这方面与 checkout 类似,但不要忘记区别 #1)。
      • 使用混合重置(默认重置类型),除了差异 #1 之外,暂存区域的建议的下一次提交(基本上是您 git 添加的内容)也将被设置到新指向的 HEAD 提交。但在工作目录中,所有文件仍将包含您对它们的最新编辑(这就是为什么这种类型的重置是默认重置,这样您就不会丢失您的工作)。
      • 通过硬重置,除了差异 1 之外,所有三棵树 HEAD、暂存区域和工作目录都将更改为新指向的 HEAD 提交。

示例:

git reset --soft 3ad2bcf
git reset da3b47

Here's a clarification of the ambiguity:

  • git checkout will move the HEAD to another commit(could be a change using a branchname too), but on whatever branch you are, the pointer to the tip of that branch(e.g., "main") will remain unchanged (so you might end up in a detached head state). Also, the working directory will change to the state of the specified commit, however, local modifications to the files in there (in the working directory) will remain unchanged. (~Thanks Géry Ogam.)

Examples:

git checkout 3ad2bcf <--- checkout to another commit
git checkout another-branch <--- checkout to another commit using a branchname
  • git reset also moves the HEAD, however again, with two differences:

    1. It moves the pointer that points to the commit at the tip of the current branch too. For instance, let's say the pointer to the current branch is named "main", then you perform a git-reset, now, the main pointer will point to another commit, and the HEAD will point to that commit as well(well basically, HEAD points to that commit indirectly through pointing to the main pointer, it is still an attached head(!), but it doesn't make any difference here).

    2. Git-reset doesn't necessarily leave the staging area and the working directory on the same state they were in before the reset was performed. As you know, there are three types of reset: soft, mixed(default) and hard:

      • With the soft reset, the staging area and the working directory both remain in the state they've been on before the reset(similar to checkout in this regard, but don't forget the difference #1).
      • With the mixed reset which is the default type of reset, in addition to difference #1, the staging area's proposed next commit(what you've git-added basically), will also be set to the newly pointed-to-by-HEAD commit. BUT in the working directory, all the files will still have your latest edits to them (that's why this type of reset is the default one, so that you don't lose your work).
      • With the hard reset, in addition to difference #1, all the three trees HEAD, staging-area and ALSO the working-directory will change to the newly pointed-to-by-HEAD commit.

Examples:

git reset --soft 3ad2bcf
git reset da3b47
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文