hgignore: help ignoring all files but certain ones
Asked Answered
C

3

43

I need an .hgdontignore file :-) to include certain files and exclude everything else in a directory. Basically I want to include only the .jar files in a particular directory and nothing else. How can I do this? I'm not that skilled in regular expression syntax. Or can I do it with glob syntax? (I prefer that for readability)

Just as an example location, let's say I want to exclude all files under foo/bar/ except for foo/bar/*.jar.

Cenesthesia answered 2/10, 2009 at 22:15 Comment(0)
S
38

To do this, you'll need to use this regular expression:

foo/bar/.+?\.(?!jar).+

Explanation

You are telling it what to ignore, so this expression is searching for things you don't want.

  1. You look for any file whose name (including relative directory) includes (foo/bar/)
  2. You then look for any characters that precede a period ( .+?\. == match one or more characters of any time until you reach the period character)
  3. You then make sure it doesn't have the "jar" ending (?!jar) (This is called a negative look ahead
  4. Finally you grab the ending it does have (.+)

Regular expressions are easy to mess up, so I strongly suggest that you get a tool like Regex Buddy to help you build them. It will break down a regex into plain English which really helps.

EDIT

Hey Jason S, you caught me, it does miss those files.

This corrected regex will work for every example you listed:

foo/bar/(?!.*\.jar$).+

It finds:

  • foo/bar/baz.txt
  • foo/bar/baz
  • foo/bar/jar
  • foo/bar/baz.jar.txt
  • foo/bar/baz.jar.
  • foo/bar/baz.
  • foo/bar/baz.txt.

But does not find

  • foo/bar/baz.jar

New Explanation

This says look for files in "foo/bar/" , then do not match if there are zero or more characters followed by ".jar" and then no more characters ($ means end of the line), then, if that isn't the case, match any following characters.

Salamone answered 2/10, 2009 at 22:27 Comment(4)
hmm, good idea, but it won't work as stated, since it won't match files without any extension at all. But I think I can morph it into what I need. The foo/bar/ part is easy so let's forget about that for the moment. If you can fix it so it matches the files "baz.txt", "baz", "jar", "baz.jar.txt", "baz.jar.", "baz.", and "baz.txt." but NOT "baz.jar" then I'll accept. :-)Cenesthesia
Hey Jason, I see what you mean. I just updated my answer with a working regex. I tested it against every string you listed.Salamone
This solution works very well for me, but I just wanted to add that the .hgignore file should have syntax: regexp before using it. You can revert to syntax: glob later in the file.Teodorateodorico
You can also use re:foo/bar/(?!.*\.jar$).+ just for that line.Burcham
S
42

The answer from Michael is a fine one, but another option is to just exclude:

foo/bar/**

and then manually add the .jar files. You can always add files that are excluded by an ignore rule and it overrides the ignore. You just have to remember to add any jars you create in the future.

Sargent answered 4/10, 2009 at 4:21 Comment(5)
How you do you manually add those? Adding them with "hg add" fails, as the ignore file will be used. Adding them with "hg add -I" fails, as still the ignore file applies. So how can they be added overriding the ignore file?Aronarondel
Mecki, adding them with 'hg add' works fine -- it overrides the ignore -- provided that you don't use wildcards in your add line. So put foo/bar/** in your .hgignore and then do 'hg add foo/bar/path/specific.file' and you're good to go. If you have a ton of exceptions to add you can pipe 'hg status -u -n foo/bar/lots-*.jar ' to 'xargs hg add' and do your explicit overrides in bulk.Sargent
and if somebody will modify foo/bar/path/specific.file , it still will be ignored? it's not a solution mateWitkowski
no, once it's added it's tracked, so if someone modified foo/bar/path/specific.file that has been added it will be detected as changed. Adding completely overrides ignores.Sargent
In case it's not clear, 'hg add' without an argument won't work for files that match .hgignore patterns. 'hg add <filename>' will add the file and as Ry4an mentions, it then will be treated as a normal repository file because .hgignore only affects adds.Mauceri
S
38

To do this, you'll need to use this regular expression:

foo/bar/.+?\.(?!jar).+

Explanation

You are telling it what to ignore, so this expression is searching for things you don't want.

  1. You look for any file whose name (including relative directory) includes (foo/bar/)
  2. You then look for any characters that precede a period ( .+?\. == match one or more characters of any time until you reach the period character)
  3. You then make sure it doesn't have the "jar" ending (?!jar) (This is called a negative look ahead
  4. Finally you grab the ending it does have (.+)

Regular expressions are easy to mess up, so I strongly suggest that you get a tool like Regex Buddy to help you build them. It will break down a regex into plain English which really helps.

EDIT

Hey Jason S, you caught me, it does miss those files.

This corrected regex will work for every example you listed:

foo/bar/(?!.*\.jar$).+

It finds:

  • foo/bar/baz.txt
  • foo/bar/baz
  • foo/bar/jar
  • foo/bar/baz.jar.txt
  • foo/bar/baz.jar.
  • foo/bar/baz.
  • foo/bar/baz.txt.

But does not find

  • foo/bar/baz.jar

New Explanation

This says look for files in "foo/bar/" , then do not match if there are zero or more characters followed by ".jar" and then no more characters ($ means end of the line), then, if that isn't the case, match any following characters.

Salamone answered 2/10, 2009 at 22:27 Comment(4)
hmm, good idea, but it won't work as stated, since it won't match files without any extension at all. But I think I can morph it into what I need. The foo/bar/ part is easy so let's forget about that for the moment. If you can fix it so it matches the files "baz.txt", "baz", "jar", "baz.jar.txt", "baz.jar.", "baz.", and "baz.txt." but NOT "baz.jar" then I'll accept. :-)Cenesthesia
Hey Jason, I see what you mean. I just updated my answer with a working regex. I tested it against every string you listed.Salamone
This solution works very well for me, but I just wanted to add that the .hgignore file should have syntax: regexp before using it. You can revert to syntax: glob later in the file.Teodorateodorico
You can also use re:foo/bar/(?!.*\.jar$).+ just for that line.Burcham
S
1

Anyone that wants to use negative lookaheads (or ?! in regex syntax) or any kind of back-referencing mechanism should be aware that Mercurial will fall back from google's RE2 to Python's re module for matching.

RE2 is a non-backtracking engine that guarantees a run-time linear with the size of the input. If performance is important to you, that is if you have a big repository, you should consider sticking to more simple patterns that Re2 supports, which is why I think that the solution offered by Ryan.

Selfreliant answered 10/1, 2020 at 9:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.