5

我想使用 PHP 读取 .gitignore 配置忽略的所有文件和路径。就像 git 一样。

可以重复读取目录并使用正则表达式对每个文件进行过滤。但是如果路径中的文件太多,它就会变得非常无效。

读取.gitignore忽略的目标文件和路径的任何好的和最有效的方法?

4

6 回答 6

7

您需要分几个步骤进行:

1 - 找到 .gitignore 文件

每个文件夹可以有一个,所以不要假设只有一个。

子模块有一个指向主 .git 文件夹的 .git 链接,所以也要小心不要过早停止。

它会像这样:

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 - 解析每个 .gitignore 文件

您需要忽略注释,注意否定运算符 ( !),并注意 glob。

这个是,给予或接受,将会是这样的:

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;
}

(注意:以上都没有经过测试,但它们应该让你朝着正确的方向前进。)

于 2013-11-22T18:18:42.350 回答
2

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:

于 2013-11-21T12:51:24.880 回答
2

我用这个函数来读取整个路径,效果很好

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;
}

更新:您可以在上述函数上使用 preg_grep,如下所示

$files = preg_grep('~\.gitignore\b~i', array_values(read_dir($path)));
于 2013-11-19T13:03:00.757 回答
1

您可以从文件中获取要忽略的文件数组.gitignore并对其进行检查。为此,您需要使用该glob函数读取文件并匹配文件。

首先,获取文件内容:

$contents = file_get_contents($pathToGitIgnoreFile);
$path = dirname(realpath($pathToGitIgnoreFile));

也可以使用文件所在目录.gitignore来匹配与 gitignore 同目录的文件。

接下来,我们需要将内容拆分为单独的规则。规则从文件中自己的行开始。以井号 ( ) 开头的行#是注释,所以我们可以使用正则表达式来查找不是注释的非空行:

$rules = array();
preg_match_all('/[\\A\\v]([^#\\v]\\V*)[\\z\\v]?/', $contents, $rules);
$rules = $rules[1];

然后你所要做的就是遍历规则并使用glob创建一个文件名数组来忽略:

$files = array();
foreach ($rules as $rule)
{
    if (strpos($rule, '!') === 0) // negative rule
        $files = array_diff($files, glob($path . DIRECTORY_SEPARATOR . substr($rule, 1)));
    else
        $files = array_merge($files, glob($path . DIRECTORY_SEPARATOR . $rule));
}
$files = array_unique($files);

我没有测试这段代码,如果它不适合你,请在下面评论。

于 2013-11-14T19:53:16.410 回答
1

.gitignore 中的条目主要是 glob 模式。您可以使用 php 函数读取 .gitignore 的每一行file,忽略空行和开头的行,#然后使用 phpglob函数(http://php.net/manual/en/function.glob.php)读取模式

于 2013-11-14T17:11:53.603 回答
0

SPL(标准 PHP 库)包含一些用于该作业的迭代器。我将示例限制为过滤掉所有以“。”开头的目录或文件。以他们的名义。

.gitignore 的规则非常复杂,解析条目和构建一组规则将超出示例的范围。

$directory = __DIR__;

$filtered = new RecursiveIteratorIterator(
  new RecursiveCallbackFilterIterator(
    new RecursiveDirectoryIterator($directory),
    function ($fileInfo, $key, $iterator) {
      // only accept entries that do not start with an . 
      return substr($fileInfo->getFilename(), 0, 1) != '.';
    }
  )
);


foreach ($filtered as $fileInfo) {
  echo (string)$fileInfo, "\n";
}
于 2013-11-20T14:50:21.703 回答