如何从Mercurial / TortoiseHG的.hgignore文件中排除文件夹列表?

时间:2018-12-03 19:31:17

标签: regex mercurial tortoisehg

好的。我需要忽略版本控制中的文件列表,但三个特定文件夹中的文件除外(我们将其命名为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”文件夹中的所有文件和子文件夹。我该如何完成任务?

P.S。据我所知,Mercurial / TortoiseHG使用Python / Perl正则表达式。

非常感谢。

1 个答案:

答案 0 :(得分:1)

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

因此,我们需要一个正则表达式,该表达式(不使用锚定)将匹配要忽略的名称,而不匹配要保留的名称。 (此外,全局匹配不起作用,因为它不那么强大:我们要么匹配得太少,要么匹配得太多,Mercurial缺少Git的“重写功能,以后不再被忽略”。)

最短的正则表达式应为:

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

(此正则表达式中实际上与诸如/bin/somename/...之类的字符串匹配的部分只是/bin/部分,但Mercurial不会查看匹配的 ,只有是否匹配。)

问题是,您的示例正则表达式应该有效,它只是同一内容的较长变体,并且不需要但无害(性能除外).*然后回来。因此,如果您的计算机不起作用,则上述方法也可能不起作用。一个示例库,其中包含一些虚拟文件,可以克隆并进行试验,可以帮助诊断问题。


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

所需情况的最短正则表达式为:

/[Bb]in/Folder[123]/

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

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

说明

首先,请注意:默认语法为regexp,因此不需要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将使{{1 }},但不会添加a/b,因为它与模式匹配。因此,重要的是要知道文件是否已经被跟踪,并考虑您显式列出到c.ext的内容。例如,另请参见How to check which files are being ignored because of .hgignore?

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

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

  • Python / Perl regexp (?!...)语法是 negation 语法:(?!...)匹配,如果括号表达式与串。这是问题的一部分。

  • 我们无需担心捕获组(请参阅capturing group in regex),因为Mercurial对正则表达式中的组不做任何处理。它只在乎我们是否匹配。

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

在这种情况下,我们要匹配的名称(因此“忽略”)名称具有一个与binBin匹配的成分,紧随其后的是与{{1 }},Folder1Folder2,后跟一个组件分隔符(例如,我们没有停止 at Folder3,这是目录/bin/Folder1中名为Folder1文件

字符串/binbin都以Bin的结尾结尾,因此可以识别为in,但是更容易表示单字符交替作为字符类:(B|b)in,从而不需要括号和竖线。

名称[Bb]Folder1Folder2的用法相同,只是它们的公用字符串以前导而不是后缀开头,因此我们可以使用Folder3

假设我们锚定了比赛。也就是说,假设Mercurial要求我们匹配整个文件名,该文件名可能是Folder[123]然后我们需要/foo/hello/bin/Folder2/bar/world.ext,因为我们需要匹配任意数量的字符以在匹配.*/[Bb]in/Folder[123]/.*之前跳过/foo/hello,并再次跳过任何字符匹配/bin/Folder2/的字符数,以匹配整个字符串。但是,由于我们没有具有锚定匹配,因此我们将在整个字符串中找到模式bar/world.ext,因此可以使用更简单的模式(没有前导和尾随{{ 1}}。