【问题标题】:git reset vs git reset HEADgit reset vs git reset HEAD
【发布时间】:2016-02-24 07:11:38
【问题描述】:

每次暂存文件时,Git 都会在您需要取消暂存文件时提供有用的说明:

(use "git reset HEAD <file>..." to unstage)

不过正派的Git Tutorials by Atlassian 简单地说:

git reset <file>

这似乎更简单,那么为什么会有区别?

【问题讨论】:

  • 注意:您现在还有 git restore --staged -- afile,带有 Git 2.23(2019 年 8 月)。见my edited answer below

标签: git git-reset unstage


【解决方案1】:

在默认参数方面没有区别(与git reset man page):

<tree-ish>/<commit> 在所有形式中默认为HEAD

该消息最初包含 HEAD:commit 3c1eb9c, Jan. 2007, git 1.5.0-rc1,但由于默认值始终已知,因此帮助消息清楚地表明了您应该进行哪个提交重置。

HEAD 出现在commit 367c988, Nov. 2007, Git 1.5.4

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)

torek 指出实际差异in the comments

通过指定HEAD,您可以保证HEAD 之后的第一个单词被作为路径名。
例如,假设您运行git reset zorgzorg 是树状结构,例如标签名称,还是路径名称,./zorg
Git 的回答是:如果git rev-parse 可以将其转换为树 ID,则它是树形的,否则它是路径。
您可以写git reset -- zorggit reset HEAD zorg 以确保git 将其视为路径。

在“Deleting a badly named git branch”中查看有关双连字符语法 (--) 的更多信息。




OP skube 加上in the comments

顺便说一句,他们确实建议使用它来丢弃工作目录中的更改
(即git checkout -- &lt;file&gt;)。
它似乎与git reset HEAD &lt;file&gt; 不一致。

虽然git reset man page 清楚地表明git reset &lt;tree-ish&gt; -- &lt;paths&gt; 中缺少树状结构意味着HEAD,但git checkout &lt;tree-ish&gt; -- &lt;paths&gt; 并非如此。

git checkout <tree-ish> -- <pathspec>

当给定&lt;paths&gt; 时,git checkout 不会切换分支。
它会从索引文件或命名的&lt;tree-ish&gt;(大多数通常是提交)。

这意味着git checkout -- path 将使用已经暂存的内容(git add'ed)覆盖工作树。
git reset -- PATH(是 git reset 的混合形式)将使用 HEAD 包含的内容重置 索引(有效地取消暂存添加的内容)

git resetgit checkout 不使用相同的默认值,并且:

  • 您可以表示git reset &lt;tree-ish&gt; &lt;file&gt; 的默认树:HEAD
    因此git reset HEAD &lt;file&gt;;
  • 但是当您没有为git checkout 提供树时,您无法表示默认参数:它是索引。
    因此git checkout -- file

-- 必须用在git checkout 的情况下,因为只有一个参数,并且需要明确参数代表文件

注意git checkout HEAD files 不同:torek 提到in the comments

git checkout HEAD pathHEAD 提交(树状)复制到索引,然后复制到工作目录。


注意:对于 Git 2.23+,2019 年 8 月,您可以改用 git restore

the examples:

恢复索引中的文件以匹配 HEAD 中的版本(这与使用 git-reset 相同)

$ git restore --staged hello.c

手册页:

git restore --staged hello.c 不指定源,仅恢复索引 (--staged):它(默认情况下)使用 HEAD 作为源。

默认情况下,工作树和索引的恢复分别是索引和 HEAD。
--source 可用于指定一个提交作为恢复源。

其他例子:

您可以同时恢复索引和工作树(这与使用git-checkout 相同)

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

或者更实用但可读性较差的简短形式:

$ git restore -s@ -SW hello.c

git restore 是一个更自然的命令名称,没有歧义。

【讨论】:

  • 值得补充的是,通过指定HEAD 可以保证HEAD 之后的第一个单词被作为路径名。例如,假设您运行git reset zorgzorg 是树形的,例如标签名称,还是路径名称,./zorg? Git 的回答是:如果git rev-parse 可以将其转换为树 ID,则它是树形的,否则它是路径。您可以写git reset -- zorggit reset HEAD zorg 以确保git 将其视为路径。
  • @torek 非常正确,像往常一样。我已将您的评论包含在答案中(带有附加链接)以获得更多可见性。
  • 那么如果git reset -- &lt;file&gt;git reset HEAD &lt;file&gt; 功能相同,并且都比简单的git reset &lt;file&gt; 更安全一点,为什么git 会建议使用HEAD 版本?当然,输入-- 比输入HEAD 更容易。顺便说一句,他们确实建议使用它来丢弃工作目录中的更改(即git checkout -- &lt;file&gt;)。只是看起来不一致。
  • @skube 因为 Git 希望您知道语法涉及到 &lt;treeish&gt; before 文件。 git reset -- &lt;file&gt; 完全混淆了这一点。
  • @torek OP 指出了两个帮助消息之间有趣的不一致:git reset HEAD &lt;file&gt;git checkout -- &lt;file&gt;:为什么不同的语法?
【解决方案2】:

第一次,在任何提交之前 HEAD 不存在,然后我们得到:

$git reset HEAD stagedFile
fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree

【讨论】:

    【解决方案3】:

    默认情况下,git reset 等价于git reset HEAD

    引用手册页(我的重点):

    git-reset - 将当前 HEAD 重置为指定状态。

    git reset [-q] [<tree-ish>] [--] <paths>…
    git reset (--patch | -p) [<tree-ish>] [--] [<paths>…​]
    git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
    

    在第一种和第二种形式中,将条目从 复制到索引。在第三种形式中,将当前分支头 (HEAD) 设置为 ,可选 修改索引和工作树以匹配。 / 在所有形式中默认为 HEAD。

    [...]

    git reset [-q] [<tree-ish>] [--] <paths>…​
    

    此表单将所有 的索引条目重置为它们在 处的状态。 (它不影响工作树或当前 分支。)

    这意味着git reset &lt;paths&gt;git add &lt;paths&gt;相反。

    从这里您可以看到行为上没有实际差异。

    这似乎更简单,那么为什么会有区别?

    由于两者相同,您不妨使用两者中最短的版本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-04
      • 2018-01-13
      • 2014-09-03
      • 2023-03-23
      • 2014-08-25
      • 1970-01-01
      • 2011-08-13
      相关资源
      最近更新 更多