在Git中取消忽略目录的子目录

150

假设我已经忽略了一个目录,但我想要取消忽略其中特定的子目录。因此,我的设置如下:

/uploads/
/uploads/rubbish/
/uploads/rubbish/stuff/KEEP_ME/
/uploads/foo/
/uploads/foo/bar/lose/

我想忽略除了KEEP_ME目录之外的所有内容。 我希望忽略看起来像这样:

而我只想保留 KEEP_ME 目录,希望 ignore 的规则如下:

/uploads/*
!/uploads/rubbish/stuff/KEEP_ME/

但是那并没有起作用,尝试了几个相同主题的变化也都没有成功。

一个能够正常工作的是

/uploads/**/**/**/
!/uploads/rubbish/stuff/KEEP_ME/

但这感觉有点太限制性和啰嗦了?


1
您提供的代码在我的机器上运行不起来(使用 git 版本 1.9.1)。一个可用的版本是:/uploads/* !/uploads/rubbish/ /uploads/rubbish/* !/uploads/rubbish/stuff /uploads/rubbish/stuff/* !/uploads/rubbish/stuff/keep(与 http://git-scm.com/docs/gitignore 中的示例类似)。我的文件夹结构如下:└ README.md └ uploads/foo/bar/lose/lose.txt └ uploads/rubbish/stuff/keep/keep.txt - gihanchanuka
6个回答

170
根据gitignore文档中的模式格式部分

可选前缀 "!" 可否定模式;任何与先前模式匹配的文件将再次被包括在内。 如果父目录被排除,则不可能重新包含该文件。Git出于性能原因不会列出排除的目录,因此包含文件的任何模式都没有效果,无论它们在哪里定义。 对于以文字"!"开头的模式,例如,"!important!.txt",请在第一个"!"前加上反斜杠("\")。

因此,在否定其内容之前,必须专门否定先前排除的父目录/uploads/rubbish/stuff/keep/模式:
#ignore everything within /uploads/ 
/uploads/*

#include everything within /uploads/rubbish/stuff/keep
!/uploads/rubbish/stuff/keep/  
!/uploads/rubbish/stuff/keep/*

要包含/uploads/rubbish/stuff/keep/目录中的子目录,请添加第三行:

!/uploads/rubbish/stuff/keep/**/*

1
你使用的是哪个版本的 git?也许这是某些版本才有的功能。 - user153275
不好意思,我忘记了我发了这个评论。不过我已经解决了。顺便说一下,我不使用前导斜杠。我不记得那是否是问题所在了。我正在使用1.7.2.5版本。 - user153275
我有一个全局的gitignore文件,其中我忽略了所有*.zip文件。然而,对于特定的项目,我想要包括zip文件。我在该项目的.gitignore文件中添加了这一行,它运行得非常好!:!*.zip - Jinghao Shi
我发现有必要在给定文件夹之前和之后显式指定任意目录,既在排除文件夹的同时也包括子文件夹。(完整答案)。 - Josiah Yoder
2
这种方法不起作用(在git 2.25中可能有一些变化)。我在下面发布了https://dev59.com/R2435IYBdhLWcg3wtSYV#60288435作为更正。 - user295691
请注意,如果您意外地使用/uploads/直接忽略目录,而不是使用/uploads/*忽略其内容,则尝试使用!规则取消忽略该忽略目录中的某些内容将无法正常工作。我在我的回答中提到了这一点,“强制添加,尽管有.gitignore文件”。 - Gabriel Staples

46

即使你将某些内容添加到 .gitignore 中,也可以使用 强制 命令将其添加到索引中。

git add --force uploads/rubbish/stuff/KEEP_ME/

然而,“KEEP_ME”似乎是一个目录,而Git通常不喜欢空文件夹,因此,如果该文件夹为空,您可以添加一个“placeholder”文件。

git add --force uploads/rubbish/stuff/KEEP_ME/.keep_me

唯一的问题是,这个特定的例子指的是一个全局的gitignore,我应该提到这一点。我知道我可以强制添加项目,但是如果有任何新项目被添加,我需要每次都要这样做,以及最初对于每个新的仓库。.keep是否确保内容不被忽略? - Wil
1
做了一个小测试。是的,在KEEP_ME中的每个新项目或文件夹都必须使用git add --force,但之后,更新只需添加(例如执行git add -u)就像文件未被忽略一样。.keep_me没有任何作用,它只是一个文件,以便Git在文件夹上操作。 - commonpike
3
“git add --force” 不是解决这个问题的正确方法。如果你移动了一个目录或将文件移动到另一个目录,git 的跟踪会删除该文件,但不会将其添加到新位置,因此您必须再次使用 “git add --force”。通过在通用模式上取消忽略,git 将跟踪存储库内文件的移动。 - Merlin
这是我唯一行得通的解决方案。我的文件夹并没有被忽略,但我无论如何也添加不了它。这种方式解决了我的问题。 - Akito

14

这篇最被赞的答案所提供的解决方案是错误的,并且很容易证明。

首先忽略uploads / *中的所有内容:

mkdir -p uploads/rubbish/stuff/KEEP_ME
touch uploads/a uploads/rubbish/a uploads/rubbish/stuff/a uploads/rubbish/stuff/KEEP_ME/a
echo '/uploads/*' >> .gitignore
git init
git add .
git commit -m "Initial commit"

现在像上面那样取消忽略被忽略的东西的父目录:

echo 'uploads/rubbish/stuff/KEEP_ME/' >> .gitignore
echo 'uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

没有未跟踪的文件。

为了使它工作,您需要忽略uploads/目录下的所有文件(不仅仅是顶层的uploads/*,而是整个目录树uploads/**/*),然后添加您想要保留的目录树的所有父目录。

echo '/uploads/**/*' > .gitignore
echo '!/uploads/rubbish/' >> .gitignore
echo '!/uploads/rubbish/stuff' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME' >> .gitignore
echo '!/uploads/rubbish/stuff/KEEP_ME/*' >> .gitignore
git status -u

这会得到:

On branch master
...
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        uploads/rubbish/stuff/KEEP_ME/a

如果我们在上面的.gitignore文件中使用uploads/*,那么所有的中间文件也会被包括在内,例如uploads/rubbish/a将出现在上述状态命令中。

9

Buo-Ren LinJohn的回答非常有用,但我需要将两者结合起来。

当想要排除uploads文件夹内的其他子文件夹以及文件时,有必要在排除文件夹和包含子文件夹时都明确指定给定文件夹之前的任意目录

**/uploads/*
!**/uploads/rubbish/
!**/uploads/rubbish/*

我还发现有必要明确重新包含子文件夹及其内容,以显示文件夹和子文件夹中的所有项目。


唉,这里一点运气都没有。我已经在这里折腾了几个小时了。Git 2.20.1。 - RichieHH
@HörmannHH 很抱歉听到这个消息。也许现在是提出新问题的时候了? - Josiah Yoder

6

我试图找出如何在排除所有通用排除文件夹的情况下包含特定文件夹。

**/build

如果在您的通用排除列表末尾添加/*,则可以继续排除所有构建文件**/build/*
然后,您需要再添加另一行来纠正您想要包含的路径,格式如下:
!**/folder/build/* 

留给我们一个读取的.gitignore文件
**/build/* 
!**/folder/build/* 

0

git版本2.30.1(Apple Git-130)

对于像我这样需要取消忽略某种类型文件的人来说,!方法也是有效的。 此外,正如Art Shayderov所提到的,这种方法仍然在git的官方文档中列出。

因此,我的情况是我们的iOS项目完全忽略了dsym文件。 但是,我们需要检入一些随xcframeworks一起提供的必要的dsym文件。 这是我的.gitignore的一部分。

## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
!*.dSYM

在我添加了最后一行并保存文件后,这些dsym立即出现在我的源代码控制工具中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接