44

我正在尝试将 Zend Framework 2 供应商目录中的目录(及其内容)SupplierName 列入白名单。

/vendor 中的原始 .gitignore 文件如下所示:

# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
!.gitignore
*

现在我想将目录 SupplierName 列入白名单,我认为这不应该太难。我已阅读 gitignore 上的文档并尝试了以下配置:

首先尝试,在说明我必须在此处添加白名单路径的评论之后添加 !SupplierName。

# Add here the vendor path to be whitelisted
!SupplierName
# Ex: for composer directory write here "!composer" (without quotes)
!.gitignore
*

之后我执行git status了没有显示 vendor/SupplierName 目录的操作。git add vendor/SupplierName显示以下消息:

您的 .gitignore 文件之一会忽略以下路径:vendor/SupplierName

第二次尝试

# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
!SupplierName
!.gitignore
*

之后我执行git status了没有显示 vendor/SupplierName 目录的操作。git add vendor/SupplierName显示以下消息:

您的 .gitignore 文件之一会忽略以下路径:vendor/SupplierName

第三次尝试

# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
!.gitignore
*
!SupplierName

之后我执行git status了没有显示 vendor/SupplierName 目录的操作。git add vendor/SupplierName 似乎工作。但是现在,当我想添加 Module.php 文件(以及其他一些文件、子目录等)时,会发生以下情况。git add vendor/SupplierName/Module.php-->

您的 .gitignore 文件之一会忽略以下路径:vendor/SupplierName/Module.php

# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
*
!.gitignore
!SupplierName
!SupplierName/
!SupplierName/*

允许我直接在供应商/供应商名称中添加文件,但git add vendor/SupplierName/config/module.config.php仍会导致

您的 .gitignore 文件之一会忽略以下路径:vendor/SupplierName/config/module.config.php

我一直在寻找有关递归白名单的问题,因为这似乎是问题所在,但没有出现任何问题。

4

7 回答 7

50

您可以使用 2 个.gitignore文件来实现所需的结果:

# vendor/.gitignore
*
!.gitignore
!SupplierName/
!SupplierName/*

# vendor/SupplierName/.gitignore
!*

我使用测试存储库对此进行了测试,并且似乎可以在vendor/SupplierName目录下添加尽可能多级别的文件。

$ git add .

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   vendor/.gitignore
#   new file:   vendor/SupplierName/.gitignore
#   new file:   vendor/SupplierName/a
#   new file:   vendor/SupplierName/b
#   new file:   vendor/SupplierName/c
#   new file:   vendor/SupplierName/d
#   new file:   vendor/SupplierName/dir1/d
#   new file:   vendor/SupplierName/dir1/dir4/dir5/dir6/dir7/dir8/dir9/dir10/somefile
#   new file:   vendor/SupplierName/dir1/dir4/f1
#   new file:   vendor/SupplierName/dir1/dir4/f2
#   new file:   vendor/SupplierName/dir1/dir4/f3
#   new file:   vendor/SupplierName/dir1/dir4/f4
#   new file:   vendor/SupplierName/dir1/e
#   new file:   vendor/SupplierName/dir1/f
#   new file:   vendor/SupplierName/dir3/dir6/f5
#   new file:   vendor/SupplierName/dir3/dir6/f6
#   new file:   vendor/SupplierName/dir3/dir6/f7
#   new file:   vendor/SupplierName/dir3/dir7/f8
#   new file:   vendor/SupplierName/e
#
于 2013-03-10T09:25:10.080 回答
16

您也可以只使用一个.gitignore文件(在您的项目根目录中)来实现这一点:

/*
!/.gitignore
!/vendor
/vendor/*
!/vendor/SupplierName
于 2013-03-10T23:37:04.880 回答
8

发现一篇有趣的文章:https ://jasonstitt.com/gitignore-whitelisting-patterns

杰森斯蒂特的所有功劳。文字是从上面的网站复制的:

忽略一切,然后添加特定的子树

# Ignore everything
*
# But descend into directories
!*/
# Recursively allow files under subtree
!/subtree/**
# You can be specific with these rules
!/some/other/deep/path/**
!.gitignore 

!*/规则取消忽略所有目录。但是 Git 不跟踪目录,只跟踪文件,所以!*/它本身只允许下降到完整的目录树;它实际上不允许任何东西进入回购。有了该规则,您只需要一个使用**递归通配符的规则即可包含子树。

如果您不使用!*/,则需要额外的规则来取消忽略 /subtree/ 及其子目录。

不是每个人都喜欢!*/,因为这意味着如果任何其他规则允许在您不希望在 repo 中的某个目录中找到文件名模式,则该目录本身不会被阻止。您需要对要包含在此文件中的文件使用特定规则。

忽略根目录,然后添加整个子树

# Ignore everything in the root
/*
# Un-ignore all of subtree
!/subtree/
!.gitignore 

这种模式比前一种更粗糙。该/*规则只会忽略 repo 目录结构的根目录中的项目,因此一旦您将目录列入白名单,即使不使用***通配符,也将允许该目录的所有内容。

忽略目录中的所有内容,但保留空目录

*
!.gitignore

Git 不想在 repo 中包含一个空目录,因为它会跟踪文件。将一个隐藏文件(如.gitignore)放入目录中,它将被保存。但是要保持目录为空,即使您有用于测试/开发目的的文件,最好忽略除 .gitignore 文件本身之外的所有内容。

于 2017-11-21T13:25:11.330 回答
2

从 CVS 迁移到 Git 时,我遇到了类似的问题。

与 CVS 不同,Git 不查看目录,而是关注文件。

例如,您不能不忽略目录“a”,但不能忽略目录“a”中的所有文件,如下所示:!a/*

子目录也是如此。

如果目录“a”有一个子目录“b”并且你忽略了“!a/*”,那么你仍然会得到“a/b”中的所有文件。

因此,对于要列入白名单的所有子目录,您也必须忽略“!a/b/*”等等。

您只需要一个 .gitignore 文件。

所以你最终会得到类似的东西:

# ignore everything
*
# except for .gitignore files in the current directory
!.gitignore
# and all files in directory a
!a/*
#and all files in subdirectory b
!a/b/*

有了这个,您仍然可以从 a/c 和 a/b/c 获取文件。我不确定是否有递归子目录的解决方法。

于 2013-03-10T19:49:43.650 回答
2

您应该首先将所有内容都包含在黑名单中,然后将每个目录和子目录都包含在白名单中。例如,我只想将 DIR /opt/source/, DIR/opt/nginx/和 FILE/home/test/.opt/hello.txt放在白名单中,可以这样编写.gitignore文件以使其工作:

/*
!/.gitignore
!/opt
/opt/*
!/opt/source/
!/opt/nginx/
!/home
/home/*
!/home/test
/home/test/*
!/home/test/.opt
/home/test/.opt/*
!/home/test/.opt/hello.txt
于 2015-10-25T03:15:30.313 回答
1

这与 @Simon Lang 的第一个技术(归功于 Jason Stitt)有关,但适用于更广泛的案例。

假设您希望在项目根目录中只有一个 .gitignore,并假设您想忽略项目的某些子目录的大部分内容,但允许其中的一小部分。例如,假设您的 repo 包含一个/vendor/具有 3rd 方依赖项的目录,您选择在很大程度上保持该依赖项,但您将对其进行一些您希望 git 跟踪的轻微调整,也许有助于在不可避免的情况下进行反向移植新版本出现。

然后,您可以在根.gitignore文件中执行以下操作:

# ignore all files and folders in `/vendor/` and in its descendants
/vendor/**

# negated pattern to un-exclude all *folders* at any depth relative to `vendor/`
# as always git will ultimately ignore the folders for which you don't
# subsequently un-exclude any *files*.
!/vendor/**/

# negated pattern to un-exclude all files and folders at any depth below the deep
# path that contains files you want in git
!/vendor/supplier/version/module/component/src/**

双星号的每个实例都是关键的。例如,尾随vendor/**匹配内部的所有内容 -vendor无限深度的所有文件和目录,因此排除其所有后代。

在类似*.exeor的“普通”通配符 gitignore 规则*中,glob 元字符匹配会发现任何目录中的任何文件,因为路径不受约束。不受约束的路径在这里完成繁重的工作,而不是通配符扩展。一旦你试图将忽略的范围限制在你的根目录的子目录中,那个繁重的提升器就消失了,你立即遇到了无法*下降到树中的问题。

西蒙的答案通过保持初始排除路径的尖端不受约束来起作用。它最初会排除包含 .gitignore 文件的目录中的每个文件(任何深度)。Mine 通过使用**/. 您可以通过拥有多个 .gitignore 文件并在位于 的 .gitignore 文件中使用 Simon 的技术来实现相同的效果/vendor/.gitignore,但这更需要维护。

我不知道**像我在这里所做的那样使用是否会对性能产生影响。这可以通过比较看起来像的 .gitignore 的性能来测试

*
!*/
!a/b/c/d/**

一个看起来像这样的

/**
!**/
!a/b/c/d/**

在有很多文件的树中。我相信相同的内容会被包含和排除,但引擎盖下的实现可能会有所不同,性能也可能会有所不同。

于 2019-07-26T09:32:45.093 回答
0

我创建了一个简单的 JS 片段脚本,可以在 Node 中运行以生成白名单规则,因为我发现手动编写规则有点令人困惑,如果我忘记如何手写它,我希望以后能够修改规则。

'use strict';

// Generating a "whitelist" wherein you only want a specific folder to be
// affected requires following .gitignore-style rules.
// https://github.com/prettier/prettier/issues/3328
//
// Handcrafting these rules is hard to reason about and error-prone, so I'm
// going to generate them.
// See: https://github.com/prettier/prettier/issues/3328
// And: https://git-scm.com/docs/gitignore
//

const path = require('path');

const whitelistDir = '/themes/simple/src/';

function generateIgnoreRule(dir) {
    let output = '# Auto-generated by ' + path.basename(__filename) + '\n';
    output += '# Exclude everything except `' + dir + '`\n';
    // Add exclude everything rule
    output += '/*' + '\n';

    // Split by path
    const parts = dir.split('/');
    if (parts[0] === '') {
        // Remove first item if its blank
        parts.shift();
    }
    if (parts[parts.length - 1] === '') {
        // Remove last item if its blank
        parts.pop();
    }

    let totalPart = '';
    for (let part of parts) {
        totalPart += '/' + part;
        output += '!' + totalPart + '\n';
        if (part !== parts[parts.length - 1]) {
            output += totalPart + '/*' + '\n';
        }
    }
    return output;
}

console.log(generateIgnoreRule(whitelistDir));
console.log(
    '\nCopy the above rules out of the console output and paste into your .gitignore / .prettierignore'
);
于 2018-11-21T22:35:59.173 回答