git .gitignore 目录及其内容的白名单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15288712/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
.gitignore whitelist on directory and its contents
提问by Ivo van Beek
I'm trying to whitelist the directory (and its contents) SupplierName in my Zend Framework 2 vendor directory.
我正在尝试将 Zend Framework 2 供应商目录中的目录(及其内容)供应商名称列入白名单。
The original .gitignore file in /vendor looks like this:
/vendor 中的原始 .gitignore 文件如下所示:
# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
!.gitignore
*
Now I'd like to whitelist the directory SupplierName which shouldn't be too hard I thought. I have read the docs on gitignoreand tried the following configurations:
现在我想将目录 SupplierName 列入白名单,我认为这应该不会太难。我已经阅读了 gitignore 上的文档并尝试了以下配置:
First try, add !SupplierName right after the comment which says that I have to add the whitelisted path here.
首先尝试,在说明我必须在此处添加列入白名单的路径的评论之后添加 !SupplierName。
# Add here the vendor path to be whitelisted
!SupplierName
# Ex: for composer directory write here "!composer" (without quotes)
!.gitignore
*
Right after that I executed git status
which didn't show the vendor/SupplierName directory. git add vendor/SupplierName
showed the following message:
在那之后,我执行了git status
它没有显示供应商/供应商名称目录。git add vendor/SupplierName
显示以下消息:
The following paths are ignored by one of your .gitignore files: vendor/SupplierName
您的 .gitignore 文件之一将忽略以下路径:vendor/SupplierName
Second try
第二次尝试
# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
!SupplierName
!.gitignore
*
Right after that I executed git status
which didn't show the vendor/SupplierName directory. git add vendor/SupplierName
showed the following message:
在那之后,我执行了git status
它没有显示供应商/供应商名称目录。git add vendor/SupplierName
显示以下消息:
The following paths are ignored by one of your .gitignore files: vendor/SupplierName
您的 .gitignore 文件之一将忽略以下路径:vendor/SupplierName
Third try
第三次尝试
# Add here the vendor path to be whitelisted
# Ex: for composer directory write here "!composer" (without quotes)
!.gitignore
*
!SupplierName
Right after that I executed git status
which didn't show the vendor/SupplierName directory. git add vendor/SupplierName
seems to work. But now, when I want to add the Module.php file (and some other files, subdirectories, etc) the following happens. git add vendor/SupplierName/Module.php
-->
在那之后,我执行了git status
它没有显示供应商/供应商名称目录。git add vendor/SupplierName
似乎工作。但是现在,当我想添加 Module.php 文件(以及其他一些文件、子目录等)时,会发生以下情况。git add vendor/SupplierName/Module.php
-->
The following paths are ignored by one of your .gitignore files: 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/*
Allows me to add files directly in vendor/SupplierName, but git add vendor/SupplierName/config/module.config.php
still results in
允许我直接在供应商/供应商名称中添加文件,但git add vendor/SupplierName/config/module.config.php
仍然导致
The following paths are ignored by one of your .gitignore files: vendor/SupplierName/config/module.config.php
您的 .gitignore 文件之一将忽略以下路径:vendor/SupplierName/config/module.config.php
I've been searching for problems regarding recursive whitelisting, because that seems to be the problem, but nothing came up.
我一直在寻找有关递归白名单的问题,因为这似乎是问题所在,但没有出现任何问题。
回答by Tuxdude
You can use 2 .gitignore
files to achieve the desired result:
您可以使用 2 个.gitignore
文件来实现所需的结果:
# vendor/.gitignore
*
!.gitignore
!SupplierName/
!SupplierName/*
# vendor/SupplierName/.gitignore
!*
I tested this with a test repo and seems to work for me in adding files as many levels deep underneath the vendor/SupplierName
directory.
我用一个测试仓库对此进行了测试,似乎对我在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
#
回答by Chronial
You can also achieve this with only one .gitignore
file (in your project root):
您也可以仅使用一个.gitignore
文件(在您的项目根目录中)来实现这一点:
/*
!/.gitignore
!/vendor
/vendor/*
!/vendor/SupplierName
回答by Simon Lang
Found an interesting article: https://jasonstitt.com/gitignore-whitelisting-patterns
发现一篇有趣的文章:https: //jasonstitt.com/gitignore-whitelisting-patterns
All credits to Jason Stitt. Texts are copied from the site above:
所有学分都归功于杰森·斯蒂特。文字是从上面的网站复制的:
Ignore everything, then add specific subtrees
# Ignore everything * # But descend into directories !*/ # Recursively allow files under subtree !/subtree/** # You can be specific with these rules !/some/other/deep/path/** !.gitignore
The
!*/
rule un-ignores all directories. But Git does not track directories, only files, so!*/
by itself will only allow descent into the full directory tree; it won't actually allow anything into the repo. With that rule in place, you only need one rule using the**
recursive wildcard in order to include a subtree.If you didn't use
!*/
, you would need additional rules to un-ignore /subtree/ and its child directories.Not everyone likes
!*/
because it means that if any other rule allows a filename pattern found inside some directory you don't want in the repo, the directory itself will not be blocked. You need to use specific rules for files to include with this one.Ignore the root directory, then add whole subtrees
# Ignore everything in the root /* # Un-ignore all of subtree !/subtree/ !.gitignore
This pattern is somewhat coarser than the previous one. The
/*
rule will only ignore items in the root of the repo's directory structure, so as soon as you whitelist a directory, all of the directory's contents will be allowed as well, even without using the*
or**
wildcards.Ignore everything in a directory, but keep the empty directory
* !.gitignore
Git does not want to include an empty directory in a repo, because it tracks files. Put a hidden file (such as .gitignore) into the directory, and it will be saved. But to keep the directory empty, even if you have files in there for testing/development purposes, it's a good idea to ignore everything except for the .gitignore file itself.
忽略一切,然后添加特定的子树
# 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/ 及其子目录。不是每个人都喜欢,
!*/
因为这意味着如果任何其他规则允许在某个目录中找到您不想要的文件名模式,则该目录本身不会被阻止。您需要对要包含在此文件中的文件使用特定规则。忽略根目录,然后添加整个子树
# Ignore everything in the root /* # Un-ignore all of subtree !/subtree/ !.gitignore
这种模式比前一种更粗糙。该
/*
规则只会忽略 repo 目录结构根目录中的项目,因此一旦您将目录列入白名单,即使不使用*
或**
通配符,也将允许该目录的所有内容。忽略目录中的所有内容,但保留空目录
* !.gitignore
Git 不想在 repo 中包含空目录,因为它会跟踪文件。将隐藏文件(如.gitignore)放入该目录中,它将被保存。但是为了保持目录为空,即使您有用于测试/开发目的的文件,最好忽略除 .gitignore 文件本身之外的所有内容。
回答by Evan Hu
You should include everything in the blacklist first, then make every directory and subdirctory in the whitelist.
For example, I only want to put DIR /opt/source/
, DIR /opt/nginx/
and FILE /home/test/.opt/hello.txt
in whitelist, could write .gitignore
file like this to make it work:
您应该先将所有内容都包含在黑名单中,然后将每个目录和子目录都包含在白名单中。例如,我只想将 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
回答by Goran
I had a similar issue when moving from CVS to Git.
从 CVS 迁移到 Git 时,我遇到了类似的问题。
Unlike CVS, Git doesn't look at directories, it focuses on files.
与 CVS 不同,Git 不查看目录,它专注于文件。
For example you can't not-ignore directory "a" but you can not-ignore all files in directory "a" like so: !a/*
例如,您不能不忽略目录“a”,但不能忽略目录“a”中的所有文件,如下所示: !a/*
The same is true for subdirectories.
子目录也是如此。
If directory "a" has a subdirectory "b" and you ignore "!a/*" then you will still get all files in "a/b".
如果目录“a”有一个子目录“b”而你忽略“!a/*”,那么你仍然会得到“a/b”中的所有文件。
So you then have to ignore that too "!a/b/*" and so on for all subdirectories that you want to white list.
因此,对于要列入白名单的所有子目录,您也必须忽略“!a/b/*”等。
You only need one .gitignore file.
您只需要一个 .gitignore 文件。
so you end up with something like:
所以你最终会得到类似的东西:
# 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/*
With this you would still get files from a/c and a/b/c. I'm not sure if there is a workaround for recursion down subdirectories.
有了这个,您仍然可以从 a/c 和 a/b/c 获取文件。我不确定是否有递归子目录的解决方法。
回答by SilbinaryWolf
I've created a simple JS snipscript that can run in Node to generate a whitelist rule as I found manually writing rules a bit confusing and I wanted to be able to modify the rule later if I forgot how to hand-write it.
我创建了一个简单的 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'
);
回答by Ryan Feeley
This is related to the first technique from @Simon Lang (with credit to Jason Stitt), but is applicable to a wider variety of cases.
这与@Simon Lang 的第一种技术有关(归功于 Jason Stitt),但适用于更广泛的案例。
Suppose you want to have just one .gitignore in your project root, and suppose you want to ignore the bulk of some subdirectory of your project, but allow in some small portion. For example, suppose your repo includes a /vendor/
directory with a 3rd party dependency that you've elected to keep largely intact, but to which you'll make some light adjustments that you want git to track, perhaps to assist with back porting when the inevitable new version appears.
假设您只想在项目根目录中包含一个 .gitignore,并假设您想忽略项目的某些子目录的大部分内容,但允许一小部分。例如,假设您的 repo 包含一个/vendor/
具有 3rd 方依赖项的目录,您已选择将其基本保持不变,但您将对其进行一些您希望 git 跟踪的轻微调整,以便在不可避免的情况下协助向后移植新版本出现。
You can then do the following in your root .gitignore
file:
然后,您可以在根.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/**
Each instance of the double asterisk is critical. For example, a trailing vendor/**
matches everything inside -- all files and directories in vendor
with infinite depth, and so excludes all of its descendants.
双星号的每个实例都很关键。例如,尾随vendor/**
匹配内部的所有内容——vendor
无限深度的所有文件和目录,因此排除其所有后代。
In a "normal" wildcard gitignore rule like *.exe
or *
, the glob metacharacter match discovers any file in any directory, since the path is unconstrained. The path being unconstrained is doing the heavy lifting here, not the wildcard expansion. As soon as you try to restrict the scope of the ignore to a subdirectory of your root, that heavy lifter is gone and you immediately bump into the inability of *
to descend into the tree.
在像*.exe
or这样的“普通”通配符 gitignore 规则中*
,glob 元字符匹配会发现任何目录中的任何文件,因为路径不受约束。不受约束的路径在这里执行繁重的工作,而不是通配符扩展。一旦您尝试将 ignore 的范围限制在您的根目录的子目录中,那么繁重的工作就会消失,您会立即遇到无法*
下降到树中的情况。
Simon's answer works by keeping the tip of the initial exclude path unconstrained. It initially excludes every file (at any depth) in the directory that contains the .gitignore file. Mine gives you the flexibility to apply this exclude-all approach to subdirectories, by using **
to do globstar matching of /
. You could achieve the same effect by having multiple .gitignore files and using Simon's technique in a .gitignore file located at /vendor/.gitignore
, but that's more to maintain.
西蒙的答案通过保持初始排除路径的尖端不受约束而起作用。它最初排除包含 .gitignore 文件的目录中的每个文件(任何深度)。通过使用**
.globstar 匹配/
. 您可以通过拥有多个 .gitignore 文件并在位于 的 .gitignore 文件中使用 Simon 的技术来实现相同的效果/vendor/.gitignore
,但这需要更多的维护。
I don't know if there are any performance implications to using **
as I've done here. That might be testable by comparing the performance of a .gitignore that looked like
我不知道**
像我在这里所做的那样使用是否有任何性能影响。通过比较看起来像的 .gitignore 的性能,这可能是可测试的
*
!*/
!a/b/c/d/**
to one that looked like this
对一个看起来像这样的人
/**
!**/
!a/b/c/d/**
in a tree having a lot of files. I believe the same content would be included and excluded, but the implementation under the hood may differ, as may the performance.
在有很多文件的树中。我相信将包含和排除相同的内容,但引擎盖下的实现可能会有所不同,性能也可能有所不同。