为什么git无法按路径进行硬/软重置?


138

$ git reset -- <file_path> 可以按路径重置。

但是,$ git reset (--hard|--soft) <file_path>将报告如下错误:

Cannot do hard|soft reset with paths.

Answers:


143

因为没有意义(其他命令已经提供了该功能),并且减少了意外执行错误操作的可能性。

只需执行“硬重置”路径git checkout HEAD -- <path>(检出文件的现有版本)。

路径的软复位没有意义。

路径的混合重置是做什么的git reset -- <path>


72
我个人认为git checkout -- <path>应该替换git reset --hard <path>。这更有意义……
vergenzt 2012年

24
git checkout -- <path>不进行硬重置;它用暂存内容替换工作树内容。git checkout HEAD -- <path>对路径进行硬重置,将索引和工作树都替换为HEAD提交中的版本。
Dan Fabulich

1
@EdPlunkett Er,答案中的第二句话告诉您其他什么命令可以提供此功能。
2014年

16
-1:如果所述修订包含已删除的文件,则检出该修订不会从工作副本中删除文件。reset --hard一条路径可以提供这个缺失的部分。Git已经非常强大,以至于“我们不允许您为了自己的保护而这样做”的借口是零水:有很多方法可以“无意间”做错事。无论如何,这都不重要git reflog
void.pointer 2015年

1
如@ void.pointer检出所述,不会删除文件。如果您想要这种行为,请查看答案。不过,我希望有一天我们能得到git reset --hard -- <path>。有合法的用例。
Mariusz Pawelski

18

您可以使用来完成您想做的事情git checkout HEAD <path>

就是说,提供的错误消息对我来说没有任何意义(因为git reset在子目录上可以正常工作),而且我认为没有理由不git reset --hard应该完全按照您的要求进行操作。


使用签出阶段进行更改,这与重置不同--soft
worc

11

问题如何已经回答,我将解释为什么部分。

那么,git reset有什么作用?根据指定的参数,它可以做两件事:

  • 如果指定路径,它将用提交中的文件替换索引中匹配的文件(默认为HEAD)。这个动作根本不影响工作树,通常用作git add的反义词。

  • 如果未指定路径,它将当前分支头移至指定的提交,并与一起将索引和工作树重置为该提交的状态。此额外的行为由mode参数控制:--
    soft:不要触摸索引和工作树。
    --mixed(默认):重置索引,但不重置工作树。
    --hard:重置索引和工作树。
    还有其他选项,请参阅文档以获取完整列表和一些用例。

    当您不指定提交时,它默认为HEAD,因此git reset --soft不会执行任何操作,因为这是将头移到HEAD(到当前状态)的命令。git reset --hard另一方面,由于其副作用,它很有道理,它表示将head移至HEAD 并将索引和工作树重置为HEAD。

    我认为现在应该很清楚为什么此操作不是针对特定文件的性质-它旨在首先移动分支头,重置工作树,而索引是第二功能。


显然,reset首先是要移动分支头的,但是由于它具有重置工作树和整个提交的索引的附加功能,以及重置特定文件的索引的功能,所以为什么不这样做呢?具有为特定文件重置工作树的功能?我相信这就是OP的要求。
Danilo SouzaMorães18年

也许是因为该功能(为特定文件重置工作树)已经可以作为git checkout命令使用?并使重置执行相同的操作会使用户进一步困惑。我的回答是,该--hard选项不适用于特定文件,因为它是分支重置而不是索引重置的模式。工作树重置称为结帐,您可以在其他答案中阅读。所有这些只是Git用户界面恕我直言的错误设计。
用户

比较第一个选项与git checkoutgit reset --仅设置索引,而仅git checkout --设置工作树?
seeker_of_bacon


3

有背后的一个很重要的原因:原则checkoutreset

用Git术语来说,检出意味着“进入当前的工作树”。并且,git checkout我们可以用任何区域的数据填充工作树,无论是来自存储库中的提交的数据,还是来自提交或暂存区域的单个文件(甚至是默认值)。

反过来,git reset没有这个角色。顾名思义,它将重置当前引用,但始终存储库作为源,而与“范围”(--soft,-mixed或--hard)无关。

回顾:

  • 结帐:从任何地方(索引/仓库提交)->工作树
  • reset:回购提交->覆盖HEAD(以及可选的索引和工作树)

因此存在一个令人困惑的问题,git reset COMMIT -- files因为仅用某些文件进行“覆盖HEAD”是没有意义的!

在没有官方解释的情况下,我只能推测git开发人员发现这reset仍然是丢弃对暂存区所做的更改的命令的最佳名称,并且鉴于唯一的数据源是存储库,因此“ 让我们扩展功能 ”,而不是创建新命令。

因此,某种程度上git reset -- <files>已经有些特殊了:它不会覆盖HEAD。恕我直言,所有这些变化都是例外。即使我们可以构思一个--hard版本,其他版本(例如--soft)也没有任何意义。


我喜欢这个答案。的确,git reset -- <files>由于它是一项有用的功能,所以喜欢添加它,但是没人知道应该在哪个命令中使用它。幸运的是,现在我们有更多的理智git restore,其具有的功能git checkout -- <path> git checkout <commit> -- <path>git reset [<commit>] -- <path>使用更加健壮的默认值,甚至更多的功能,你以前无法完成(相反的是接受的答案说,现在你终于可以轻松地恢复只是工作树,没有动人的指数)。
Mariusz Pawelski

0

说明

git reset手册列出了三种调用方式:

  • 2是文件方式的:它们不会影响工作树,而是仅对由<paths>以下指定的索引中的文件进行操作:

    • git reset [-q] [<tree-ish>] [--] <paths>..
    • git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
  • 1是明智的提交方式:对引用的中的所有文件进行操作<commit>,并且可能会影响工作树:

    • git reset [<mode>] [<commit>]

没有调用模式只能在指定的文件上运行影响工作树。

解决方法

如果两者都想:

  • 重置文件的索引/缓存版本
  • 检出文件(即,使工作树与索引匹配并提交版本)

您可以在git配置文件中使用此别名:

[alias]
  reco   = !"cd \"${GIT_PREFIX:-.}\" && git reset \"$@\" && git checkout \"$@\" && git status --short #"  # Avoid: "fatal: Cannot do hard reset with paths."

然后,您可以执行以下操作之一:

$ git reco <paths>

$ git reco <branch/commit> <paths>

$ git reco -- <paths>

(用于recoreset && check out)


-2

git reset --soft HEAD〜1 filename撤消提交,但更改保留在本地。文件名可能是-对于所有提交的文件


6
致命Cannot do soft reset with paths.
alt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.