Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP filtering files and paths according .gitignore

I want to use PHP to read all files and paths ignored by .gitignore configuration. Just like how git does.

It's possible to read directory repeatedly and use regular expression for each file to filter. But it`s so ineffective if the path have too much files.

Any good and most effective way to read target files and path ignored by .gitignore?

like image 739
Angolao Avatar asked Nov 14 '13 15:11

Angolao


3 Answers

You need to proceed in several steps:

1 - Find the .gitignore files

Each folder can have one, so don't assume there's a single one.

And submodules have a .git link to the main .git folder, so be wary about stopping too early as well.

It'll go something like:

function find_gitignore_files($dir) {
  $files = array();
  while (true) {
    $file = "$dir/.gitignore";
    if (is_file($file)) $files[] = $file;
    if (is_dir("$dir/.git") && !is_link("$dir/.git")) break;  # stop here
    if (dirname($dir) === '.') break;                         # and here
    $dir = dirname($dir);
  }
  return $files;
}

2 - Parse each .gitignore file

You need to ignore comments, mind the negation operator (!), and mind the globs.

This one is, give or take, is going to go something like:

function parse_git_ignore_file($file) { # $file = '/absolute/path/to/.gitignore'
  $dir = dirname($file);
  $matches = array();
  $lines = file($file);
  foreach ($lines as $line) {
    $line = trim($line);
    if ($line === '') continue;                 # empty line
    if (substr($line, 0, 1) == '#') continue;   # a comment
    if (substr($line, 0, 1) == '!') {           # negated glob
      $line = substr($line, 1);
      $files = array_diff(glob("$dir/*"), glob("$dir/$line"));
    } else {                                    # normal glob
      $files = glob("$dir/$line");
    }
    $matches = array_merge($matches, $files);
  }
  return $matches;
}

(Note: none of the above is tested, but they should put you in the right direction.)

like image 105
Denis de Bernardy Avatar answered Oct 25 '22 11:10

Denis de Bernardy


Just a crazy idea: if you rely on Git to give you the patterns for ignored files why not rely on it to give the list of included/ignored files? Just issue a command like:

  • git ls-files for all tracked files
  • git clean -ndX or git ls-files -i --exclude-from=[Path_To_Your_Global].gitignore for all ignored files

See which Git command gives you the best output and then loop through the path files.

And a word of caution: take all the necessary precaution measures needed when executing external commands!

Sources:

  • Show ignored files in git
  • List files in local git repo?
like image 32
Max Avatar answered Oct 25 '22 10:10

Max


I use this function to read the Whole path, it works good

function read_dir($dir)
    {
        $files = array();
        $dir = preg_replace('~\/+~','/',$dir . '/');
        $all  = scandir($dir);
        foreach($all as $path):
            if($path !== '.' && $path !== '..'):
                $path = $dir . '/' . $path;
                $path = preg_replace('~\/+~','/',$path);
                $path = realpath($path);
                if(is_dir($path)):
                    $files = array_merge($files, read_dir($path));
                endif;
                $files[] = preg_replace('~/+~i','/',$path);
            endif;
        endforeach;
        return $files;
}

UPDATE: You Can Use preg_grep over the above function as follow

$files = preg_grep('~\.gitignore\b~i', array_values(read_dir($path)));
like image 20
Mohammed Al Ashaal Avatar answered Oct 25 '22 10:10

Mohammed Al Ashaal