【问题标题】:How to exclude list of folders from Mercurial/TortoiseHG's .hgignore file?如何从 Mercurial/TortoiseHG 的 .hgignore 文件中排除文件夹列表?
【发布时间】:2019-05-05 03:38:44
【问题描述】:

好的。我需要忽略版本控制中的文件列表,除了三个特定文件夹中的文件(我们称它们为 Folder1、Folder2 和 Folder3)。我可以将我需要忽略的所有文件夹作为普通列表列出,但我认为这不是一种优雅的方式,所以我编写了以下正则表达式:

.*/(Bin|bin)/(?!Folder1/|Folder2/|Folder3/).*

我的想法是这样的,从左到右:

  • .* - 任意数量的任意字符。
  • / - 斜线符号,用于分隔文件夹。
  • (Bin|bin) - 名称为“Bin”或“bin”的文件夹。
  • / - 斜线符号,用于分隔文件夹。
  • (?!Folder1/|Folder2/|Folder3/) - 文件夹名称不是“Folder1/”,也不是“Folder2/”,也不是“Folder3/”。这部分是最复杂的,但我以某种方式搜索了它。我不明白为什么它应该起作用,但它在测试期间起作用。
  • .* - 任意数量的任意字符。

当我在 regex101.com 使用几个文本字符串(代表文件的路径)对其进行测试时,这个表达式可以完美运行,但是当我将它放在我的 .hgignore 文件中时,它没有任何效果,如下所示:

syntax: regexp
.*/(Bin|bin)/(?!Folder1/|Folder2/|Folder3/).*

由于某种原因,它会忽略所有“Bin”和“bin”文件夹中的所有文件和子文件夹。我怎样才能完成我的任务?

附:据我所知,Mercurial/TortoiseHG 使用 Python/Perl 正则表达式。

非常感谢。

【问题讨论】:

  • 您说 nothing 有效,但您说它忽略了 bin 中的文件/子文件夹。它是什么 ?可能是忽略正则表达式应该是积极的而不是消极的。试试改成(?:fold1|2|3)
  • 正确的话应该是“它不能按需要工作”。如果我将正则表达式更改为正则,文件夹 1、2 和 3 将匹配正则表达式。我需要它来匹配除这些文件夹中的文件之外的所有文件夹和文件。 “.hgignore”文件被控制版本系统用来列出没有被版本控制的文件,即被 Mercurial 忽略的文件。我希望忽略所有 Bin 和 bin 文件夹(文件夹 1-3 除外)中的所有文件,因此它们应该与正则表达式匹配。不应忽略文件夹 1-3 中的文件,因此不应与正则表达式匹配。
  • 有些不对劲。如果正则表达式匹配,文件 被处理?不然不会?如果是 Python,试试这个正则表达式 ^(?:(?!(?:Bin|bin)/(?:Folder1|Folder2|Folder3)/).)*$,它将否定扩展到它应该在的 bin 文件夹。否则它将匹配所有个其他文件夹。
  • 哎呀。 Mercurial 是版本控制系统,对吧?默认情况下,它会跟踪您放在存储库文件夹中的所有文件/文件夹的更改,对吗?有时不需要 Mercurial 来跟踪某些文件和文件夹(因为这些文件对于所有存储库用户来说都是不同的)。有时你可能有很多这样的文件(我的例子)。 Mercurial 有一个名为“.hgignore”的专用文件,您可以在其中使用正则表达式来选择您希望 Mercurial 不跟踪(即忽略)的所有文件。因此,如果文件与正则表达式匹配 - Mercurial 会忽略它。如果文件与正则表达式不匹配,Mercurial 不会忽略它。
  • 我希望 Mercurial 忽略所有 Bin 和 bin 文件夹中的所有文件,除了“.../Bin/Folder1/...”、“.../Bin/Folder2/...”和“.../Bin/Folder3/...”。您建议的正则表达式都没有完成这项工作。 ^ 和 & 也不适用,因为 Bin 和 bin 文件夹可以位于文件夹/文件层次结构中的任何位置。

标签: regex mercurial tortoisehg


【解决方案1】:

为了稍微调整一下问题以使其更清楚(至少对我而言),我们有任意数量的 /bin/somename/....../bin/anothername/... 名称​​应该被忽略,以及三组.../bin/folder1/....../bin/2folder/....../Bin/third/...被忽略的名称集。

因此,我们需要一个正则表达式(没有锚定)将匹配要忽略的名称,但不匹配要保留的名称。 (此外,glob 匹配不起作用,因为它没有那么强大:我们要么匹配得太少,要么匹配太多,而且 Mercurial 缺少 Git 的“用以后不忽略的覆盖”特性。)

最短的正则表达式应该是:

/[Bb]in/(?!(folder1|2folder|third)/)

(这个正则表达式中真正匹配/bin/somename/...这样的字符串的部分只是/bin/部分,但是Mercurial不看什么匹配,只看是否 匹配的东西。)

问题是,您的示例正则表达式应该可以工作,它只是同一事物的更长变体,在前面和后面添加了不需要但无害(性能除外).* .因此,如果您的不起作用,则上述方法也可能不起作用。一个示例存储库,其中包含一些可以克隆和试验的虚拟文件,将有助于诊断问题。


原始(错误)答案(针对不是问题的问题)

所需案例的最短正则表达式是:

/[Bb]in/Folder[123]/

但是,如果目录/文件夹名称实际上不符合这种模式,我们需要:

/[Bb]in/(somedir|another|third)/

说明

首先,附注:默认语法是正则表达式,因此最初的syntax: regexp 行是不必要的。因此,您的 .hgignore 文件可能不是正确的 UTF-8 格式:请参阅 Mercurial gives "invalid pattern" error for simple GLOB syntax。 (但这会产生不同的行为,所以这可能是一个问题。在任何关于 .hgignore 文件故障的答案中都值得一提。)

接下来,有几点值得注意:

  • Mercurial 仅跟踪文件,而不跟踪目录/文件夹。所以真正的问题是任何给定的文件名是否与.hgignore 中列出的模式匹配。如果它们确实匹配,并且该文件当前未跟踪,文件将不会通过彻底的“添加所有内容”操作自动添加,Mercurial 不会抱怨该文件未跟踪。

  • 如果某个文件已被跟踪,则其名称与忽略模式匹配的事实无关紧要。如果文件a/b/c.ext 未被跟踪并且确实 匹配一个模式,hg add a/b/c.ext 无论如何都会添加它,而hg add a/b 将在a/b 中集体添加所有内容但赢了t 添加c.ext,因为它与模式匹配。因此,重要的是要知道该文件是否已被跟踪,并考虑您明确列出到hg add 的内容。例如,另请参阅How to check which files are being ignored because of .hgignore?

  • 全局模式比正则表达式更容易正确编写。除非您出于学习或教学目的这样做,或者 glob 不够强大,否则请坚持使用 glob 模式。 (在非常旧的 Mercurial 版本中,glob 匹配明显比 regexp 匹配慢,但这个问题已经修复了很长时间。)

  • Mercurial 的正则表达式忽略条目不会自动锚定:如果您想要锚定行为,请根据需要在前面使用 ^,在末尾使用 $。在这里,您想要锚定行为,因此您可以消除前导和尾随.*。 (Mercurial 将此称为 rooted 而不是 anchored,重要的是要注意某些模式 是锚定的,但 .hgignore 不是.)

  • Python/Perl 正则表达式(?!...) 语法是否定 语法:(?!...) 匹配如果括号表达式 匹配字符串。这是问题的一部分。

  • 我们不必担心捕获组(请参阅capturing group in regex),因为 Mercurial 对来自正则表达式的组不做任何事情。它只关心我们是否匹配。

  • 路径名实际上是斜线分隔的组件。前导组件是文件名上方的各个目录(文件夹),最后一个组件是文件名。 (也就是说,尽量不要将第一部分视为文件夹:这不是错,而是它不如“组件”通用,因为最后一部分也是一个组件。)

在这种情况下,我们想要匹配并因此“忽略”具有一个与binBin 匹配的组件的名称,其后紧跟与Folder1Folder2 匹配的另一个组件, 或 Folder3 后跟一个组件分隔符(这样我们就没有停止 /bin/Folder1,例如,这是一个名为@987654357 的文件 @在目录/bin)。

字符串binBin 都以in 的公共尾随部分结尾,因此可以识别为(B|b)in,但单字符交替更容易表示为字符类:[Bb] ,这样就不需要括号和竖线了。

名称Folder1Folder2Folder3 也是如此,只是它们的共同字符串是前导而不是尾随,因此我们可以使用Folder[123]

假设我们有锚定匹配。也就是说,假设 Mercurial 要求我们匹配 整个 文件名,例如,/foo/hello/bin/Folder2/bar/world.ext那么我们需要.*/[Bb]in/Folder[123]/.*,因为我们需要匹配任意数量的字符以在匹配/foo/hello 之前跳过/bin/Folder2/,并再次跳过任意数量的字符以匹配@ 987654372@,为了匹配整个字符串。但由于我们没有锚定匹配,我们将在整个字符串中找到模式/bin/Folder2/,因此忽略此文件,使用没有前导和尾随.* 的更简单模式。

【讨论】:

  • 我知道大部分这些概念。回答两个不确定的问题:1) 是的,这些文件夹的名称比文件夹[1-3] 更复杂。所以第一个例子不是一个选项。 2)我的“.hgignore”文件使用了许多其他条件,我在那里同时使用了 glob 和正则表达式。我没有找到用 glob 完成任务的方法,所以我改用正则表达式。
  • 我不明白为什么每个人都误解了我的目标。我在原始帖子中声明,正则表达式应包含所有[Bb]in 文件夹中的所有文件,[Bb]in/somedir 除外,[Bb]in/anotherDir 除外,[Bb]in/third 除外。您提供的第二个示例与我需要的完全相反。它只匹配这三个文件夹,我需要它来匹配除这三个文件夹之外的所有文件夹。这就是我尝试使用否定参数的原因。
  • 啊哈。在这样的复杂问题中,提供一些所需行为的样本有助于避免这种混淆。是的,你需要底片。将修复答案...
  • 由于某种原因,您的新示例也不起作用。你是对的,我会尝试为每个人准备一个存储库,以便能够在那里测试表达式。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
  • 2011-01-11
相关资源
最近更新 更多