【问题标题】:How to emulate language complement operator in .hgignore?如何在 .hgignore 中模拟语言补码运算符?
【发布时间】:2009-07-03 13:22:55
【问题描述】:

我有一个匹配一组文件名的 Python 正则表达式。如何更改它以便我可以在 Mercurial 的 .hgignore 文件中使用它来忽略 匹配表达式的文件?

全文: 我有一个很大的源代码树,其中散布着*.ml 文件。我想把它们放到一个新的存储库中。还有其他不太重要的文件太重而无法包含在存储库中。我正在尝试查找.hgignore 文件的对应表达式。

第一个观察:Python 没有常规语言补码运算符(AFAIK 它只能补码一组字符)。 (顺便说一句,为什么?)

第二次观察: Python 中的以下正则表达式:

re.compile("^.*(?<!\.ml)$")

按预期工作:

abcabc - match  
abc.ml - no match  
x/abcabc - match  
x/abc.ml - no match

但是,当我在 .hgignore 文件中放入完全相同的表达式时,我得到了:

$ hg st --all  
?  abc.ml  
I .hgignore  
I abcabc  
I x/xabc  
I x/xabc.ml  

根据.hgignore 手册页,Mercurial 只使用普通的 Python 正则表达式。那我怎么会得到不同的结果呢? Mercurial 怎么可能找到x/xabc.ml 的匹配项?

有没有人知道缺少常规语言补码运算符的丑陋方法?

【问题讨论】:

标签: python regex mercurial


【解决方案1】:

正则表达式依次应用于每个子目录组件以及文件名,而不是同时应用于整个相对路径。因此,如果我的仓库中有 a/b/c/d,则每个正则表达式都将应用于 a、a/b、a/b/c 以及 a/b/c/d。如果任何组件匹配,该文件将被忽略。 (您可以通过尝试^bar$ 与 bar/foo 来判断这是这种行为 - 您会看到 bar/foo 被忽略。)

^.*(?&lt;!\.ml)$ 忽略 x/xabc.ml,因为该模式匹配 x(即子目录)。

这意味着没有正则表达式可以帮助您,因为您的模式必须匹配第一个子目录组件。

【讨论】:

  • 但在我上面的回答中,“x/abcabc”和“x/abc.ml”的处理方式不同:第一个匹配(正确),而第二个不匹配(也正确)。
  • 您将忽略函数应用于整个相对路径而不是子路径。如果您正在查看源代码,请查看 mercurial/dirstate.py 中的 _dirignore。我很确定这就是这种行为的来源。
  • 啊,我还以为它匹配的是整个相对路径。那个人 hgignore 说确实如此,但在重读时它指定了其他内容。
  • 现在我明白了。在顶层目录“x”、“y”等被忽略,因为它们匹配正则表达式,所以我们从不递归到它们。我们真正想要的是“从不忽略目录,只忽略文件”的逻辑,即使它们与忽略正则表达式匹配。当然,您通常不希望出现这种行为,仅在这种情况下。
  • 我的测试和 dirstate.py 中的 _dirignore 表明对于 repo 中的 a/b/c/d,尝试了以下字符串:a、a/b、a/b/c、a/ b/c/d(但不是 'd' 本身!)。尝试 ^zz$ 对 'zz/a' 和 'a/zz'。很遗憾,手册页没有解释这一点。
【解决方案2】:

问题似乎特别是子目录中的匹配项与根目录不同。请注意以下几点:

$ hg --version
Mercurial Distributed SCM (version 1.1.2)

这是一个旧版本,但它的行为方式相同。我的项目有以下文件:

$ find . -name 'abc*' -print
./x/abcabc
./x/abc.ml
./abcabc
./abc.ml

这是我的 .hgignore:

$ cat .hgignore
^.*(?<!\.ml)$

现在,当我运行 stat:

$ hg stat
? abc.ml

所以,hg 未能接听x/abc.ml。但这真的是正则表达式的问题吗?也许不是:

$ python
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import mercurial.ignore
>>> import os
>>> root = os.getcwd()
>>> ignorefunc = mercurial.ignore.ignore(root, ['.hgignore'], lambda msg: None)
>>> 
>>> ignorefunc("abc.ml") # No match - this is correct
>>> ignorefunc("abcabc") # Match - this is correct, we want to ignore this
<_sre.SRE_Match object at 0xb7c765d0>
>>> ignorefunc("abcabc").span() 
(0, 6)
>>> ignorefunc("x/abcabc").span() # Match - this is correct, we want to ignore this
(0, 8)
>>> ignorefunc("x/abc.ml") # No match - this is correct!
>>> 

请注意,ignorefunc 对待 abcabcx/abcabc 相同(匹配 - 即忽略),而 abc.mlx/abc.ml 也同样对待(不匹配 - 即不忽略)。

所以,也许逻辑错误出现在 Mercurial 的其他地方,或者我正在查看 Mercurial 的错误位(尽管如果是这种情况我会感到惊讶)。除非我遗漏了什么,否则可能需要针对 Mercurial 提交错误(而不是 Martin Geisler 指出的 RFE)。

【讨论】:

  • 如果您回复我的第一个答案,当我从 ^re/.+ 更改为 ^.+ (如问题所示)时,我能够重现该问题。 (所以我删除了那个答案。)显然这与指定的目录有关,这导致了我目前的建议。我没有查看 hg 的来源,但是,根据这个外部测试,问题确实存在于某个地方。
  • 呃 - 是的,我在评论您的第一个(现已删除)答案。无论如何,我的测试似乎没有指出正则表达式是问题的根源。
【解决方案3】:

通过一些测试,找到了两个似乎可行的解决方案。第一个根到子目录,显然这很重要。第二个是易碎的,因为它只允许使用一个后缀。我正在使用 Mercurial 1.2.1 在 Windows XP(定制为更加统一)上运行这些测试。

(我用# message添加的评论。)

$ hg --版本 Mercurial 分布式 SCM(版本 1.2.1) $猫.hgignore 语法:正则表达式 ^x/.+(?

第二个:

$猫.hgignore 语法:正则表达式 #^x/.+(?

据我了解,第二个具有完全预期的行为。第一个仅在子目录中具有预期行为,但更灵活。

【讨论】:

  • 不幸的是,如果我在 .hgignore 中尝试您的模式,我会得到以下显示为“?”:.hgignore(不应该存在),abc.ml(应该存在),abcabc(不应该),x/abc.ml(应该),y/abc.ml(应该),y/abcabc(不应该)。使用 OP 的正则表达式,它会正确忽略所有内容,但也会错误地忽略 x/abc.ml 和 y/abc.ml。所以我不确定这是一种解决方法。
  • 哪种模式?植根于子目录(第一个)的那个自然不会影响不在该子目录中的文件。除了一个警告之外,它可以正常工作,而第二个警告在所有情况下也都可以正常工作。我现在会更新我的帖子。
  • 我的意思是第一个,因为它没有被注释掉。但是,不幸的是,对于
  • 它易碎的另一个原因。 :) 感谢您发现额外的错误。
  • 第一个解决方案需要在.hgignore 中指定所有目录。这归结为使用手工工具来爬取源树(然后我们可以显式选择每个文件并且不需要 .hgignore)。第二个正则表达式导致一个名为例如的文件'耻辱'被包括在内(不匹配)。这太不准确了。
猜你喜欢
  • 2023-01-08
  • 2021-01-25
  • 1970-01-01
  • 1970-01-01
  • 2010-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-01
相关资源
最近更新 更多