22

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

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

然而,Atlassian的不错的Git 教程只是简单地说:

git reset <file>

这似乎更直接,那么为什么有区别呢?

4

3 回答 3

25

在默认参数方面没有区别(来自git reset手册页):

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

该消息最初包括 HEAD: commit 3c1eb9c, Jan. 2007, git 1.5.0-rc1,但由于默认值并不总是已知的,因此帮助消息清楚地表明您应该重置哪个提交。

HEAD出现在提交 367c988,2007 年 11 月,Git 1.5.4 中

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

torek指出了评论中的实际差异:

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

请参阅“删除名称错误的 git 分支--”中有关双连字符语法 ( ) 的更多信息。




OP skube在评论中添加:

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

虽然git reset手册页清楚地表明在 HEAD 中缺少树状结构git reset <tree-ish> -- <paths>,但对于git checkout <tree-ish> -- <paths>.

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

<paths>给出时,git checkout不切换分支。它从索引文件或命名(通常是提交)
更新工作树中的命名路径。<tree-ish>

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

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

  • git reset <tree-ish> <file>您可以为:表示默认树HEAD
    因此git reset HEAD <file>
  • 但是当您不提供树时,您无法表示默认参数git checkout:它是索引。
    因此git checkout -- file

在这种情况下--必须使用git checkout,因为只有一个参数,并且需要明确参数代表files

请注意,这git checkout HEAD files是不同的:torek在评论中提到

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


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

请参阅示例

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

$ git restore --staged hello.c

手册页:

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

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

其他示例:

您可以恢复索引和工作树(这与 using 相同git-checkout

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

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

$ git restore -s@ -SW hello.c

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

于 2015-11-21T23:11:45.467 回答
4

默认情况下,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>]

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

[...]

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

这种形式将所有 <paths> 的索引条目重置为它们在 <tree-ish> 的状态。(它不会影响工作树或当前分支。)

这意味着git reset <paths>与 相反git add <paths>

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

这似乎更直接,那么为什么有区别呢?

由于它们都是相同的,因此您不妨使用两者中最短的版本。

于 2015-11-21T23:12:44.273 回答
1

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

$git reset HEAD stagedFile
fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree
于 2017-11-27T21:16:27.307 回答