了解 .git忽略屏蔽和 git 清理

Understanding .gitignore masking and git clean

我真的很难理解 .gitignore file 是如何工作的...

我的文件是这样的:

custom/history
cache
*.log
custom/modules/*/Ext
upload
sugar-cron*
custom/application/Ext
custom/Extenstion/modules/*/Ext/Language
!custom/modules/*/Language/cs_CZ.*
!custom/modules/*/Language/en_us.*
custom/Extenstion/application/Ext/Language
!custom/Extenstion/application/Ext/Language/cs_CZ.*
!custom/Extenstion/application/Ext/Language/en_US.*
.htaccess
config.php
config_override.php
files.md5

这是我的 git 状态:

apache@cb772759c68a sugarcrm$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#    LOG.txt
#    deploy_backup/
nothing added to commit but untracked files present (use "git add" to track)

所以现在我想删除这两个未跟踪的文件,但令我惊讶的是一大堆其他文件也被删除了。

apache@cb772759c68a sugarcrm$ git clean -fd
Removing Disabled/upload:/
Removing LOG.txt
Removing custom/Extension/modules/Bugs/Ext/Language/
Removing custom/Extension/modules/Cases/Ext/Language/
Removing custom/Extension/modules/EmailAddresses/
Removing custom/Extension/modules/EmailParticipants/
Removing custom/Extension/modules/ForecastManagerWorksheets/
Removing custom/Extension/modules/ForecastWorksheets/
Removing custom/Extension/modules/Forecasts/
Removing custom/Extension/modules/Meetings/Ext/Layoutdefs/
Removing custom/Extension/modules/Meetings/Ext/WirelessLayoutdefs/
Removing custom/Extension/modules/Meetings/Ext/clients/
Removing custom/Extension/modules/ModuleBuilder/
Removing custom/Extension/modules/OutboundEmail/
Removing custom/Extension/modules/PdfManager/
Removing custom/Extension/modules/ProjectTask/Ext/Language/
Removing custom/Extension/modules/Quotas/
Removing custom/Extension/modules/Quotes/Ext/Dependencies/
Removing custom/Extension/modules/Targets/
Removing custom/Extension/modules/Tasks/Ext/Language/
Removing custom/Extension/modules/TimePeriods/
Removing custom/application/
Removing custom/install/
Removing custom/modules/Administration/
Removing custom/modules/Bugs/
Removing custom/modules/Cases/
Removing custom/modules/Contracts/
Removing custom/modules/Emails/
Removing custom/modules/HHP_Products/
Removing custom/modules/KBContents/
Removing custom/modules/Project/
Removing custom/modules/ProjectTask/
Removing custom/modules/ProspectLists/
Removing custom/modules/Prospects/
Removing custom/modules/Quotas/
Removing custom/modules/Reports/
Removing custom/modules/RevenueLineItems/
Removing custom/modules/Schedulers/
Removing custom/modules/Tags/
Removing custom/modules/Teams/
Removing custom/modules/hhp_assignment_zip/
Removing custom/modules/hhp_zipcode/
Removing custom/working/modules/Calls/
Removing custom/working/modules/Leads/clients/
Removing deploy_backup/
Removing deploy_log/
Removing dist/identity-provider/tests/docker/saml-test/config/simplesamlphp/config/
Removing vendor/sugarcrm/identity-provider/tests/docker/saml-test/config/simplesamlphp/config/

第一点 - 删除的文件在 git status 之后没有显示,所以很明显它们是 gitignore "mask" 的一部分......任何人都可以解释一下,这些文件中的任何一个如何匹配 gitignore? 中的任何模式?喜欢 vendor/sugarcrm/identity-provider/tests/docker/saml-test/config/simplesamlphp/config/ ...任何人都可以帮我建造一个支柱 gitignore?

第二点 - 我认为 .git忽略 "protects" 来自 git clean 的这些未版本控制的文件,git 字面上不会对它们采取任何操作。很明显它确实删除了它们......我怎么能在使用 git clean 时不删除未版本化的文件?

编辑:我把 git clean 和 git rm 混淆了,我一直在谈论 git clean

编辑 2:事实证明,与 .gitignore 不匹配的已删除目录毕竟是 "empty"。 (他们有子目录,但目录树没有任何文件...)

  1. .gitignore 忽略文件的添加和提交。它并不能保护它们不被清洗,恰恰相反。

  2. 那些清理过的文件与 .gitignore 相关的方式如下:

    custom/Extension/modules/Bugs/Ext/Language/ custom/Extension/modules/Cases/Ext/Language/

匹配 custom/modules/*/Ext 规则。

LOG.txt
vendor/sugarcrm/identity-provider/tests/docker/saml-test/config/simplesamlphp/config/

文件未添加到索引中,因此它们符合清理条件。

  1. 为避免清理未版本控制的文件,请不要 运行 git clean。手动删除不需要的文件。

TL;DR

您误解了 git clean 默认和 -d 删除的内容。 (注意:我自己并不是 git clean 的忠实粉丝;让它删除重要文件太容易了。)

作为 ,在 .gitignore 中列出一个文件,特别是 禁用 ,默认情况下,让 git clean 清除它。但是,git clean 比这(明显)复杂。我们稍后会详细介绍。

不过,首先让我们解决 .gitignore 条目的一个特点。如果您已经知道所有这些(但似乎没有人知道 :-) ),您可以跳到下面的 git clean 特定部分。

  1. tracked(现在在索引中)的文件永远不会被忽略,因此匹配 .gitignore 或等效文件(例如, .git/info/exclude) 模式无关。

    短语现在在索引中就是这个意思。当您使用 git addgit rm --cached 添加或删除文件时,会更改其跟踪性。您还可以使用 git ls-files --stage 导出索引中每个文件的完整列表及其暂存数据(模式、哈希和暂存槽编号),或者不使用 --stage 仅获取名称.

  2. 文件(不是目录)已被 Git 找到,现在不在索引中,是 未追踪。 Git 不存储目录,因此目录永远不会出现在索引中。1 跟踪或未跟踪纯粹是 属性 个文件。

  3. 未跟踪的文件也可以是被忽略的文件。如果是这样,git add 将不会添加它,即使您在命令行上明确命名它(尽管您都可以将其明确命名为 使用 --force 来添加它)。

    这意味着文件(但不是目录)属于以下三个类别之一:已跟踪、未跟踪(仅)或未跟踪并忽略。 这对 [=27 很重要=],它只抱怨未跟踪的文件(不是未跟踪和忽略的),但也在 git clean 的片刻。

  4. 最后,当 Git 进行完整的目录树搜索/扫描时——例如在 git add . 中——遇到一个它 的目录可能 能够跳过(其中没有跟踪文件),Git 将检查 目录本身 是否匹配 .gitignore 模式,并且如果是这样,不要往里面看。 这会加速此类目录上的 git statusgit add -A / git add .(有时速度非常快,如果您可以忽略例如整个供应商树或 SDK)。

规则 4 是为什么,如果你想 忽略某些目录路径下的特定文件路径,你必须指示 Git 特别不忽略目录。如果您忽略该目录,Git 可能永远不会查看该目录的内部。这尤其会影响这三行:

custom/Extenstion/application/Ext/Language
!custom/Extenstion/application/Ext/Language/cs_CZ.*
!custom/Extenstion/application/Ext/Language/en_US.*

如果您忽略了整个目录 custom/Extenstion/application/Ext/Language,Git 将不会查看其中,也永远不会找到任何匹配 custom/Extenstion/application/Ext/Language/cs_CZ.* 的文件来取消忽略它。因此有必要将目录本身排除在忽略状态之外:您应该将第一行更改为 custom/Extenstion/application/Ext/Language/*,以便 Git 必须查看目录内部。以 cs_CZ.*en_US.* 结尾的后续行将覆盖捷克语和美国英语文件的忽略状态。


1事实上,它们可以出现在索引中,但只是为了被视为特例。 git ls-files,可以显示索引内容,直接跳过。


使用 git clean -d 明确修改规则 4

Git 只能删除 的目录。这是一个通用的 OS 强制规则:如果目录 d 包含一些文件 d/f1d/f2 等,并且您要删除 d如果不先删除文件,您就会遇到文件问题。系统会强制您先删除目录中的文件。这也适用于子目录:如果 d/sub 存在,即使 d/sub 本身是一个空目录,您也不能删除 d只能删除空目录。

没有 -d

运行 git clean 不仅保留了规则 4,而且实际上 扩展了 它。例如,在我们开始的示例中,Git 注意到 (1) custom/Extenstion/application/Ext/Language 是一个目录; (2) 目录匹配忽略模式;所以 (3) 假设 custom/Extenstion/application/Ext/Language 中没有 文件 已经被跟踪 ,Git 可以并且将会跳过整个目录(当然不要删除它,因为 git clean 是 运行out -d)。

假设有另一个名为 xyzzy/ 的目录,其索引中没有列出任何文件。该目录可能完全是空的。在这种情况下,根据定义,其中没有未跟踪的文件;所以 git clean 没有 -d 不应该对它做任何事情。或者它可能有文件;这些文件根据定义是未跟踪的(因此可能是未跟踪和忽略的),但你说不要删除目录,所以 git clean still 甚至懒得看里面。这是一个有点奇怪的情况:Git 通常不会去查看未知目录。2(你在 git status 中也看到了这一点:你必须使用 git status -uall 在神秘目录中找到 文件 。但是 git add -A或者git add .要往里面看,除非目录被忽略,这也是规则4在一般情况下有点复杂的原因。)

但是,

运行 -d 显然完全抛弃了规则 4。同样,为了删除目录,Git 必须首先删除目录中的所有文件。为此,Git 还必须枚举内容。因此,如果您告诉 git clean 使用 -d,则完全禁用规则 4 似乎是合适的。路径名的目录性将强制 Git 扫描目录的内容。要么我们已经需要查看内部,因为有被跟踪的文件,要么我们需要查看内部以删除文件以删除目录。


2请注意,"unknown" 与 "untracked" 不同。它甚至不是 Git 术语;我在这里做了。但是,正如我们将看到的,如果 Git 确实 定义短语 "untracked directory".

可能会更好

git clean 删除的内容

运行 git clean -n 将向您展示它将删除的内容。此显示使用一些 shorthand:删除目录意味着删除该目录中的所有文件,包括(递归地)带有子文件的子目录。这比 运行 -f 而不是 -n 更安全,因为 -f 向您显示它删除的内容,与 -n 向您显示它将删除的内容相同。

默认情况下,git clean 删除未跟踪的文件,但不删除 未跟踪和忽略的文件。也就是回到上面的第3点,看文件的三个分类: git clean去掉中间的分类(只)。添加 -X(大写 X)告诉 Git:不要删除未跟踪的文件;相反,删除未跟踪和忽略的文件。

添加 -x 告诉 Git:不要阅读通常的忽略指令文件,例如 .gitignore。此时,no 个文件将被忽略,因此(无论跟踪了哪些文件)没有文件可以被跟踪和忽略。将它与 -X 结合使用是没有意义的,3 因此 git clean 禁止您同时使用 -x-X.

运行 git clean-d 添加空目录删除。不过,在这里,事情变得特别古怪。似乎 Git 的跟踪、未跟踪和未跟踪和忽略的分类有点崩溃。 The documentation 表示 -d 将:

Remove untracked directories in addition to untracked files.

但是Git 没有未跟踪目录 的定义。 "Tracked-ness" 完全是 个文件 的 属性 个。我们确实看到,在脚注中,目录作为不可见实体潜入索引(目的是加速各种 Git 操作),但这并不真正意味着目录被 跟踪.

我们可以编一个:"untracked directory" 可能是一个不包含任何跟踪文件的目录。我认为(但尚未证明令我满意)这个定义有效并解释了 git clean 的行为。不过,如果 Git 文档确实正确定义了这一点,那将大有帮助。


3-x-X-e 结合使用可能会有一些实际用途,但 Git 仍然禁止这样做,至少从今天开始。