git checkout HEAD-之间有区别吗?和git reset --hard HEAD吗? [英] Is there a difference between git checkout HEAD -- . and git reset --hard HEAD?

查看:174
本文介绍了git checkout HEAD-之间有区别吗?和git reset --hard HEAD吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过了这个stackoverflow链接,但我认为我要问的是在结帐cmd中使用HEAD的细微差别,因为他们的建议似乎不起作用:

I have taken a look at this stackoverflow link but I think the subtle difference between what I am asking is the usage of HEAD within the checkout cmd as their suggestions don't' seem to be working :

两者之间是否有区别git reset --hard HEAD和git checkout.?

git checkout HEAD -- .也会清理我的暂存区. 此外,第二个答案是关于已添加到登台区域的已删除文件的信息, 似乎又回来了git checkout HEAD -- .

git checkout HEAD -- . cleans out my staging area as well. Additionally, the second answer, regarding deleted files added to staging area, seem to be coming back with git checkout HEAD -- .

有没有一种情况会得到不同的结果?

Is there a situation where one would get different results?

推荐答案

是的,除了.所暗示的以外(如果您不在存储库的顶层),还有一个区别.我什至不会声称只有 差异.只需显示一个示例,看看它们是不同的即可.

Yes, there is a difference, besides that implied by . if you're not at the top level of your repository. I won't go so far as to claim that what follows is the only difference; it suffices to show one example, to see that they are different.

首先创建一个至少具有一次提交的新存储库(按照我的习惯,在这里我做了两次提交):

Start by creating a new repository with at least one commit (here I have made two, as is my habit):

$ mkdir treset
$ cd treset
$ git init
Initialized empty Git repository in ...
$ echo 'for testing reset vs checkout' > README
$ git add README
$ git commit -m 'initial commit'
[master (root-commit) 058b755] initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 README
$ echo contents for file a > file-a
$ echo contents for file b > file-b
git commit -m 'add files'
[master f505609] add files
 2 files changed, 2 insertions(+)
 create mode 100644 file-a
 create mode 100644 file-b

这时,HEAD和索引匹配(均包含来自提交f505609的内容),工作树也包含与提交匹配的(正常格式)文件.现在,我们添加一个 new 文件,并将其复制到索引中:

At this point, HEAD and the index match—both contain the content from commit f505609—and the work-tree contains the (normal format) files that match that commit as well. Now let's add a new file, and copy it into the index:

$ echo 'uncommitted file' > foo
$ git add foo

技术上,git add foo在存储库中创建了 blob对象 a9e2570d6af8c05b57e2cefecaebeedfabc98bf2,然后将该哈希ID放入索引中:

Technically, the git add foo created blob object a9e2570d6af8c05b57e2cefecaebeedfabc98bf2 in the repository and then put that hash ID into the index:

$ git ls-files --stage
100644 e16f62b2e75cf86a6f54adcfddcfd77140f238b9 0       README
100644 881d9334f4593efc7bab0dd536348abf47efed5c 0       file-a
100644 fa438bc26ce6b7a8f574bad9e63b83c912a824b9 0       file-b
100644 a9e2570d6af8c05b57e2cefecaebeedfabc98bf2 0       foo

(由于文件foo的已知内容,该blob对象的哈希ID是可预测的.其他三个文件也是如此,但实际上它们是已提交的,因此这些blob对象是永久的.如果foo从未真正提交过,而是从索引中删除了该条目,则可以将其GC化.)

(The hash ID of this blob object is predictable due to the known content for file foo. That's true of the other three files as well, but they're actually committed, so those blob objects are permanent. The one for foo could be GCed, if we never actually commit it and instead remove the entry from the index.)

如果使用git checkout HEAD,则将Git从HEAD定向到 copy 到索引中,然后将其扩展为普通的工作树文件. HEAD包含三个文件(READMEfile-afile-b),因此执行此操作,并使用它们已经具有的内容更新这三个工作树文件,因此没有明显的效果. 1

If we use git checkout HEAD, we direct Git to copy from HEAD into the index and then expand them into normal work-tree files. HEAD contains three files (README, file-a, and file-b), so this does that and updates the three work-tree files with the contents they already have—so there's no observable effect.1

$ git checkout HEAD -- .; ls
file-a  file-b  foo README

请注意,文件foo保留在索引(再次运行git ls-files以查看)和工作树中.

Note that file foo remains, both in the index (run git ls-files again to see) and in the work-tree.

1 除非,就是说,我们通过可用的任何OS级工具来检查文件修改时间或执行的系统调用之类的事情.在这种情况下,我们可以判断Git是否确实覆盖了工作树文件.在我的系统上,它实际上没有,因为索引哈希与HEAD哈希匹配,并且索引中缓存的stat数据与工作树文件中的stat数据匹配,所以它没有打扰.但是在原理中,Git将HEAD复制到索引,然后将索引复制到工作树,并且如果有必要基于哈希和/或统计数据,则Git实际上会接触到工作-tree文件在这里.

1Unless, that is, we inspect things like file modification times or system calls executed, via whatever OS-level tools we have available. In this case we can tell if Git really did overwrite the work-tree files or not. On my system, it actually didn't, because the index hashes matched the HEAD hashes and the stat data cached in the index matched the stat data from the work-tree files, so it didn't bother. But in principle Git copied HEAD to the index, and then the index to the work-tree, and if it were necessary based on hashes and/or stat data, Git would have actually touched the work-tree files here.

如果我们告诉Git重置索引以匹配当前提交,并重置工作树以匹配对索引的更改,则操作是不同的.这次,Git检查索引并看到文件foo存在,而提交中没有该文件.因此,Git从索引中删除文件foo ,并相应地更新工作树:

If we tell Git to reset the index to match the current commit, and reset the work-tree to match changes to the index, the action is different. This time, Git examines the index and sees that file foo is present, while it's absent in the commit. So Git removes file foo from the index, and updates the work-tree accordingly:

$ git reset --hard HEAD; ls
HEAD is now at f505609 add files
file-a  file-b  README

文件foo从工作树中消失了.

File foo has vanished from the work-tree.

如果我们要使用git reset --mixed HEAD,则Git将从索引中删除foo,但不会从工作树中删除. (这种重设的默认操作(还有很多其他类型)是--mixed.)

If we were to use git reset --mixed HEAD, Git would remove foo from the index, but not from the work-tree. (The default action for this kind of reset—there are many other kinds—is --mixed.)

使用新的Git 2.23+ git restore命令,我们可以分别控制索引和工作树.首先,我们必须将foo放回到索引和工作树中:

With the new Git 2.23+ git restore command, we can control the index and work-tree separately. First we have to put foo back into the index and work-tree:

$ echo 'uncommitted file' > foo
$ git add foo

我们现在可以选择是否将HEAD复制到索引,以及是否类似地管理工作树. 其文档也更加明确:

We can now choose whether to copy HEAD to the index or not, and whether to manage the work-tree similarly. Its documentation is a bit more explicit too:

如果跟踪了一条路径,但该路径在还原源中不存在,则会将其删除以匹配该源.

If a path is tracked but does not exist in the restore source, it will be removed to match the source.

要跟踪"路径的意思是该路径在索引中.在这种情况下,foo现在已在索引中(由于git add),因此可以对其进行跟踪.如果我们从HEAD恢复索引,则foo将从索引中删除,就像git reset --hardgit reset --mixed一样.因此,让我们尝试 VonC的命令,但要使用.(当前目录和所有子目录) 2 作为路径名,在这里:

What it means for a path to be "tracked" is that the path is in the index. In this case, foo is in the index now (due to the git add) so it is tracked. If we restore the index from HEAD, foo will be removed from the index, just as with git reset --hard or git reset --mixed. So let's try VonC's command, but with . (the current directory and all sub-directories)2 as the pathname, here:

$ git restore --source HEAD --staged --worktree .
$ ls
file-a  file-b  README

因此您可以看到它与git reset --hard具有相同的效果.与git reset不同,git restore仅具有一项工作-尽管有两个部分,所以我们不必担心其他操作模式.

So you can see that this had the same effect as git reset --hard. Unlike git reset, git restore has only one job—though with two parts to it—so we need not worry about other modes of operation.

(这就是为什么同时添加了git switchgit restore的原因:大多数情况下相同的事情您已经可以使用git checkoutgit reset进行,但是它们只有一项工作,即使它包含多个部分;相比之下,git checkout则有大约三到七个不同的工作,具体取决于您的计算方式,而git reset则有大约三到五个左右的工作. 3 )

(This is why both git switch and git restore were added: the mostly do the same things you can already do with git checkout and git reset, but they only have one job, even if it has several parts. By contrast, git checkout has anywhere from about three to about seven different jobs, depending on how you count, and git reset has anywhere from about three to about five.3)

2 这个特定的存储库只有一个顶级目录,因此我们不必担心您在工作树中做了一个cd subdir.但是,如果有的话,.意味着将其应用于subdir/*文件,这样,结帐和重置就更加不同了.

2This particular repository has only the one top level directory, so we need not worry that you've done a cd subdir within the work-tree. If you had, though, . would mean apply this to the subdir/* files, so that checkout and reset would be even more different.

3 对于git checkout,请考虑:

  • 切换分支
  • 从索引提取到工作树(仅la git checkout-index)
  • 从特定提交中提取索引,然后再提取到工作树
  • 复制合并冲突(具有文件名的git checkout -m)
  • 在合并时切换分支(git checkout -m但具有分支名称)
  • switch branches
  • extract from index to work-tree (only, a la git checkout-index)
  • extract from specific commit to index and then on to work-tree
  • reproduce merge conflict (git checkout -m with a file name)
  • switch branches while merging (git checkout -m but with a branch name)

虽然只有五个,但我们可以git checkout --oursgit checkout --theirs进行操作,有些人可能希望将它们与通常的从索引提取"风格分开计算.当您添加 create分支(git checkout -b)和强制重置分支(git checkout -B)时,我们可以获得更多. <,git switch也具有创建和强制重置选项!

While that's just five, we can git checkout --ours and git checkout --theirs and some might wish to count these as separate from the usual "extract from index" flavor. We can get even more when you add create branch (git checkout -b) and forcibly reset branch (git checkout -B). Alas, git switch has the create and forcibly-reset options as well!

当然,有些可能会像git checkout一样将其中的一些或全部集中到一个操作中.这就是为什么我说取决于您的计数"的原因.

Some might, of course, lump some or all of these into one operation, just as git checkout does. That's why I say "depending on how you count".

对于git reset,请考虑:

  • 在不移动HEAD
  • 的情况下重置索引和/或工作树
  • 通过移动HEAD
  • 重置索引和/或工作树
  • 重置一个或多个特定路径(不能移动HEAD)
  • 中止合并,选择或还原(无法移动HEAD)
  • git reset -p有选择地打补丁(不能移动HEAD)
  • reset index and/or work-tree without moving HEAD
  • reset index and/or work-tree with moving HEAD
  • reset one or more specific paths (cannot move HEAD)
  • abort a merge or cherry-pick or revert (cannot move HEAD)
  • selectively patch with git reset -p (cannot move HEAD)

所有这些都集中在一个命令git reset下.

all of which are lumped under the one command git reset.

这篇关于git checkout HEAD-之间有区别吗?和git reset --hard HEAD吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆