Proposed Patch to hgignore

pistazienfresser at web.de pistazienfresser at web.de
Thu Mar 6 03:57:12 CST 2008


Hello.

I would like to propose an addition to the syntax of the .hgignore file, 
namely, the possibility to _not_ ignore files matching a wildcard or regular 
expression. 

This change is similar to the .gitignore semantics, and is very helpful for 
example to track changes to varios dotfiles.

one would use for example

syntax: glob
*
!^.bashrc
!^.emacs
!^.emacs.d/*
!^.muttrc

to only track .bashrc, .muttrc, .emacs and everything below .emacs.d

Implementing this behaviour with the current syntax might be possible but would
involve complicated regular expressions.

the appended patch applies to the current stable branch as well as to the 
development branch.

Thanks,
	Jakob Krainz

appended:
MD5 (hgignore-patch.hg-export.2.gz) = 747020454b237d8e0f9c54819cd4efb1
-------------- next part --------------
# HG changeset patch
# User pistazienfresser at web.de
# Date 1204410997 -3600
# Node ID 3032962e4897fce0e7b314c9a038b774c9eb95e5
# Parent  0068809347d72e552f980487ee669ace9a82d214
.hgignore syntax extension - now with re-inclusion

diff -r 0068809347d7 -r 3032962e4897 doc/hgignore.5.txt
--- a/doc/hgignore.5.txt	Fri Feb 29 14:48:21 2008 -0800
+++ b/doc/hgignore.5.txt	Sat Mar 01 23:36:37 2008 +0100
@@ -57,6 +57,10 @@ a regexp pattern of the form "\.c$" will
 a regexp pattern of the form "\.c$" will do the same.  To root a
 regexp pattern, start it with "^".
 
+If a file matches a pattern prefixed with "!", it will not be ignored,
+regardless of the other patterns it might match. This can be used to 
+make exceptions to broad patterns.
+
 EXAMPLE
 -------
 
@@ -69,10 +73,12 @@ Here is an example ignore file.
   *.pyc
   *~
   .*.swp
+  !dontignoreme.pyc
 
   # switch to regexp syntax.
   syntax: regexp
   ^\.pc/
+  !^\.pc/important
 
 AUTHOR
 ------
diff -r 0068809347d7 -r 3032962e4897 mercurial/ignore.py
--- a/mercurial/ignore.py	Fri Feb 29 14:48:21 2008 -0800
+++ b/mercurial/ignore.py	Sat Mar 01 23:36:37 2008 +0100
@@ -46,9 +46,11 @@ def ignore(root, files, warn):
 
     syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
     pats = {}
+    patneg = {}
     for f in files:
         try:
             pats[f] = []
+            patneg[f] = []
             fp = open(f)
             syntax = 'relre:'
             for line in _parselines(fp):
@@ -59,6 +61,11 @@ def ignore(root, files, warn):
                     except KeyError:
                         warn(_("%s: ignoring invalid syntax '%s'\n") % (f, s))
                     continue
+                if line.startswith('!'):
+                    negate = True
+                    line = line[1:]
+                else:
+                    negate = False
                 pat = syntax + line
                 for s, rels in syntaxes.items():
                     if line.startswith(rels):
@@ -68,6 +75,7 @@ def ignore(root, files, warn):
                         pat = rels + line[len(s)+1:]
                         break
                 pats[f].append(pat)
+                patneg[f].append(negate)
         except IOError, inst:
             if f != files[0]:
                 warn(_("skipping unreadable ignore file '%s': %s\n") %
@@ -75,12 +83,23 @@ def ignore(root, files, warn):
 
     allpats = []
     [allpats.extend(patlist) for patlist in pats.values()]
+    allpatnegate = []
+    [allpatnegate.extend(neglist) for neglist in patneg.values()]
     if not allpats:
         return util.never
 
+    pinc = []
+    pexc = []
+    
+    for i in xrange(len(allpats)):
+        if(allpatnegate[i]):
+            pexc.append(allpats[i])
+        else:
+            pinc.append(allpats[i])
+
     try:
         files, ignorefunc, anypats = (
-            util.matcher(root, inc=allpats, src='.hgignore'))
+            util.matcher(root, inc=pinc, exc=pexc, src='.hgignore'))
     except util.Abort:
         # Re-raise an exception where the src is the right file
         for f, patlist in pats.items():
diff -r 0068809347d7 -r 3032962e4897 tests/test-hgignore
--- a/tests/test-hgignore	Fri Feb 29 14:48:21 2008 -0800
+++ b/tests/test-hgignore	Sat Mar 01 23:36:37 2008 +0100
@@ -27,6 +27,7 @@ touch dir/a.o
 touch dir/a.o
 touch dir/b.o
 touch dir/c.o
+touch '!bang'
 
 hg add dir/a.o
 hg commit -m 0
@@ -39,6 +40,28 @@ echo "--" ; hg status 2>&1 | sed -e 's/a
 
 echo ".*\.o" > .hgignore
 echo "--" ; hg status
+
+echo ".*\.o" > .hgignore
+echo "!a\.o" >> .hgignore
+echo "--" ; hg status
+
+echo '--'
+echo separator one
+
+echo ".*\.o" > .hgignore
+echo "!bang" >> .hgignore
+echo "--" ; hg status
+
+echo ".*\.o" > .hgignore
+echo "\!bang" >> .hgignore
+echo "--" ; hg status
+
+echo ".*a.*" > .hgignore
+echo "!\!bang" >> .hgignore
+echo "--" ; hg status
+
+echo '--'
+echo separator two
 
 echo "glob:**.o" > .hgignore
 echo "--" ; hg status
diff -r 0068809347d7 -r 3032962e4897 tests/test-hgignore.out
--- a/tests/test-hgignore.out	Fri Feb 29 14:48:21 2008 -0800
+++ b/tests/test-hgignore.out	Sat Mar 01 23:36:37 2008 +0100
@@ -2,6 +2,7 @@
 ? baz
 --
 A dir/b.o
+? !bang
 ? a.c
 ? a.o
 ? dir/c.o
@@ -10,6 +11,22 @@ abort: .hgignore: invalid pattern (relre
 abort: .hgignore: invalid pattern (relre): *.o
 --
 A dir/b.o
+? !bang
+? .hgignore
+? a.c
+? syntax
+--
+A dir/b.o
+? !bang
+? .hgignore
+? a.c
+? a.o
+? syntax
+--
+separator one
+--
+A dir/b.o
+? !bang
 ? .hgignore
 ? a.c
 ? syntax
@@ -20,17 +37,33 @@ A dir/b.o
 ? syntax
 --
 A dir/b.o
+? !bang
+? .hgignore
+? dir/c.o
+--
+separator two
+--
+A dir/b.o
+? !bang
 ? .hgignore
 ? a.c
 ? syntax
 --
 A dir/b.o
+? !bang
+? .hgignore
+? a.c
+? syntax
+--
+A dir/b.o
+? !bang
 ? .hgignore
 ? a.c
 ? syntax
 --
 .hgignore: ignoring invalid syntax 'invalid'
 A dir/b.o
+? !bang
 ? .hgignore
 ? a.c
 ? a.o
@@ -38,11 +71,13 @@ A dir/b.o
 ? syntax
 --
 A dir/b.o
+? !bang
 ? .hgignore
 ? a.c
 ? syntax
 --
 A dir/b.o
+? !bang
 ? .hgignore
 ? a.c
 ? a.o


More information about the Mercurial-devel mailing list