Git:如何在不暂存文件以供删除的情况下取消跟踪文件

Git: how to untrack files without staging them for deletion

我有一些配置文件想在本地更改,但不想冒意外提交这些更改的风险。它们也不能添加到 gitignore,因为需要在整个项目中跟踪它们。当我修改这些文件以满足我的环境需要时,我的 git status 看起来像这样:

Changes not staged for commit:
    (use "git add <file>..." to update what will be committed)
    (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   config1.cfg
        modified:   config2.cfg

Untracked files:
    (use "git add <file>..." to include in what will be committed)

        whatever.html
        somethingElse.js

然后我运行:

git rm --cached config1.cfg config2.cfg

git status 看起来像这样:

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

        deleted:    config1.cfg
        deleted:    config2.cfg

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    config1.cfg
    config2.cfg
    whatever.html
    somethingElse.js
    

运行 git reset --HEAD config1.cfg config2.cfg returns 他们到集结区,不出所料。但是,某些内容可能未被跟踪但仍同时上演,这有点没有意义,即使该上演是为了删除。而且——我没有删除文件,但如果我现在提交,它们将被删除。

我意识到这可能是污迹和清洁过滤器的更好用例,但是否有可能达到一种状态,即以前跟踪的文件未被跟踪,就好像从未被跟踪过一样?如果不是,是否有充分的理由不可能?

编辑澄清一下,现在我对情况有了更好的了解:我试图创建的场景是我工作时文件在我的本地未被跟踪,而不会影响它们在远程的跟踪状态.

but if I commit now then they will be deleted.

没有。 文件(你在工作树中看到的那些东西)不会被删除。提交对工作树没有影响

commit 会将它们记录为已删除,因为它必须这样做,因为它们存在于上一次提交中,而现在你说它们不应该出现在下一次提交中.这就是删除:存在的东西现在不再存在。

Git的三个地方

听起来您可能会受益于了解一下 Git“是”什么。 Git功法横扫三处:

  • 工作树。这就是 Git 向您展示的内容。它是将一个装满文件的文件夹渲染到磁盘上,以便您可以编辑这些文件。

  • 索引。也称为临时区域或缓存。这是一个不可见的 引用 文件集合,这些文件构成了您下一次提交将包含的内容。

  • 实际 存储库 提交 的不可见集合。每个提交本身都包含文件,在某种意义上,“包含”这个词的细节在这里并不重要。

当您签出一个分支时,您正在签出一个提交。提交用于填充工作树和索引;他们在那一刻都匹配。

如果您更改工作树中的一个文件(这是您 可以 更改任何内容的唯一位置)并添加它并提交,那么只有那个文件被更改,正确,但所有其他文件仍在工作树和索引中,因此此提交包含 所有文件 — 而不仅仅是您更改的文件(这是一个常见的误解)。每次提交都是创建索引时 whole 状态的快照,而这又反映了 whole 状态工作树,由您选择添加到索引的内容调解。

因此,索引是您可以操纵在工作树中执行的操作与将进入下一次提交的操作之间的关系的地方。当您说 git add . 时,您实际上是在说“索引应该反映 我在工作树中所做的一切 ”。但这是一个非常广泛的命令;您可以绝对 file-by-file 精确控制索引在 run-up 到下一次提交时的样子。

你做了什么

当你说 git rm --cached config1.cfg 时,你说的是,“从 config1.cfg =58=]索引。"当您提交时,这对工作树没有影响;它只会进行提交,其中 config1.cfg 恰好不存在。

但是现在您正在考虑这个问题,并且您意识到这不是您要说的意思,因为下一次提交将构成 的删除 config1.cfg。你不喜欢那样。您确实希望下一次提交仍然包含config1.cfg;您只是不希望它从上次提交中 更改

这就是你说的意思:

I have some config files that I want to change locally but not risk accidentally committing those changes

你应该做的

您的目标不是进行 config1.cfg 不存在的提交。您的目标是进行提交,其中 config1.cfg 与之前的状态相比 未更改,即使您实际上已经编辑了它工作树。

好的,那么您应该怎么做才能实现这一目标?好吧,第一道防线是:不要说 git add . 或类似的笼统的通配语句。相反,为了将更改的文件添加到索引,不要添加它们。只需将您 想要反映在下一次提交中的更改文件添加到索引。

但是假设您鲁莽地突破了该保护措施并且您 确实config1.cfg 以其更改后的状态添加到索引中. (你做到了。) 然后说 git restore --staged config1.cfg。这会将 config1.cfg 从上次提交(每次提交都包含所有文件,还记得吗?)复制到索引中。所以现在索引中的 config1.cfg 看起来像以前的提交,而不像工作树版本。状态将是 git 知道您已经修改了工作树中的 config1.cfg(除非您已将其添加到 gitignores 文件) ,但该更改不会计划包含在您进行的下一次提交中。

(在Git版本2.25.0之前,你会使用git reset的形式来完成这个目标,即git reset config1.cfg。但是git reset是可怕的,所以如果你有足够新的 Git,请改用 restore。)