.gitignore un-ignore equivalent in .hgignore - mercurial

In the .gitignore syntax there is an option where you can have a ! at the beginning of the file and it will un-ignore any previously ignored files.
So I can have the following:
logs/*
!logs/stuff.txt
And logs/stuff.txt will still be tracked.
What is the Mercurial .hgignore equivalent for this?

The equivalent is just adding the file. Once a file has been hg added the .hgignore file has absolutely no effect on how it's treated, so you ignore logs/* (be sure you're in glob mode, not regex mode) and then hg add logs/stuff.txt.

Using regexp syntax you can write both rules in one:
syntax: regexp
logs\/(?!stuff.txt$)

Related

.hgignore regex syntax to ignore a specific file (e.g. "core") anywhere

Suppose I have a working directory like this:
t.c
core
multicore
test1/core
I want to ignore all "core" files.
If I use "/core$" (4) will get ignored but not (2).
If I use "^core$" (2) will get ignored but not (4)
If I use "core$" (2) and (4) will get ignored but so will (3) which is not what I want.
How do you do this?
planetmaker's answer, "use glob syntax", is simpler and is what I would usually recommend. There is, however, a regexp answer, and a minor flaw in the glob syntax version.
Mercurial uses Python regular expressions, so we have the (alt1|alt2|...) syntax available. Note that these are grouped.1 We can and should use (?:...) to avoid grouping when required, but for .hgignore, the grouping is irrelevant, so it is simpler (and much more readable) to just use the parentheses, and I do so where possible below.
We could just write:
^core$
/core$
to ignore the file core with nothing coming before it (first pattern) and to ignore a file with a name like test1/core (second pattern). This is a fine, but we can compress it a bit more using the alternation syntax. The leading ^ works even in an alternate within a group, as long as it is still, in effect, leading, so:
(^|/)core$
means the same thing and accomplish the job using regexp syntax.
Annoyingly, all of these patterns ignore all files in any directory named core (whether or not we use regexp vs glob syntax):
$ rm core
$ mkdir core
$ touch core/keepme
$ cat .hgignore
syntax: glob
core
$ hg status -A
? .hgignore
? multicore
? t.c
I core/keepme
I test1/core
The problem is that as soon as we say ignore (some pattern that matches a directory named core), if there are files in that directory that are currently untracked, Mercurial ignores them too. You can forcibly add the file—as with Git, once a file is tracked, any ignore-file pattern that matches it becomes irrelevant—but this does not help with additional files we stick into the directory:
$ hg add core/keepme
$ touch core/keep-me-too
$ hg status -A
A core/keepme
? .hgignore
? multicore
? t.c
I core/keep-me-too
I test1/core
Here, regular expressions can prove to be the answer. Python (and Perl) regexps allow "negative lookbehind", i.e., you can say "as long as some pattern does not appear". Hence we can replace the existing .hgignore contents with:
$ cat .hgignore
(?<!^core/).*/core$
and now we have this status:
$ hg status -A
A core/keepme
? .hgignore
? core/keep-me-too
? multicore
? t.c
I test1/core
This particular regular expression depends on the wanted core directory being named core at the top level (^core). If we wanted to keep core directories named core (top level) and a/subsys/core, we would write:
(?<!(^core|^a/subsys/core)/).*/core$
as our regular expression.
Constructing these regexps is something of an art form, and rarely worth a lot of effort. Glob syntax is almost always simpler, and as long as it suffices, I prefer it. It was once significantly slower than regexp syntax but this was fixed back around Mercurial 3.1.
1Grouped, here, means that in Python code, we may use the .groups() method to obtain the parts of the string matched by these parts of the regular expressions. Non-grouped (?:...) expressions do not affect the way .groups() gathers the parts of the strings. As in the paragraph to which this is a footnote, this is more a concern when writing Python (or Perl, or whatever) code, not when using these patterns in .hgignore or other parts of Mercurial.
Try to give the filename using glob syntax:
syntax: glob
core
It gives:
~/hg-test$ hg st -A
M .hgignore
? multicore
I core
I dir1/core

Ignoring the same filename in root and subdirectories

In a Mac project, there are .DS_Store files at multiple levels, like so:
project/.DS_Store
project/subdir/.DS_Store
project/subdir/other_file.txt
project/.hgignore
When I use the following for a .hgignore file, the top-level .DS_Store doesn't get ignored. Is there any way to ignore both .DS_Store files with a single glob line in the .hgignore file? It seems like this should be easy, and adding another .DS_Store line feels clumsy.
syntax: glob
**/.DS_Store
The following works, but I prefer the readability of the glob syntax for ignore files:
syntax: regexp
.*\.DS_Store
Use the glob expression, but don't limit it to being inside a folder, like this:
syntax:glob
.DS_Store
That will match any file with the exact name of .DS_Store anywhere in the repo.

mercurial and ignore pattern

I'm trying to get mercurial to ignore diffs. I performed the following according to Mercurial ignore file:
$ echo "*.diff" >> .hgignore
Status now give me an error (I added the '...' for readability):
$ hg status
abort: .../.hgignore: invalid pattern (relre): *.diff
Searching the web for the error message returned a few non-relevant results. Any ideas on how to ignore diff files?
Write first:
syntax: glob
Fully .hgignore
syntax: glob
*.diff
The default regex. You can write all the regular expression, then switch to syntax glob. Example:
\.pyc$
test\.py$
syntax: glob
*.diff
If you want to exclude all but a few, it is better to use a regular expression.

Mercurial ignore all files except specific file names

I have a large file system in which almost every folder has a file called content.txt
I want to track every file named content.txt and automatically ignore everything else. I want the repo to automatically track new files named content.txt so I don't want to ignore everything in the .hgignore and then manually add.
Anyone know how to do this?
It has to be regexp mode, not glob
You must debug path-part of regexp, but "all except content.txt" draft is re:.*\.(?!content.txt) as hope
Alternative solution can be
* ignore all
* add content.txt files pattern to commit command (-I option), see hg help commit and hg help patterns
hg commit -I '**content.txt'
Edit
re:.*/(?!content.txt)
Try this:
syntax: regexp
\.(?!txt$)[^.]+$ # "*." is followed by "txt" and we're at the end
(?<!\.)txt$ # "txt" follows a "."
(?<!/)content\. # "content." follows path separator
(?<!content)\. # "." follows "content"
I left in the comments I made while experimenting, to make sense of it all. (That's glob syntax in the first one.)

Hgignore everything except, regardless of directory

I've seen the posts for hgignore everything except, but I can't seem to transform the regex to work with subdirectories as well.
syntax: regexp
(?<!\.cfm)$
Works for the root directory but not subdirs/subsubdirs. I don't want to manually specify those.
This is what I see without the ignore:
>hg stat
? document.cfm
? document.txt
? subdir1\document.cfm
? subdir1\document.txt
? subdir1\subsubdir1\document.cfm
? subdir1\subsubdir1\document.txt
? subdir2\document.cfm
? subdir2\document.txt
This is what I see with the ignore:
>hg stat
M .hgignore
? document.cfm
This is what I want to see:
>hg stat
? document.cfm
? subdir1\document.cfm
? subdir1\subsubdir1\document.cfm
? subdir2\document.cfm
Adding a file overrides ignores, so for the .hgignore if you've already added it you don't need to worry about including it. That makes this much easier.
syntax: regexp
(?<!\.cfm)$
assuming that what you were trying to do is ignore everything except .cfm files. Example:
% hg stat --all
A .hgignore
I adir/file.cfm
In general, don't overcomplicate the regex lines -- if you're (un)ignoring two different categories of things use two lines.
The desired action is impossible. Python only does fixed-width negative lookups. Closing this question. Thanks to anyone who looked into it.