当我想取消一个阶段性文件时,我所有的Git教程都显示如下内容:

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

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

这个提示告诉我们使用git重置来取消暂存文件。

但相反,在我的终端上,我看到:

git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    renamed:    cat.js -> catcat.js
    renamed:    tolendo.gogo -> tolendo.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    readme (copy).md
    tolendo (copy).txt
    zing (copy).html

我的终端告诉我要使用git恢复,但是教程和git的网站告诉我要使用git重置HEAD。

我不知道新的恢复命令。我尝试谷歌找到git重置和git恢复之间的区别,但似乎没有符合我的问题。


当前回答

对于第一个问题“git-restore是什么?”:

Git-restore是一个恢复未提交更改的工具。非提交的更改包括:a)工作副本中的更改,或b)索引(也就是暂存区域)中的内容。

这个命令是在git 2.23中引入的(和git-switch一起),用来分离之前在git-checkout中联合的多个关注点。

Git-restore可以在三种不同的模式下使用,这取决于您是想恢复工作副本中的工作,还是索引中的工作,或者两者都恢复。

Git恢复[——worktree] <file>覆盖<file>在你的工作副本索引(*)的内容。换句话说,它将还原工作副本中的更改。是否指定——worktree并不重要,因为如果不指定的话,它就是隐含的。

用本地存储库中的当前HEAD覆盖索引中的<文件>。换句话说,它取消了之前的内容。到目前为止,它确实相当于旧的git重置HEAD <file>。

使用git restore——staging——worktree——source HEAD <file>来覆盖工作副本和当前HEAD索引。这个版本可以做到这两点:将工作副本恢复到HEAD,并取消之前的工作。

对于你的第二个问题“git-restore和git-reset有什么区别?”:

这两个命令之间有重叠,也有不同之处。

两者都可以用于修改工作副本和/或暂存区域。但是,只有git-reset可以修改存储库。从这个意义上说,如果您只想恢复本地工作,git-restore似乎是更安全的选择。

还有更多不同之处,我在此无法一一列举。

(*)没有添加到索引的文件仍然被认为在索引中,但是从当前的HEAD修订来看,它处于“干净”状态。

其他回答

我用最近的git 2.23(2019年8月)在“如何从工作目录重置所有文件而不是从暂存区重置所有文件?”中介绍了git恢复(仍标记为“实验性”)。

它帮助将git检出分离为两个命令:

一个用于文件(git恢复),它可以覆盖git重置情况。 一个用于分支(git开关,参见“被git checkout弄糊涂了”),它只处理分支,而不处理文件。

如reset, restore和revert文档所述:

There are three commands with similar names: git reset, git restore and git revert. git-revert is about making a new commit that reverts the changes made by other commits. git-restore is about restoring files in the working tree from either the index or another commit. This command does not update your branch. The command can also be used to restore files in the index from another commit. git-reset is about updating your branch, moving the tip in order to add or remove commits from the branch. This operation changes the commit history. git reset can also be used to restore the index, overlapping with git restore.

So:

恢复索引中的文件以匹配HEAD中的版本(这与使用git-reset相同) Git恢复——暂存hello.c 或者您可以同时恢复索引和工作树(这与使用git-checkout相同) git restore——source=HEAD——staging——worktree hello.c 或者更实用但可读性较差的简写形式: git restore -s@ -SW hello.c


在Git 2.25.1(2020年2月)中,“Git restore - staging”没有正确地更新缓存树结构,导致随后编写虚假树,这一问题已被纠正。

看到讨论。

参见Jeff King (peff)的commit e701bab (2008 Jan 2020)。 (由Junio C Hamano—gitster—在commit 09e393d中合并,2020年1月22日)

restore: invalidate cache-tree when removing entries with --staged Reported-by: Torsten Krah Signed-off-by: Jeff King When "git restore --staged " removes a path that's in the index, it marks the entry with CE_REMOVE, but we don't do anything to invalidate the cache-tree. In the non-staged case, we end up in checkout_worktree(), which calls remove_marked_cache_entries(). That actually drops the entries from the index, as well as invalidating the cache-tree and untracked-cache. But with --staged, we never call checkout_worktree(), and the CE_REMOVE entries remain. Interestingly, they are dropped when we write out the index, but that means the resulting index is inconsistent: its cache-tree will not match the actual entries, and running "git commit" immediately after will create the wrong tree. We can solve this by calling remove_marked_cache_entries() ourselves before writing out the index. Note that we can't just hoist it out of checkout_worktree(); that function needs to iterate over the CE_REMOVE entries (to drop their matching worktree files) before removing them. One curiosity about the test: without this patch, it actually triggers a BUG() when running git-restore: BUG: cache-tree.c:810: new1 with flags 0x4420000 should not be in cache-tree But in the original problem report, which used a similar recipe, git restore actually creates the bogus index (and the commit is created with the wrong tree). I'm not sure why the test here behaves differently than my out-of-suite reproduction, but what's here should catch either symptom (and the fix corrects both cases).


在Git 2.27 (Q2 2020)中,“Git restore - staging -worktree”现在默认从“HEAD”中取出内容,而不是出错。

参见Eric Sunshine (sunshineco)提交的088018e(2020年5月05日)。 (由Junio C Hamano—gitster—在commit 4c2941a中合并,2020年5月8日)

restore: default to HEAD when combining --staged and --worktree Signed-off-by: Eric Sunshine Reviewed-by: Taylor Blau By default, files are restored from the index for --worktree, and from HEAD for --staged. When --worktree and --staged are combined, --source must be specified to disambiguate the restore source, thus making it cumbersome to restore a file in both the worktree and the index. (Due to an oversight, the --source requirement, though documented, is not actually enforced.) However, HEAD is also a reasonable default for --worktree when combined with --staged, so make it the default anytime --staged is used (whether combined with --worktree or not).

现在,这是可行的:

git restore --staged --worktree
git restore -SW

对于第一个问题“git-restore是什么?”:

Git-restore是一个恢复未提交更改的工具。非提交的更改包括:a)工作副本中的更改,或b)索引(也就是暂存区域)中的内容。

这个命令是在git 2.23中引入的(和git-switch一起),用来分离之前在git-checkout中联合的多个关注点。

Git-restore可以在三种不同的模式下使用,这取决于您是想恢复工作副本中的工作,还是索引中的工作,或者两者都恢复。

Git恢复[——worktree] <file>覆盖<file>在你的工作副本索引(*)的内容。换句话说,它将还原工作副本中的更改。是否指定——worktree并不重要,因为如果不指定的话,它就是隐含的。

用本地存储库中的当前HEAD覆盖索引中的<文件>。换句话说,它取消了之前的内容。到目前为止,它确实相当于旧的git重置HEAD <file>。

使用git restore——staging——worktree——source HEAD <file>来覆盖工作副本和当前HEAD索引。这个版本可以做到这两点:将工作副本恢复到HEAD,并取消之前的工作。

对于你的第二个问题“git-restore和git-reset有什么区别?”:

这两个命令之间有重叠,也有不同之处。

两者都可以用于修改工作副本和/或暂存区域。但是,只有git-reset可以修改存储库。从这个意义上说,如果您只想恢复本地工作,git-restore似乎是更安全的选择。

还有更多不同之处,我在此无法一一列举。

(*)没有添加到索引的文件仍然被认为在索引中,但是从当前的HEAD修订来看,它处于“干净”状态。