Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the equivalent of .hgignore's regular expressions ^var/(?!\log|.dummy) and ^var/log/(?!\.dummy) in .gitignore?

I am converting my Mercurial repository to Git. Part of the file system looks like this:

|-- .gitignore
|-- .hgignore
`-- var
    |-- .dummy
    |-- asdf
    `-- log
        |-- .dummy
        `-- asdf

My .hgignore file uses regular expressions. Part of my .hgignore file is as follows:

^var/(?!\log|.dummy)
^var/log/(?!\.dummy)

I want to track the .dummy files but not the asdf files. hg status returns:

? var/.dummy
? var/log/.dummy

How can I get the same effect in .gitignore? I have tried the following:

/var/**/*
!/var/.dummy
!/var/log/.dummy

But this will not ignore var/asdf as desired. How can I track var/.dummy and var/log/.dummy and ignore var/asdf and var/log/asdf?

like image 819
saltycrane Avatar asked Dec 16 '22 16:12

saltycrane


2 Answers

If you are only using the .dummy files as placeholders to make sure that you always get those particular (nearly empty) directories when you make a clean checkout, then you should probably just exclude /var and use git add -f var/.dummy var/log/.dummy to start explicitly tracking the placeholder files. The effective result is that you will ignore everything except the .dummy files that you explicitly tracked.

On the other hand, if you plan on expanding the hierarchy of nearly empty directories beyond just var/log, then you might be able to make use of a bit of explanation.

The rules are described in gitignore(5), but sometimes it is difficult to make sense of all the rules and how they interact. The important part is that the last rule wins, and that later rules can only be effective if the directories they act on are not already wholly ignored. This means that you if you have ignored directories, you have to unignore them before you can unignore a bit of their contents (while re-ignoring the rest of their contents).


If you want to automatically ignore everything except .dummy files under var, then the simplest way of doing this involves putting a .gitignore file in your var directory instead of doing it at the top level. I described this solution in another SO answer.

# var/.gitignore
*
!/.gitignore
!.dummy
!*/
  1. Ignore everything in this directory (var).
  2. But, do not ignore this one .gitignore file (you can leave this out if you are willing to do git add -f to start tracking this .gitignore file).
  3. Also, do not ignore .dummy files at any depth in the hierarchy rooted at this directory (var).
  4. Also, do not ignore any directories at any depth under this directory (var).
    Without this rule, the first rule will ignore the subdirectories and Git would never even open them to look for .dummy files.

The last two patterns are “recursive” because they do not have a non-trailing slash (meaning that * will match slashes in addition to other characters). A trailing slash makes the pattern match only directories. Leading and embedded slashes effectively anchor the pattern to the location of the .gitignore file (or the root of the repository for patterns from other exclude files). The idea is that a plain *.o should match anywhere, but dir/*.o should only match items directly under dir (and we can use /*.o for this latter effect in dir/.gitignore).


If you can not tolerate a var/.gitinore file, then you can still do what you asked, but you can not automatically “unignore” new .dummy files anywhere under var without editing the exclude patterns.

# .gitignore at root of repository
/var/*
!/var/.dummy

!/var/log/
/var/log/*
!/var/log/.dummy
  1. Ignore everything under the var directory that is a sibling of this .gitignore file.
  2. But, do not ignore the var/.dummy.
  3. Also, do not ignore the directory var/log.
  4. But, ignore everything directly in var/log.
  5. But, do not ignore var/log/.dummy.

The pattern is: unignore an interesting directory (skip this the first time, since everything is “unignored” by default), ignore what is in the directory, unignore the .dummy file in it. Repeat the pattern for each deeper part of the hierarchy.

You can replace log with * to make it work for any directory directly under var, but it will not automatically work for directories that are deeper (e.g. it would work for var/cache/.dummy, but not for var/log/ssh/.dummy). This is because we are using non-trailing slashes and anchor the patterns. To manually make it work, you have to repeat the pattern to generate more exclusion rules for the deeper parts (unignore interesting dir, ignore contents of dir, unignore file).

like image 169
Chris Johnsen Avatar answered Dec 19 '22 07:12

Chris Johnsen


You don't need to exclude .dummy with regex. Just ignore everything and manually add then all your .dummy.

Ignore affects only on the status command result.

like image 45
zerkms Avatar answered Dec 19 '22 07:12

zerkms