git checkout HEAD-之间有区别吗?和git reset --hard HEAD吗?

时间:2019-12-14 23:17:01

标签: git

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

https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/connections-api

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

有没有可能得到不同结果的情况?

2 个答案:

答案 0 :(得分:3)

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

说明差异的设置

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

$ 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 文件,并将其复制到索引中:

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

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

$ 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起来,而从索引中删除该条目。)

使用git checkout HEAD

如果我们使用git checkout HEAD,我们会将Git从HEAD定向到 copy 到索引中,然后将它们扩展为普通的工作树文件。 HEAD包含三个文件(READMEfile-afile-b),因此可以做到这一点,并使用它们已经拥有的内容更新这三个工作树文件,因此没有明显的效果。 1

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

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


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


使用HEAD

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

foo

文件$ git reset --hard HEAD; ls HEAD is now at f505609 add files file-a file-b README 从工作树中消失了。

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

使用--mixed

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

foo

我们现在可以选择是否将$ echo 'uncommitted file' > foo $ git add foo 复制到索引,以及是否类似地管理工作树。 Its documentation也更加明确:

  

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

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

.

因此,您可以看到它与$ git restore --source HEAD --staged --worktree . $ ls file-a file-b README 具有相同的作用。与git reset --hard不同,git reset仅具有一项工作-尽管有两个部分,所以我们不必担心其他操作模式。

(这就是为什么同时添加了git restoregit switch的原因:大多数情况下,您可以使用git restore和{{1} },但他们只有一个工作[em] ,即使它有多个部分。相反,git checkout有大约三到七个不同的工作,具体取决于您的计算方式,而{ {1}}的范围是大约3到大约5。 3


2 此特定存储库只有一个顶级目录,因此我们不必担心您在工作树中完成了git reset。如果有的话,git checkout意味着将其应用于git reset文件,因此签出和重置将更加不同。

3 对于cd subdir,请考虑:

  • 切换分支
  • 从索引提取到工作树(仅la .
  • 从特定提交中提取索引,然后再到工作树
  • 复制合并冲突(带有文件名的subdir/*
  • 在合并时切换分支(git checkout,但具有分支名称)

虽然只有五个,但我们可以git checkout-indexgit checkout -m进行操作,有些人可能希望将它们与通常的“从索引中提取”味道分开。当您添加 create分支git checkout -m)和强制重置分支git checkout --ours)时,我们可以得到更多。 {,git checkout --theirs也具有创建和强制重置选项!

某些人当然可以像git checkout -b一样将其中的一些或全部集中到一个操作中。这就是为什么我说“取决于您的计数”的原因。

对于git checkout -B,请考虑:

  • 无需移动git switch即可重置索引和/或工作树
  • 通过移动git checkout
  • 来重置索引和/或工作树
  • 重置一个或多个特定路径(无法移动git reset
  • 中止合并,选择或还原(无法移动HEAD
  • 使用HEAD进行选择性修补(无法移动HEAD

所有这些都集中在一个命令HEAD下。

答案 1 :(得分:1)

为避免使用confusion,应使用新的实验性命令 git restore (Gti 2.23 +,2019年8月)。

正如我在“ What is git restore Command ? What is the different between git restore and git reset?”中所述,您可以指定使用git restore恢复的内容。

  • 索引
  • 和/或工作树。

这比在git checkout中依靠HEAD或不依靠HEAD更为明确。

使用reset --hardgit restore

git restore --source=HEAD --staged --worktree hello.c

或简称,它更实用,但可读性更差:

git restore -s@ -SW hello.c