如何将空目录添加到 Git 存储库?

git directory git-add

如何将空目录(不包含文件)添加到 Git 存储库?

虽然它没有用,但there is a way to hack an empty (really empty) directory into your repo。但是,它不会在当前版本的 Git 中checkout

@tiwo 我不同意它没有用。您的目录层次结构是您项目的一部分,因此它应该是版本控制的。

就我而言,我想为 tmp 文件添加目录结构,但不是 tmp 文件本身。通过这样做,我的测试仪具有正确的结构(否则会出现错误),但我不会用 tmp 数据阻塞我的提交。所以是的,它对我有用!

@AdamMarshall 我认为 tiwo 是说黑客没有用,因为它被结帐忽略了。 Tmp dirs 听起来确实是 VCS 的一个有用功能。

为什么不让创建 tmp 文件的过程也创建 tmp 目录呢?

H
HelloGoodbye

使目录保持(几乎)空(在存储库中)的另一种方法是在该目录中创建一个 .gitignore 文件,其中包含以下四行:

# Ignore everything in this directory
*
# Except this file
!.gitignore

这样您就不必像在 m104 的 solution 中那样正确地获得订单了。

这也带来了好处,即当您执行 git status 时,该目录中的文件不会显示为“未跟踪”。

使 @GreenAsJade 的评论持久化:

我认为值得注意的是,这个解决方案正是问题所要求的,但也许不是许多查看这个问题的人一直在寻找的。此解决方案保证目录保持为空。它说“我真的不想在这里签入文件”。与“我这里还没有要签入的文件,但我需要这里的目录,文件可能稍后会出现”相反。

我认为@JohnMee提出的README解决方案应该和这个一起使用; .gitignore 文件解释了我们希望避免版本控制的内容,而 README 文件解释了目录的用途,这两个都是非常重要的信息。

@pedromanoel 我编写了您将放入 .gitignore 文件中的 README 的文档(作为注释)。

发现 1 个不同之处:1.)一个空文件夹,2.)一个包含 .gitignore 文件的文件夹。 ;-)

这非常适合缓存文件夹。

不幸的是,这会导致一个非空目录,它有一个隐藏文件。

G
Gilles 'SO- stop being evil'

你不能。请参阅 Git FAQ

目前 git 索引(暂存区)的设计只允许列出文件,并且没有足够能力进行更改以允许空目录的人足够关心这种情况来补救它。在目录中添加文件时会自动添加目录。也就是说,目录永远不必添加到存储库中,并且不会自行跟踪。你可以说“git add

”,它会在那里添加文件。如果您确实需要一个目录存在于结帐中,您应该在其中创建一个文件。 .gitignore 很适合这个目的;您可以将其留空,或填写您希望在目录中显示的文件的名称。

下面的答案要好得多。事实上,低级软件 git 不允许它对我来说并不重要,因为当我需要一个空目录时如何实际使用 Git。添加 2 行 .gitignore 对我来说似乎是可以接受的。

对于这个常见问题,您可以在整个 Internet 上阅读“不可能,您不能,等等。”。 .gitignore 技巧是一个常见的答案,可以满足许多需求。然而有可能让 git track 成为一个真正空的目录,see my answer

虽然我想得越多,就越感觉像“空字符串的 SHA 哈希”,如果它存在,实际上将是一个明确定义的空树标识符,除非无法判断该对象是否是一棵树或一团。

我已经看到很多存储库为此使用了一个名为 .gitkeep 的空文件。

@Amala:当您说“下面”时,您指的是什么。答案的顺序正在改变......

M
Mark Amery

在目录中创建一个名为 .gitkeep 的空文件,然后添加它。

.gitkeep 不是 Git 规定的,它会让人们第二次猜测它的含义,这将引导他们到谷歌搜索,这将引导他们到这里。 .git 前缀约定应保留给 Git 本身使用的文件和目录。

@t-mart“应该保留 .git 前缀约定......”为什么? git 是否请求此预订?

在这种情况下,READMEABOUT 文件会同样好或更好。给下一个人留个便条,就像我们在 URL 之前所做的那样。

如果您正在编写应在空目录上测试代码的单元测试,则不起作用...

@szablica 我认为这根本不会令人困惑。事实上,我认为将其命名为 .gitkeep 非常直观。称它为 .gitignore 对我来说听起来很矛盾。所以这只是个人口味的问题。

W
Will

您始终可以在目录中放置一个 README 文件,并说明您为什么要在存储库中使用此目录,否则为空目录。

+1,好建议,除非将来要使用,否则空目录没有任何意义。所以在里面创建一个 README 文件,写下这个目录是干什么用的,以后会放什么文件。这解决了这两个问题。

@ilius 废话。在许多情况下,可能非常需要包含空目录的目录结构(例如 MVC 应用程序,您需要一个模型目录但尚未开始创建任何模型,或者您计划稍后添加共享视图的共享视图目录)。此外,在其中的每一个中都放一个 README 是多余的,因为它们的用途很明显,而且很容易忘记在每个中都放一个 README。并且当您向其中添加一些其他文件时,您必须记住删除自述文件。基本上,git 绝对应该允许空目录。

@Jez:我不同意。关键是 git 旨在控制(和索引)源代码。重要的是,提交的 id 是内容的散列。也就是说,它必须有内容。树的每个部分都不需要自述文件,只需要叶节点。如果您有打算放置代码的地方,但没有代码,并且您甚至不会花时间回显“模型的地方”>>自述文件,那么您所拥有的只是一个想法而不是提交。对 git 不感兴趣。说“我希望正在运行的应用程序有 XYZ 空目录”是运行时问题,而不是源问题。与您的安装人员一起处理它。

@JoeAtzberger 这是一个缺失的功能,而不是有意的限制。来自 Git 常见问题解答:目前 Git 索引(暂存区)的设计只允许列出文件,并且没有足够能力进行更改以允许空目录的人足够关心这种情况来补救它。

@jbo5112 是的,您指的“特殊代码”是我提到的“安装程序”。您的 webapp 安装已经必须处理创建数据库、本地配置、拉取依赖项或 100 个其他操作,但是几个空目录超出了它的范围?尝试 gradle、passenger、chef、原始 Makefile 等。创建目录和安装应用程序的其他(可能更复杂/危险)工作之间没有安全差异。如果你真的没有 deps、config、DB 等,也没有安装程序,那么只需使用 README。没有任何情况要求您两者都做。

A
Asclepius
touch .placeholder

在 Linux 上,这会创建一个名为 .placeholder 的空文件。值得一提的是,这个名称对 git 来说是不可知的,并且这种方法用于系统中的其他各个地方,例如 /etc/cron.d/.placeholder。其次,正如另一位用户所指出的,.git 前缀约定可以保留给 Git 本身用于配置目的的文件和目录。

或者,如另一个 answer 中所述,目录可以包含描述性 README.md file

无论哪种方式,这都要求文件的存在不会导致您的应用程序中断。

这对于初始的裸目录很有用,但是如果它开始充满文件怎么办?然后 Git 会注意到它们并将它们声明为未跟踪的文件。此处选择的答案更优雅地工作,以允许保留目录但随后安全地忽略内容。

问题和主要的普遍关注是关于添加一个空目录。如果它以后有一个常驻文件,显然删除 .keep 文件或忽略它。相反,如果要忽略目录中的文件,那将是一个完全不同的问题。

建议 git clean -nd | sed s/'^Would remove '// | xargs -I{} touch "{}.keep" 在所有未跟踪的空目录中执行此操作。

不喜欢这个解决方案,很难猜出这个文件的作用。此外,如果您在开发环境中生成文件(如日志或图像等),这并不能阻止这些文件被版本化并进入生产环境,这并不好。

优雅:.keep 文件连同提交消息 显示了“保留”项目结构的意图。添加自述文件或关于我认为会引起更多混乱...

M
Manu Manjunath

为什么我们需要空的版本化文件夹

第一件事:

在 Git 版本控制系统下,空目录不能是树的一部分。

它根本不会被跟踪。但是在某些情况下,“版本控制”空目录可能是有意义的,例如:

搭建预定义的文件夹结构,使其可供存储库的每个用户/贡献者使用;或者,作为上述的特殊情况,为临时文件创建一个文件夹,例如 cache/ 或 logs/ 目录,我们希望在其中提供文件夹但 .gitignore 其内容

与上述相关,某些项目在没有某些文件夹的情况下将无法工作(这通常暗示项目设计不佳,但这是一个常见的现实场景,也许可能存在需要解决的权限问题)。

一些建议的解决方法

许多用户建议:

放置一个 README 文件或另一个包含某些内容的文件以使目录非空,或者使用一种“反向逻辑”(即包含所有文件)创建一个 .gitignore 文件,最后服务于方法#1的相同目的。

虽然这两种解决方案都有效,但我发现它们与有意义的 Git 版本控制方法不一致。

为什么你应该在你的项目中放置你可能并不真正想要的伪造文件或自述文件?

为什么要使用 .gitignore 来做与它的用途(不包括文件)完全相反的事情(保存文件),即使它是可能的?

.gitkeep 方法

使用名为 .gitkeepempty 文件以强制该文件夹存在于版本控制系统中。

虽然看起来差别不大:

您使用的文件仅用于保存文件夹。你不要放任何你不想放的信息。例如,您应该使用自述文件作为包含有用信息的自述文件,而不是作为保留文件夹的借口。关注点分离总是一件好事,您仍然可以添加 .gitignore 来忽略不需要的文件。

将其命名为 .gitkeep 可以从文件名本身(以及其他开发人员,这对于共享项目和 Git 存储库的核心目的之一)来说非常清晰和直接,该文件是与代码无关的文件(由于前导点和名称)与 Git 明确相关的文件其目的(保留)已明确说明且一致且语义相反,其含义可忽略

与代码无关的文件(因为前导点和名称)

与 Git 明显相关的文件

它的目的(保持)被清楚地陈述并且在其含义上是一致的和语义上相反的以忽略

采用

我已经看到 LaravelAngular-CLI 等非常重要的框架采用了 .gitkeep 方法。

您错过了一个想法 - 保留和清空文件夹(例如 /logs、/tmp、/uploads)的原因是什么?是的 - 它保持文件夹为空。 :) 因此,如果您想保持文件夹为空,则必须忽略其中的文件。

@RomanAllenstein:不一定。可能是您创建了一个具有给定结构的存储库,以后可以填充该结构。这些文件将在创建后立即添加到存储库中,开始删除或编辑 .gitignore 文件会很烦人(而且很危险,因为您可能甚至没有意识到它们没有被跟踪:git 忽略了它们)

如果您编辑答案以将 .gitkeep 替换为任何其他非 git 前缀的文件名,您会得到我的支持,我认为这是最好和最有用的答案。原因:我认为“.git*”应该保留给 git 规定的文件,而这只是一个占位符。当我看到它时,我的第一个猜测是,例如“.gitkeep”文件会被自动忽略(这将是一个不错的功能),但事实并非如此,对吧?

@Santosh您可以编辑我的帖子并对社区有用,而不是幼稚地吹嘘非母语人士并无用地污染评论,这与平均智能行为[IN]一致。这就是编辑的原因,顺便说一句。无论如何感谢您的免费课程,非常感谢:)

我想知道为什么人们很难理解为什么要向 git 添加“空”文件夹。你必须从某个地方开始,对吧?所以,通常你从你的项目文件夹结构开始 - 唉 - 在项目开始时还没有任何东西。一旦你的项目 repo 完成,团队工作人员可以克隆并开始使用 SAME 结构。

P
Peter Mortensen

如其他答案中所述,Git 无法在其暂存区域中表示空目录。 (请参阅 Git FAQ。)但是,如果出于您的目的,如果一个目录仅包含一个 .gitignore 文件就足够空,那么您只能通过以下方式在空目录中创建 .gitignore 文件:

find . -type d -empty -exec touch {}/.gitignore \;

您可能想忽略 .git 目录:find . -name .git -prune -o -type d -empty -exec touch {}/.gitignore \;

对于大多数情况,一个更简单的变体是 find * -type d -empty -exec touch {}/.gitignore \;

由于 OS X 几乎在每个目录中都创建了一个 .DS_Store 文件,因此这在那里不起作用。我发现的唯一(危险!)解决方法是首先通过 find . -name .DS_Store -exec rm {} \; 删除所有 .DS_Store 文件,然后使用此答案中的首选变体。请务必仅在正确的文件夹中执行此操作!

有谁知道从命令行在 Windows 中执行此操作的方法?我在 Ruby 和 Python 中看到了一些解决方案,但如果可以管理,我想要一个准系统解决方案。

@akhan 向 .gitignore 添加内容对 find 命令的 -empty 标志没有影响。我的评论是关于删除目录树中的 .DS_Store 文件,因此可以应用 -empty 标志。

P
Peter Mortensen

Andy Lester 是对的,但如果您的目录只是需要为空,而不是 empty 为空,您可以在其中放置一个空的 .gitignore 文件作为解决方法。

顺便说一句,这是一个实现问题,而不是基本的 Git 存储设计问题。正如 Git 邮件列表中多次提到的那样,之所以没有实施,是因为没有人足够关心为它提交补丁,而不是它不能或不应该完成。

r
rogerdpack

Ruby on Rails日志文件夹创建方式:

mkdir log && touch log/.gitkeep && git add log/.gitkeep

现在日志目录将包含在树中。它在部署时非常有用,因此您不必编写例程来创建日志目录。

可以通过发出将日志文件排除在外,

echo log/dev.log >> .gitignore

但你可能知道。

这与 Ruby on Rails 有什么关系?

@QuolonelQuestions github.com/rails/rails/blob/master/activerecord/test/migrations/…

它现在已重命名为 .keep github.com/rails/rails/blob/main/activerecord/test/migrations/…

L
Lesmana

Git 不跟踪空目录。有关详细说明,请参阅 Git FAQ。建议的解决方法是将 .gitignore 文件放在空目录中。我不喜欢那个解决方案,因为 .gitignore 被 Unix 约定“隐藏”了。也没有解释为什么目录是空的。

我建议在空目录中放一个 README 文件,解释为什么该目录是空的以及为什么需要在 Git 中对其进行跟踪。有了 README 文件,就 Git 而言,目录不再是空的。

真正的问题是为什么你需要 git 中的空目录?通常你有某种构建脚本可以在编译/运行之前创建空目录。如果没有,那就做一个。这比将空目录放在 git 中要好得多。

所以你有一些理由在 git 中需要一个空目录。把这个原因放在 README 文件中。这样其他开发人员(以及未来的你)就知道为什么需要有空目录。您还将知道,当需要空目录的问题解决后,您可以删除空目录。

要列出每个空目录,请使用以下命令:

find -name .git -prune -o -type d -empty -print

在每个空目录中创建占位符自述文件:

find -name .git -prune -o -type d -empty -exec sh -c \
  "echo this directory needs to be empty because reasons > {}/README.emptydir" \;

要忽略目录中除 README 文件之外的所有内容,请将以下行放入您的 .gitignore

path/to/emptydir/*
!path/to/emptydir/README.emptydir
path/to/otheremptydir/*
!path/to/otheremptydir/README.emptydir

或者,您可以排除每个 README 文件被忽略:

path/to/emptydir/*
path/to/otheremptydir/*
!README.emptydir

要在创建后列出每个 README:

find -name README.emptydir
P
Peter Mortensen

警告:事实证明,这个调整并没有真正起作用。带来不便敬请谅解。

原帖如下:

我在玩 Git 内部时找到了一个解决方案!

假设您在存储库中。创建空目录: $ mkdir path/to/empty-folder 使用管道命令和空树 SHA-1 将其添加到索引中: $ git update-index --index-info 040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 path/to/empty-文件夹 键入命令,然后输入第二行。按 Enter,然后按 Ctrl + D 终止输入。注意:格式为模式 [SPACE] 输入 [SPACE] SHA-1hash [TAB] 路径(制表符很重要,答案格式不保留)。而已!您的空文件夹在您的索引中。你所要做的就是承诺。

这个解决方案很短,显然工作正常(见编辑!),但它不是那么容易记住......

可以通过创建一个新的空 Git 存储库来找到空树 SHA-1,将 cd 放入其中并发出 git write-tree,它会输出空树 SHA-1。

编辑:

自从我找到这个解决方案以来,我一直在使用它。它的工作方式似乎与创建子模块完全相同,只是没有在任何地方定义模块。这会在发出 git submodule init|update 时导致错误。问题是 git update-index040000 tree 部分重写为 160000 commit

此外,放置在该路径下的任何文件都不会被 Git 注意到,因为它认为它们属于某个其他存储库。这很讨厌,因为它很容易被忽视!

但是,如果您还没有(也不会)在存储库中使用任何 Git 子模块,并且“空”文件夹将保持为空,或者如果您希望 Git 知道它的存在并忽略它的内容,您可以使用这个调整。采用子模块的常规方式需要更多的步骤来进行调整。

将空文件夹放入索引并提交后,是否可以git svn dcommit获得所需的结果?

此调整不太可能与任何其他工具一起使用。就像警告和编辑中所述,我不鼓励使用它,除非在非常有限的情况下。

基于此,我创建了一个没有这些缺点的更好的解决方案:stackoverflow.com/a/58543445/277882

G
GAMITG

假设您需要一个名为 tmp 的空目录:

$ mkdir tmp
$ touch tmp/.gitignore
$ git add tmp
$ echo '*' > tmp/.gitignore
$ git commit -m 'Empty directory' tmp

换句话说,您需要将 .gitignore 文件添加到索引中,然后才能告诉 Git 忽略它(以及空目录中的所有其他内容)。

两件事:您可以只“echo '*' > tmp/.gitignore”而不是触摸,并且“git commit -m”不会在您将文件添加到索引后提交所做的更改。

如果您只执行 echo bla > file,您将不会得到 file: File exists,因为如果文件已经存在,> 将覆盖该文件,如果文件不存在则创建一个新文件。

/bin/sh 文化假设!* 如果“这里”是 csh 并且设置了变量 noclobber,那么您确实会得到 file: File exists。如果有人说“我明白了”,不要以为他们是白痴并回答“不,你没有”。 * c2.com/cgi/wiki?AmericanCulturalAssumption

@clacke 如果有人决定使用与其他人不同的外壳,他们应该在遇到问题时明确说明。与国籍不同,每个人都可以自由选择贝壳。

@SeldomNeedy 也许他们正在寻求帮助,因为他们甚至不知道他们使用的外壳与其他人不同。

B
Brent Bradburn

也许添加一个空目录似乎是阻力最小的路径,因为您有脚本期望该目录存在(可能是因为它是生成的二进制文件的目标)。另一种方法是修改脚本以根据需要创建目录。

mkdir --parents .generated/bin ## create a folder for storing generated binaries
mv myprogram1 myprogram2 .generated/bin ## populate the directory as needed

在此示例中,您可能会签入到目录的(损坏的)符号链接,以便您可以在没有“.generated”前缀的情况下访问它(但这是可选的)。

ln -sf .generated/bin bin
git add bin

当你想清理你的源代码树时,你可以:

rm -rf .generated ## this should be in a "clean" script or in a makefile

如果您采用通常建议的方法来签入一个几乎是空的文件夹,那么在不删除“.gitignore”文件的情况下删除内容的复杂性很小。

您可以通过将以下内容添加到根 .gitignore 来忽略所有生成的文件:

.generated

注意:我建议的符号链接在干净的结帐中“损坏”,因为 .generated 目录最初不存在。一旦您进行构建,它将不再被破坏。

我同意在某些情况下这是一个非常好的主意,但在其他情况下(例如分发一个项目,其中您有一个带有诸如 models/ 和 views/ 等文件夹的空骨架)您希望用户手头有这些目录而不是与手动阅读文档相比,期望他们在克隆存储库后运行某种安装脚本可能有点过分。我认为这个答案与@john-mee 的 README 答案结合起来应该涵盖大多数情况,如果不是全部的话。

v
vidur punj

在该目录中添加一个 .gitkeep 文件并提交它。

touch .gitkeep 

它是 git 遵循的标准。

M
Mig82

我喜欢 @Artur79 和 @mjs 的答案,所以我一直在使用两者的组合,并将其作为我们项目的标准。

find . -type d -empty -exec touch {}/.gitkeep \;

但是,我们只有少数开发人员在 Mac 或 Linux 上工作。在 Windows 上做了很多工作,我找不到一个等效的简单单线来完成同样的工作。有些人很幸运因为其他原因安装了 Cygwin,但仅仅为此而开出 Cygwin 似乎有点过头了。

编辑以获得更好的解决方案

因此,由于我们的大多数开发人员已经安装了 Ant,我想到的第一件事就是将 Ant 构建文件放在一起,以独立于平台完成此任务。这仍然可以找到here

不过,后来我觉得把它做成一个小实用命令会更好,所以我用 Python 重新创建了它,并将它发布到 PyPI here。您可以通过简单地运行来安装它:

pip3 install gitkeep2

它允许您递归地创建和删除 .gitkeep 文件,还允许您向它们添加消息,以便您的同行了解这些目录为何重要。最后一点是奖金。我认为如果 .gitkeep 文件可以是自记录的,那就太好了。

$ gitkeep --help
Usage: gitkeep [OPTIONS] PATH

  Add a .gitkeep file to a directory in order to push them into a Git repo
  even if they're empty.

  Read more about why this is necessary at: https://git.wiki.kernel.org/inde
  x.php/Git_FAQ#Can_I_add_empty_directories.3F

Options:
  -r, --recursive     Add or remove the .gitkeep files recursively for all
                      sub-directories in the specified path.
  -l, --let-go        Remove the .gitkeep files from the specified path.
  -e, --empty         Create empty .gitkeep files. This will ignore any
                      message provided
  -m, --message TEXT  A message to be included in the .gitkeep file, ideally
                      used to explain why it's important to push the specified
                      directory to source control even if it's empty.
  -v, --verbose       Print out everything.
  --help              Show this message and exit.

希望对你有帮助。

对于它的价值,Windows Powershell 单线可能是ls -r -dir | ?{$_.getFileSystemInfos().Count -eq 0} | %{ni -p $_.FullName -n .gitkeep}

G
GAMITG

你不能,不幸的是永远也不能。这是 Linus Torvald 自己做出的决定。他知道什么对我们有好处。

我读过一次的地方有一篇咆哮。

我找到了 Re: Empty directories..,但也许还有另一个。

你必须忍受这些变通方法......不幸的是。

我知道您将此作为错误论点的示例发布,但我很欣赏该链接,因为它实际上是反对跟踪目录的合理论点。 ;-)

这个答案似乎不一致,因为在引用线程的下一篇文章中,Linus Torvald 说他希望他们需要添加目录跟踪:markmail.org/message/libip4vpvvxhyqbl。事实上,他说他“会欢迎 [添加对跟踪空目录的支持] 的补丁”

帕特里克,他在那里也使用了“白痴”这个词。我怀疑他的措辞是针对这个线程中的人们的,所以我认为他不会自己在 Git 中实现一些“白痴”的东西。

佚名

我也一直面临空目录的问题。使用占位符文件的问题是,如果不再需要它们,您需要创建它们并删除它们(因为后来添加了子目录或文件。使用大型源树管理这些占位符文件可能很麻烦并且会出错易于。

这就是为什么我决定编写一个开源工具来自动管理此类占位符文件的创建/删除。它是为 .NET 平台编写的,可在 Mono(.NET for Linux)和 Windows 下运行。

看看:http://code.google.com/p/markemptydirs

D
DevonDahon

这个解决方案对我有用。

1. 将 .gitignore 文件添加到您的空目录:

*
*/
!.gitignore

* 忽略文件夹中的所有文件

*/ 忽略子目录

!.gitignore 包含 .gitignore 文件

2. 然后删除缓存,暂存文件,提交并推送:

git rm -r --cached .
git add . // or git stage .
git commit -m ".gitignore fix"
git push

这很棒。我曾经在主 .gitignore 中执行 .gitkeep 文件和类似的几行,但我更喜欢这个。只是看起来更像 git-y。谢谢。

G
GAMITG

添加 .gitignore 文件时,如果要在其中放入任意数量的内容(您希望 Git 忽略),您可能需要添加仅带有星号 * 的单行,以确保您没有t 意外添加被忽略的内容。

n
ntninja

阅读 @ofavre@stanislav-bashkyrtsev 的答案,使用损坏的 GIT 子模块引用来创建 GIT 目录,我很惊讶没有人建议对这个想法进行简单的修改,以使整个事情变得理智和安全:

与其将伪造的子模块入侵到 GIT 中,不如添加一个空的真实子模块。

输入:https://gitlab.com/empty-repo/empty.git

一个只有一次提交的 GIT 存储库:

commit e84d7b81f0033399e325b8037ed2b801a5c994e0
Author: Nobody <none>
Date: Thu Jan 1 00:00:00 1970 +0000

没有消息,没有提交的文件。

用法

向您的 GIT 存储库添加一个空目录:

git submodule add https://gitlab.com/empty-repo/empty.git path/to/dir

要将所有现有的空目录转换为子模块:

find . -type d -empty -delete -exec git submodule add -f https://gitlab.com/empty-repo/empty.git \{\} \;

Git 将在创建子模块引用时存储最新的提交哈希,因此您不必担心我(或 GitLab)使用它来注入恶意文件。不幸的是,我没有找到任何方法来强制在结帐期间使用哪个提交 ID,因此您必须在添加存储库后使用 git submodule status 手动检查参考提交 ID 是否为 e84d7b81f0033399e325b8037ed2b801a5c994e0

仍然不是本机解决方案,但我们可能拥有最好的解决方案,而无需有人真正、非常肮脏地使用 GIT 代码库。

附录:重新创建此提交

您应该能够使用(在一个空目录中)重新创建这个确切的提交:

# Initialize new GIT repository
git init

# Set author data (don't set it as part of the `git commit` command or your default data will be stored as “commit author”)
git config --local user.name "Nobody"
git config --local user.email "none"

# Set both the commit and the author date to the start of the Unix epoch (this cannot be done using `git commit` directly)
export GIT_AUTHOR_DATE="Thu Jan 1 00:00:00 1970 +0000"
export GIT_COMMITTER_DATE="Thu Jan 1 00:00:00 1970 +0000"

# Add root commit
git commit --allow-empty --allow-empty-message --no-edit

创建可重现的 GIT 提交非常困难……

Z
Zaz

没有办法让 Git 跟踪目录,因此唯一的解决方案是在您希望 Git 跟踪的目录中添加一个占位符文件。

该文件可以命名并包含您想要的任何内容,但大多数人使用名为 .gitkeep 的空文件(尽管有些人更喜欢与 VCS 无关的 .keep)。

前缀 . 将其标记为隐藏文件。

另一个想法是添加一个 README 文件来解释目录的用途。

G
GAMITG

如前所述,不可能添加空目录,但这是一个将空 .gitignore 文件添加到所有目录的衬里。

ruby -e 'require "fileutils" ; Dir.glob(["target_directory","target_directory/**"]).each { |f| FileUtils.touch(File.join(f, ".gitignore")) if File.directory?(f) }'

为了方便访问,我将它保存在 Rakefile 中。

我宁愿使用 find . -type d -empty -print0 | xargs --null bash -c 'for a; do { echo "*"; echo "!.gitignore"; } >>"$a/.gitignore"; done' --

C
Community

许多人已经回答了这个问题。只需在此处添加 PowerShell 版本。

找到目录中的所有空文件夹在其中添加一个空的 .gitkeep 文件

Get-ChildItem 'Path to your Folder' -Recurse -Directory | Where-Object {[System.IO.Directory]::GetFileSystemEntries($_.FullName).Count -eq 0} | ForEach-Object { New-Item ($_.FullName + "\.gitkeep") -ItemType file}

不错。‌‌ ༼ ͡☉ ͜ʖ ͡☉ ༽

另外,ni -p $_.FullName -n .gitignore -v "*`r`n!.gitignore"

C
Community

The solution of Jamie Flournoy 效果很好。这是保留 .htaccess 的一些增强版本:

# Ignore everything in this directory
*
# Except this file
!.gitignore
!.htaccess

使用此解决方案,您可以提交一个空文件夹,例如 /log/tmp/cache,并且该文件夹将保持为空。

他想保留一个空目录而不是文件。

我已经提到它也会保留.htaccess。示例:如果软件有一个不能通过 Web 访问的日志文件目录(如 oxid eshop),则该目录中有一个 .htaccess。如果您将上述 .gitignore 放入文件夹中,则不会提交 .htaccess 并且可以通过 Web 访问该文件夹。

如果您有一个受版本控制的 .htaccess 文件,那么您已经拥有包含它的目录受版本控制。因此,问题已经解决了 - .gitignore 文件变得无关紧要。

@Wallacoloo 与您说得对的问题有关,但是该文件很有用,我将其用于上传目录,例如文件应受.htaccess保护的目录。与罗马人的解释相反,.htaccess 文件将被提交,因为它被忽略规则排除在外。 [旧线程,我知道]

P
Peter Mortensen

我总是构建一个函数来检查我想要的文件夹结构并在项目中为我构建它。这解决了这个问题,因为空文件夹由代理保存在 Git 中。

function check_page_custom_folder_structure () {
    if (!is_dir(TEMPLATEPATH."/page-customs"))
        mkdir(TEMPLATEPATH."/page-customs");    
    if (!is_dir(TEMPLATEPATH."/page-customs/css"))
        mkdir(TEMPLATEPATH."/page-customs/css");
    if (!is_dir(TEMPLATEPATH."/page-customs/js"))
        mkdir(TEMPLATEPATH."/page-customs/js");
}

这是在 PHP 中,但我确信大多数语言都支持相同的功能,并且由于文件夹的创建由应用程序负责,因此文件夹将始终存在。

就这样我们都在同一个页面上,我不再这样做了。这是浪费时间。 .gitkeep 约定是一种更好的做法。

我看不出这怎么会浪费时间。当您的 TEMPLATEPATH 显然是动态的时,您不能使用 .gitkeep 解决方案。即使使用非动态文件夹结构,您也应该添加更多内容,而不是删除检查目录的非常好的解决方案,例如检查权限和 chmod 文件。在全局 .gitignore 中添加一种标记目录的方法对我来说是完美的。 #keep /path/to/dir 之类的东西

P
Peter Mortensen

这是一个 hack,但有趣的是它可以工作(Git 2.2.1)。类似于@Teka 的建议,但更容易记住:

将子模块添加到任何存储库(git submodule add path_to_repo)

这将添加一个文件夹和一个文件 .submodules。提交更改。

删除 .submodules 文件并提交更改。

现在,您有一个在签出提交时创建的目录。有趣的是,如果您查看此文件的树对象的内容,您将得到:

致命:不是有效的对象名称 b64338b90b4209263b50244d18278c0999867193

我不鼓励使用它,因为它可能会在未来的 Git 版本中停止工作。这可能会使您的存储库损坏。

这实际上有效,但我认为这让 IntelliJ 感到困惑......:|

基于此,我创建了一个没有这些缺点的更好的解决方案:stackoverflow.com/a/58543445/277882

a
ajmedway

如果您想添加一个文件夹,该文件夹将在多个语义目录中容纳大量临时数据,那么一种方法是将类似这样的内容添加到您的根 .gitignore ...

/app/data/**/*.* !/app/data/**/*.md

然后,您可以在每个目录中提交描述性 README.md 文件(或空白文件,只要您可以像在这种情况下使用 *.md 一样唯一地定位它们),以确保目录都保留在repo 但文件(带扩展名)被忽略。限制:目录名称中不允许使用 .

您可以使用 xml/images 文件或其他文件填充所有这些目录,并随着时间的推移在 /app/data/ 下添加更多目录,因为您的应用程序需要开发存储空间(其中 README.md 文件用于刻录每个存储空间的描述目录是准确的)。

无需通过为每个新目录创建新的 .gitignore 来进一步更改您的 .gitignore 或去中心化。可能不是最聪明的解决方案,但在 gitignore 方面很简洁,并且总是对我有用。又好又简单! ;)

https://i.stack.imgur.com/xNBNN.png

T
Trendfischer

有时您必须处理糟糕的编写库或软件,它们需要一个“真正的”空目录和现有目录。放置一个简单的 .gitignore.keep 可能会破坏它们并导致错误。在这些情况下,以下内容可能会有所帮助,但不能保证......

首先创建需要的目录:

mkdir empty

然后向该目录添加一个损坏的符号链接(但在上述用例之外的任何其他情况下,请使用带有说明的 README):

ln -s .this.directory empty/.keep

要忽略此目录中的文件,您可以将其添加到您的根目录 .gitignore

echo "/empty" >> .gitignore

要添加忽略的文件,请使用参数强制它:

git add -f empty/.keep

提交后,您的索引中有一个损坏的符号链接,git 会创建目录。断开的链接有一些优点,因为它不是常规文件并且不指向常规文件。所以它甚至适合问题“(不包含文件)”的部分,不是出于意图,而是出于含义,我猜:

find empty -type f

此命令显示一个空结果,因为此目录中不存在任何文件。因此,大多数获取目录中所有文件的应用程序通常看不到这个链接,至少如果他们看到“文件存在”或“可读”。甚至某些脚本也不会在那里找到任何文件:

$ php -r "var_export(glob('empty/.*'));"
array (
  0 => 'empty/.',
  1 => 'empty/..',
)

但我强烈建议仅在特殊情况下使用此解决方案,在空目录中写好 README 通常是更好的解决方案。 (而且我不知道这是否适用于 Windows 文件系统......)

a
arcseldon

一种简单的方法是将 .gitkeep 文件添加到您希望(当前)保持为空的目录中。

有关更多信息,请参阅此 SOF answer - 这也解释了为什么有些人发现添加 .gitignore 文件的竞争约定(如这里的许多答案所述)令人困惑。

J
Jörg W Mittag

你不能。这是 Git 维护人员有意的设计决定。基本上,像 Git 这样的源代码管理系统的目的是管理源代码,而空目录不是源代码。 Git 也经常被描述为内容跟踪器,同样,空目录不是内容(实际上恰恰相反),因此它们不会被跟踪。

我反对这种观点。结构就是内容,你所命名的一切都有助于内容。

空文件也不是源代码或内容。这只是一个名字。然而,Git 会很高兴地跟踪空文件。我不认为让 Git 拒绝跟踪空目录是故意的设计决定。我认为跟踪空目录是一项 99% 的时间根本不需要的功能,因此他们没有费心去做使其正常工作所需的额外工作。如果有人非常想要该功能来实现它,Git 可以做到这一点。我怀疑 Git 维护者是否会反对这样的补丁,如果它做得正确的话。

@TobyAllen 这里是更新后的 FAQ link 最佳答案也是常见问题解答中推荐的内容,其中包含更精确的说明。

这是一个缺失的功能(并且优先级低),而不是有意的限制。来自 Git 常见问题解答:目前 Git 索引(暂存区)的设计只允许列出文件,并且没有足够能力进行更改以允许空目录的人足够关心这种情况来补救它。

真的不同意。我可以找到要跟踪空文件夹的各种原因。例如,我正在为我的项目开发一个非常轻量级的 PHP MVC 框架。我有用于放置模型、视图等的特定文件夹。当我基于我的框架创建一个新站点时,这些文件夹是空的,因为默认情况下没有模型或视图,但我确实需要该文件夹存在,否则我的框架赢了不行!