git reset --hard不会使工作树看起来像索引?

时间:2016-04-01 06:20:38

标签: git git-reset

Pro Git解释git reset就像这样:

  

小结

     

reset命令按特定顺序覆盖这三棵树,当你告诉它时停止:

     
      
  1. 将分支HEAD点移至(如果--soft,则停在此处
  2.   
  3. 使索引看起来像HEAD (在此处停止,除非--hard
  4.   
  5. 使工作目录看起来像索引
  6.   

我理解的方式是,如果我git reset --hard,那么我的索引和工作目录都会像我的HEAD一样完全。所以我继续这样做了:

# make a git repo
mkdir mygitrepo
cd mygitrepo
git init

# init commit
touch old_file
git commit -a

# stage a file
touch staged
git add staged

# create file that is not staged
touch unstaged

到目前为止,我的回购看起来像这样:

  • HEAD old_file
  • index old_file + staged
  • working dir old_file + staged + unstaged

现在,如果我运行git reset --hard,那么我希望我的回购成为:

  • HEAD old_file
  • index old_file
  • working dir old_file

但我会这样做:

  • HEAD old_file
  • index old_file
  • working dir old_file + unstaged

我通过显式传递目标参数(例如git reset --hard target)进行了类似的测试,我得到了类似的结果:暂存的文件都消失了,但是git reset --hard之后仍然存在未分段的文件。

有人可以解释我是否误解了git reset的任何内容?

2 个答案:

答案 0 :(得分:1)

如" Undoing Changes"

中所述
  

git clean命令通常与git reset --hard一起执行   请记住,重置只会影响跟踪的文件,因此需要单独的命令来清除未跟踪的文件

     

组合使用这两个命令可以将工作目录返回到特定提交的确切状态。

--hard选项记录为:

  

重置索引和工作树   自<commit>以来对工作树中跟踪的文件的任何更改都将被丢弃。

这在2008年已经讨论过了 Simply put by Linux Torvalds

  

如果你习惯做&#34; git checkout -f&#34;或者&#34; git reset --hard&#34;,这两个检查(*)都被忽略了。毕竟,你要求强制切换。

(*检查=脏文件或未跟踪文件)

  

至少在第二种情况下,我认为发生的是git赢了   删除它不知道的文件,这样你就会有一个&#34; turd&#34;离开了

已添加文件...即使从未提交过(全新),仍然会被git reset --hard删除为seen also in 2008

  

我昨天意外删除了数百个新添加的文件   这样做。

     

我的问题是为什么&#34; git reset --hard&#34;不能成为一个特例    新添加的跟踪文件?
  毕竟,&#34; git status&#34;知道他们已经&#34;新文件&#34;和&#34; git reset --hard&#34;我们可以意识到,从地球上擦掉它们并不是最有帮助的事情。

作为建议,git read-tree -m HEADgit rm --cached <file list> 之前 git reset --hard有助于保留这些新文件(将其从索引中移除)

Junio C. Hamano stil argues

  

你会想要&#34; reset --hard&#34;当在HEAD中不存在路径但在其他情况下在索引中时删除该路径   而且,根据我的经验,这往往是最理想的。

(就像摆脱冲突的合并一样)

请注意,在此实例中,git fsck can still help recover those deleted new files

答案 1 :(得分:1)

Git会遵循一条重要规则(除非明确告知不要这样做):请勿触摸未跟踪的文件

使用默认功能,Git永远不会执行任何最终导致未跟踪文件丢失的操作。这是因为来自未跟踪文件的信息永远无法被Git恢复:它不会“知道”它们,所以它不会将它们的内容存储在任何地方,因此对它们进行任何操作都非常危险。所以它根本不会碰它们。

这也是为什么如果该分支包含具有相同路径的跟踪的文件,Git将不允许您切换到具有未跟踪文件的分支。因为这样做会覆盖未跟踪的文件,将其替换为该分支中的文件,但您永远无法恢复未跟踪的文件。所以Git不会切换分支,要求你先处理未跟踪的文件(这可能意味着重命名它,将它添加到Git,甚至删除它)。

因此,当您执行git reset时,您只会影响索引。 git reset --hard将影响索引和工作目录。对于Git,工作目录仅包含跟踪文件。这就是git reset --hard既不会删除未跟踪文件也不会删除.gitignore中文件的原因。 Git并不“了解”它们,因此它不会触及它们。

如果要删除未跟踪的文件,则有一个命令负责:git clean。该命令带有不同的参数组合,它们都执行各种不同的工作。

默认情况git clean -f将删除未跟踪的文件,但保持忽略的文件不变。如果您还想删除被忽略的文件,可以使用git clean -x -f。请注意,您通常必须为-f指定--force(或git clean)才能执行任何操作。这只是一个额外的安全机制,以确保您知道自己在做什么。您可以使用-n来执行空运行,并仅显示Git将删除哪些文件。这样可以轻松避免出现问题。