“git reset --hard hash”和“git checkout hash”之间有区别吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2541545/
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-19 04:12:08  来源:igfitidea点击:

Is there a difference between "git reset --hard hash" and "git checkout hash"?

gitgit-checkoutgit-reset

提问by e-satis

While resetand checkouthave different usages most of the time, I can't see what difference there is between these two.

虽然resetcheckout具有不同用途的大部分时间,我看不出有什么区别在这两个之间。

There probably is one or nobody would have bothered adding a --hardoption to do something the basic checkoutcan do.

可能有一个或没有人会费心添加一个--hard选项来做一些基本checkout可以做的事情。

Maybe there is a difference is the way you will see the history?

也许不同的是你看待历史的方式?

回答by Cascabel

This answer is mostly quoted from my answer to a previous question: git reset in plain english.

这个答案主要引用自我对上一个问题的回答:git reset in plain english

The two are very different. They result in the same state for your index and work tree, but the resulting history and current branch aren't the same.

两者非常不同。它们为您的索引和工作树生成相同的状态,但生成的历史记录和当前分支不相同。

Suppose your history looks like this, with the master branch currently checked out:

假设您的历史记录如下所示,当前已检出 master 分支:

- A - B - C (HEAD, master)

and you run git reset --hard B. You'll get this:

然后你跑git reset --hard B。你会得到这个:

- A - B (HEAD, master)      # - C is still here, but there's no
                            # branch pointing to it anymore

You'd actually get that effect if you use --mixedor --softtoo - the only difference is what happens to your work tree and index. In the --hardcase, the work tree and index match B.

如果您使用--mixed或,您实际上会得到这种效果--soft- 唯一的区别是您的工作树和索引会发生什么。在这种--hard情况下,工作树和索引匹配B

Now, suppose you'd run git checkout Binstead. You'd get this:

现在,假设你会跑git checkout B。你会得到这个:

- A - B (HEAD) - C (master)

You've ended up in a detached HEAD state. HEAD, work tree, index all match B, same as with the hard reset, but the master branch was left behind at C. If you make a new commit Dat this point, you'll get this, which is probably not what you want:

您最终处于分离的 HEAD 状态。HEAD, work tree, index all match B,与硬重置相同,但 master 分支在C. 如果您此时进行新的提交D,您会得到这个,这可能不是您想要的:

- A - B - C (master)
       \
        D (HEAD)

So, you use checkout to, well, check out that commit. You can fiddle with it, do what you like, but you've left your branch behind. If you want the branch moved too, you use reset.

因此,您可以使用 checkout 来检查该提交。你可以摆弄它,做你喜欢做的事,但你已经把你的分支抛在了后面。如果您也希望分支移动,请使用重置。

回答by Jakub Nar?bski

If documentation provided with Git doesn't help you, take a look at A Visual Git Referenceby Mark Lodato.

如果 Git 提供的文档对您没有帮助,请查看Mark Lodato 的A Visual Git Reference

In particular if you are comparing git checkout <non-branch>with git reset --hard <non-branch>(hotlinked):

特别是如果您正在git checkout <non-branch>git reset --hard <non-branch>(热链接)进行比较:

git checkout master~3
(source: github.com)

git结帐大师~3
(来源:github.com

git reset --hard master~3

git reset --hard master~3

Note that in the case of git reset --hard master~3you leave behind a part of DAG of revisions - some of commits are not referenced by any branch. Those are protected for (by default) 30 days by reflog; they would ultimately be pruned (removed).

请注意,如果git reset --hard master~3您留下了一部分 DAG 修订版 - 某些提交没有被任何分支引用。这些受reflog保护(默认情况下)30 天;它们最终会被修剪(移除)。

回答by hasen

git-reset hashsets the branch reference to the given hash, and optionally checks it out, with--hard.

git-reset hash将分支引用设置为给定的散列,并可选择使用--hard.

git-checkout hashsets the working tree to the given hash; and unless hash is a branch name, you'll end up with a detached head.

git-checkout hash将工作树设置为给定的哈希值;除非 hash 是一个分支名称,否则你最终会得到一个分离的头。

ultimately, git deals with 3 things:

最终,git 处理 3 件事:

                   working tree (your code)
-------------------------------------------------------------------------
                     index/staging-area
-------------------------------------------------------------------------
      repository (bunch of commits, trees, branch names, etc)

git-checkoutby default just updates the index and the working tree, and can optionally update something in the repository (with the -boption)

git-checkout默认情况下只更新索引和工作树,并且可以选择更新存储库中的某些内容(使用-b选项)

git-resetby default just updates the repository and the index, and optionally the working tree (with the --hardoption)

git-reset默认情况下只更新存储库和索引,以及可选的工作树(带有--hard选项)

You can think of the repository like this:

您可以这样考虑存储库:

 HEAD -> master

 refs:
    master -> sha_of_commit_X
    dev -> sha_of_commit_Y

 objects: (addressed by sha1)

    sha_of_commit_X, sha_of_commit_Y, sha_of_commit_Z, sha_of_commit_A ....

git-resetmanipulates what the branch references point to.

git-reset操纵分支引用指向的内容。

Suppose your history looks like this:

假设您的历史记录如下所示:

           T--S--R--Q [master][dev]
          / 
   A--B--C--D--E--F--G [topic1]
                   \
                    Z--Y--X--W [topic2][topic3]

Keep in mind that branches are just names that advance automatically when you commit.

请记住,分支只是在您提交时自动前进的名称。

So you have the following branches:

所以你有以下分支:

 master -> Q
 dev -> Q
 topic1 -> G
 topic2 -> W
 topic3 -> W

And your current branch is topic2, that is, the HEAD points to topic2.

而你当前的分支是topic2,即HEAD指向topic2。

HEAD -> topic2

Then, git reset Xwill reset the name topic2to point to X; meaning if you make a commit P on branch topic2, things will look like this:

然后,git reset X将名称重置topic2为指向 X;这意味着如果您在分支 topic2 上提交 P,事情将如下所示:

           T--S--R--Q [master][dev]
          / 
   A--B--C--D--E--F--G [topic1]
                   \
                    Z--Y--X--W [topic3]
                           \
                            P [topic2]