.gitignore排除文件夹,但包括特定的子文件夹


962

我有application/添加到的文件夹.gitignore。里面 application/的文件夹是文件夹application/language/gr。如何包含此文件夹?

我已经试过了

application/
!application/language/gr/

没有运气...


1
希望“ .gitignore模式格式”文档更加清晰(2013年12月)。请参阅下面的答案
VonC

我最喜欢的问题和答案,已添加到收藏夹以及浏览器书签中。
codekiddy

Answers:


1610

如果您排除application/,则其下的所有内容将始终被排除(即使后来出现的某些否定排除模式(“忽略”)可能与下方的内容匹配application/)。

要执行您想要的操作,您必须“取消忽略”每个父目录中要“取消忽略”的任何内容。通常,您最终会成对地编写规则:忽略目录中的所有内容,而不忽略某些子目录。

# you can skip this first one if it is not already excluded by prior patterns
!application/

application/*
!application/language/

application/language/*
!application/language/gr/

注意
尾随/*是重要的:

  • 该模式dir/不包括名为目录的目录,dir并且(暗含)目录下的所有目录。
    使用dir/Git时,它将永远不会查看下面的任何内容dir,因此也不会将任何“不排除”模式应用于下面的任何内容dir
  • 模式本身并dir/*没有说明什么dir;它只是排除了所有内容dir。使用dir/*,Git将处理的直接内容dir,从而为其他模式提供“取消排除”部分内容(!dir/sub/)的机会。

12
后面的星号重要吗?如果是这样,含义有什么区别?根据gitignore文档中描述的算法,以斜杠结尾的末尾将匹配目录和该目录下的路径。以星号结尾的内容将作为球形模式接受处理。实验表明,星号变体可以工作,但没有一个以斜杠结尾的变体。我想知道为什么会这样。
SEH

122
@seh:是的,拖尾/*很重要。如果目录被排除,Git将永远不会查看该目录的内容。该模式dir/不包括名为目录的目录,dir并且(暗含)目录下的所有目录。模式本身并dir/*没有说明什么dir;它只是排除了所有内容dir。使用dir/Git时,它将永远不会查看下面的任何内容dir,因此也不会将任何“不排除”模式应用于下面的任何内容dir。使用dir/*,Git将处理的直接内容dir,从而为其他模式提供“取消排除”部分内容(!dir/sub/)的机会。
克里斯·约翰森

7
嗯,这可以解释。无论我阅读过gitignore文档多少次,我都无法理解恢复的模式何时不起作用。根据您的解释,现在很清楚。该gitignore文件需要一个“配方”部分解释如何做到这一点。
seh

8
我不能完全使它正常工作(疯狂的.gitignore文件!),所以我只是将CD压缩后将文件强制添加到所需的目录中。git add -f .
K0D4

2
请注意,您不能依赖的输出git status,它只会告诉您将要添加顶级目录。相反,请执行git add顶层目录中的a,然后git status(希望)列出已被模式匹配的文件的子集。
马修·斯特劳布里奇

136

来自Karsten Blees(kblees)的Git 1.9 / 2.0 提交59856de(2014年第1季度)澄清了以下情况:

gitignore.txt:阐明排除目录的递归性质

可选前缀“ !”,用于否定模式;先前模式排除的所有匹配文件将再次包含在内。

如果排除该文件的父目录,则无法重新包含该文件。(*
*:除非git 2.8+中满足某些条件,否则请参见下文)
Git出于性能原因不会列出排除的目录,因此所包含文件上的任何模式均无效,无论它们在何处定义。

对于以文字“ ” 开头的模式(例如“ \”),请在第一个“ !” 前面加上反斜杠(“ ”)。!\!important!.txt

排除特定目录以外的所有内容的示例foo/bar(请注意/*-,不带斜杠,通配符还将排除内的所有内容foo/bar):

 --------------------------------------------------------------
     $ cat .gitignore
     # exclude everything except directory foo/bar
     /*
     !/foo
     /foo/*
     !/foo/bar
 --------------------------------------------------------------

在您的情况下:

application/*
!application/**/
application/language/*
!application/language/**/
!application/language/gr/**

您必须先将文件夹列入白名单,然后才能将给定文件夹中的文件列入白名单。


2016年2月/ 3月更新:

请注意,在git 2.9.x / 2.10(2016年中?)下,如果重新包含的路径中没有通配符,则如果排除了该文件的父目录,则可以重新包含该文件。

NguyễnTháiNgọcDuy(pclouds试图添加此功能:

因此,使用git 2.9+可能确实有效,但最终被还原:

application/
!application/language/gr/

我试图在Windows的git上使用答案末尾发布的更新的重新包含语法,v2.8.1.windows.1但它似乎不起作用:(
David Hancock

1
@DavidHancock抱歉,我已经编辑了答案:目前尚不可用。
VonC

1
@DavidHancock我也是:那是我必须多次编辑的13个以上的Stack Overflow答案!
VonC

5
Git 2.9已于昨天发布。确认答案中提到的application/+ !application/language/gr/模式已按预期工作。
雷珊

1
@RayShan Strange:我看到取消该功能的还原提交,但我没有看到(发行说明github.com/git/git/blob/master/Documentation/RelNotes/2.9.0.txt没有提及)任何改进.gitignore规则的提交。
VonC

52

@Chris Johnsen的答案很好,但是对于较新版本的Git(1.8.2或更高版本),您可以利用双星号模式来获得更多速记解决方案:

# assuming the root folder you want to ignore is 'application'
application/**/*

# the subfolder(s) you want to track:
!application/language/gr/

这样,您不必“忽略”要跟踪的子文件夹的父目录。


在Git 2.17.0(不确定此版本的发布时间。可能回到1.8.2之前)中,**对于导致文件生成的每个子目录,请使用与excludes结合使用的模式。例如:

# assuming the root folder you want to ignore is 'application'
application/**

# Explicitly track certain content nested in the 'application' folder:
!application/language/
!application/language/gr/
!application/language/gr/** # Example adding all files & folder in the 'gr' folder
!application/language/gr/SomeFile.txt # Example adding specific file in the 'gr' folder

9
las,这失败了(Git 1.8.4.msysgit.0),因为该模式**可以匹配零个子文件夹,并且*可以匹配language和排除它,从而防止包含gr。完整的父母@Chris Johnson建议似乎仍然有必要。
肖恩·古格勒2014年

3
听起来很完美,但在git 2.3.7上对我不起作用... /www/**/* !/www/config.xml !/www/resconfig.xml和res目录仍然被忽略。
罗布

@Rob还需要添加!/www/res/。您可以使用该folder/**/*模式,但是仍然需要为要添加的每个子目录添加排除项。它比忽略/排除组合更短,更易读。
本·凯恩'18

我知道这是一个古老的评论,但是如果您好奇的话。我在答案中添加了编辑,以记录此方法。
本·凯恩

21

关于此还有很多类似的问题,因此我将发布我之前写的内容:

我在计算机上使用此方法的唯一方法是这样做:

# Ignore all directories, and all sub-directories, and it's contents:
*/*

#Now ignore all files in the current directory 
#(This fails to ignore files without a ".", for example 
#'file.txt' works, but 
#'file' doesn't):
*.*

#Only Include these specific directories and subdirectories:
!wordpress/
!wordpress/*/
!wordpress/*/wp-content/
!wordpress/*/wp-content/themes/
!wordpress/*/wp-content/themes/*
!wordpress/*/wp-content/themes/*/*
!wordpress/*/wp-content/themes/*/*/*
!wordpress/*/wp-content/themes/*/*/*/*
!wordpress/*/wp-content/themes/*/*/*/*/*

请注意,您必须显式允许要包含的每个级别的内容。因此,如果我在主题下有5个子目录,则仍然需要清楚地说明。

这是来自@Yarin在这里的评论:https : //stackoverflow.com/a/5250314/1696153

这些是有用的主题:

我也试过

*
*/*
**/**

**/wp-content/themes/**

要么 /wp-content/themes/**/*

这些都不对我有用。大量的反复试验!


1
注意:请记住,顺序在.gitignore文件中也很重要,因此请确保将!规则放在底部。
starbeamrainbowlabs


8

最简单也是最好的方法是尝试手动添加文件(通常优先于.gitignore样式规则):

git add /path/to/module

您甚至可能希望-N 添加意图,以建议您将其添加,但不是立即添加。我经常为尚不准备上演的新文件执行此操作。


这是一份很容易重复的质量检查的答案副本。我将其重新发布在此处以提高可见性-我发现不使用混乱的gitignore规则会更容易。


2
感谢您的回答。我必须添加-f,因为它位于我的.gitignore中,如下所示:git add -f path / to / file
jasonflaherty


6

添加其他答案:

!/.vs/              <== include this folder to source control, folder only, nothing else
/.vs/*              <== but ignore all files and sub-folder inside this folder
!/.vs/ProjectSettings.json <== but include this file to source control
!/.vs/config/       <== then include this folder to source control, folder only, nothing else
!/.vs/config/*      <== then include all files inside the folder

结果如下:

在此处输入图片说明


2
这对我来说是最有用的答案,因为视觉效果有所帮助。谢谢!
乔尔·墨菲

4

特别是对于较旧的Git版本,大多数建议都无法很好地起作用。如果是这种情况,我将在目录中放置一个单独的.gitignore,无论其他设置如何,我都希望包含该目录,并允许存在所需的内容。

例如:/.gitignore

# ignore all .dll files
*.dll

/dependency_files/.gitignore

# include everything
!*

因此,/ dependency_files中的所有内容(甚至包括.dll文件)都很好。


4

我在这里发现了类似的情况,默认情况下,在laravel中,.gitignore所有使用asterix的都将忽略,然后覆盖公共目录。

*
!public
!.gitignore

如果遇到OP场景,这还不够。

如果您要提交的特定子文件夹public,譬如说例如,在你的public/products目录要包括那些一个子文件夹深如文件,包括public/products/a/b.jpg他们不会正确检测,即使你加他们特别喜欢这个!/public/products!public/products/*等。

解决方案是确保为每个这样的路径级别添加一个条目,以覆盖所有条目。

*
!.gitignore
!public/
!public/*/
!public/products/
!public/products/*
!public/products/*/
!public/products/*/
!public/products/*/*

3

只是走下目录结构以获取所需内容的另一个示例。注意:我并未排除,Library/Library/**/*

# .gitignore file
Library/**/*
!Library/Application Support/
!Library/Application Support/Sublime Text 3/
!Library/Application Support/Sublime Text 3/Packages/
!Library/Application Support/Sublime Text 3/Packages/User/
!Library/Application Support/Sublime Text 3/Packages/User/*macro
!Library/Application Support/Sublime Text 3/Packages/User/*snippet
!Library/Application Support/Sublime Text 3/Packages/User/*settings
!Library/Application Support/Sublime Text 3/Packages/User/*keymap
!Library/Application Support/Sublime Text 3/Packages/User/*theme
!Library/Application Support/Sublime Text 3/Packages/User/**/
!Library/Application Support/Sublime Text 3/Packages/User/**/*macro
!Library/Application Support/Sublime Text 3/Packages/User/**/*snippet
!Library/Application Support/Sublime Text 3/Packages/User/**/*settings
!Library/Application Support/Sublime Text 3/Packages/User/**/*keymap
!Library/Application Support/Sublime Text 3/Packages/User/**/*theme

> git add Library

> git status

On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   Library/Application Support/Sublime Text 3/Packages/User/Default (OSX).sublime-keymap
    new file:   Library/Application Support/Sublime Text 3/Packages/User/ElixirSublime.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/Package Control.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/Preferences.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/RESTer.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/SublimeLinter/Monokai (SL).tmTheme
    new file:   Library/Application Support/Sublime Text 3/Packages/User/TextPastryHistory.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/ZenTabs.sublime-settings
    new file:   Library/Application Support/Sublime Text 3/Packages/User/adrian-comment.sublime-macro
    new file:   Library/Application Support/Sublime Text 3/Packages/User/json-pretty-generate.sublime-snippet
    new file:   Library/Application Support/Sublime Text 3/Packages/User/raise-exception.sublime-snippet
    new file:   Library/Application Support/Sublime Text 3/Packages/User/trailing_spaces.sublime-settings

正是我想做的;-)
Kitze 16-11-15

3

在WordPress中,这对我有帮助:

wp-admin/
wp-includes/
/wp-content/*
!wp-content/plugins/
/wp-content/plugins/*
!/wp-content/plugins/plugin-name/
!/wp-content/plugins/plugin-name/*.*
!/wp-content/plugins/plugin-name/**

3

gitignore-指定要忽略的故意未跟踪的文件。

排除特定目录foo / bar以外的所有内容的示例(请注意/ * -不带斜杠,通配符还将排除foo / bar内的所有内容):

$ cat .gitignore
# exclude everything except directory foo/bar
/*
!/foo
/foo/*
!/foo/bar

WordPress的另一个示例:

!/wp-content
wp-content/*
!/wp-content/plugins
wp-content/plugins/*
!wp-content/plugins/my-awesome-plugin

此处提供更多信息:https : //git-scm.com/docs/gitignore


2

我经常在CLI中使用此变通办法,而不是配置我.gitignore,而是创建一个单独的.include文件,在该文件中定义我希望包含的(子)目录,尽管这些目录直接或递归地被忽略.gitignore

因此,我另外使用

git add `cat .include`

在暂存期间,在提交之前。

对于OP,我建议使用.include包含以下几行的:

<parent_folder_path>/application/language/gr/*

注意:使用cat不允许使用别名(在内.include)来指定$ HOME(或任何其他特定目录)。这是因为homedir/app1/*git add使用上述命令传递给该行时,该行显示为git add 'homedir/app1/*',并且将字符括在单引号('')中会保留引号内每个字符的文字值,从而防止别名(例如homedir)起作用(请参阅Bash Single)。引号)。

这是.include我在此处的回购中使用的文件的示例。

/home/abhirup/token.txt
/home/abhirup/.include
/home/abhirup/.vim/*
/home/abhirup/.viminfo
/home/abhirup/.bashrc
/home/abhirup/.vimrc
/home/abhirup/.condarc

1

我想跟踪jquery生产js文件,这行得通:

node_modules/*
!node_modules/jquery
node_modules/jquery/*
!node_modules/jquery/dist/*

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.