如何将空目录(不包含文件)添加到Git存储库?
- 虽然这并不有用,但是有一种方法可以将一个空的(真正空的)目录侵入到您的repo中。然而,它不会使用当前版本的git来实现cx1〔0〕。
- @我不同意这没用。您的目录层次结构是项目的一部分,因此它应该是版本控制的。
- @乔本特利,你说得对!很遗憾,Git没有尊重这一部分,但是只要这一部分没有被修复,在存储库中拥有空目录是无用的(注意,当签出时Git也忽略空目录)。
- 在我的例子中,我想为tmp文件添加一个目录结构,而不是tmp文件本身。通过这样做,我的测试人员具有正确的结构(否则会有错误),但是我不会用tmp数据阻塞提交。所以是的,它对我很有用!
- @Adammarshall我认为Tiwo是在说黑客是没有用的,因为它被收银台忽略了。tmp dirs听起来确实是VCS的一个有用功能。
- 为什么不让创建tmp文件的过程也创建tmp目录呢?
- 您可以使用githook或gitattribute过滤器将.deleteme文件添加到repo中,然后在签出时自动删除该文件。但是,它可能会破坏git commit -a,并可能在每次结账时触发……
- 对我来说,超过1000的投票数表明这个特性应该在Git中,就像在SVN中一样。接下来,我知道至少有一个软件产品期望某个文件夹结构存在,即使其中一些文件夹实际上是空的。如果我把一个.whatever文件放在那个文件夹中,这个文件将成为我项目的一个(不需要的)部分,因为这就是MF的工作方式。这对简历来说真的很痛苦,我真的希望这些黑暗的日子能被遗忘很久。
- @Jensg 1000的加分意味着1000人认为这个问题很有用。即使他们都想要这个特性,这并不意味着应该实现它——有多少Git用户?
- 具有讽刺意味的是,尽管Git总是试图做与cvs相反的事情,但最终却做了我在cvs中觉得很烦人的事情。
- 哈哈哈,我喜欢这个…这就是为什么你雇佣用户体验人员的原因。让顽固的程序员要求黑客为面向公共的工具添加空目录…"但你不懂这个工具!"是的,你不明白人们(想)如何使用你的产品。
- 对于那些认为这不是一个有用功能的人,我会提出一个挑战性的问题:当用户签出东西时,我有一个/temp目录需要在那里。如果没有,我使用的软件包就不会创建它。如果不是让Git识别一个空目录,我该怎么做呢?
- 有时这对我来说是必要的,例如在编译了.js或.css的文件夹中。
- @Jhtan是的
- 不能。只需在目录中创建一个空文件,如.keep。
- 我建议将其添加到主要解决方案中:stackoverflow.com/a/21422128/1670956
另一种使目录保持(几乎)空白(在存储库中)的方法是在包含这四行的目录中创建一个.gitignore文件:
1 2 3 4
| # Ignore everything in this directory
*
# Except this file
!.gitignore |
那么,您不必像处理M104的解决方案那样正确地获得订单。
这还提供了这样的好处:当您执行git状态时,该目录中的文件不会显示为"未跟踪"。
使@greenasjade的评论坚持不懈:
I think it's worth noting that this solution does precisely what the question asked for, but is not perhaps what many people looking at this question will have been looking for. This solution guarantees that the directory remains empty. It says"I truly never want files checked in here". As opposed to"I don't have any files to check in here, yet, but I need the directory here, files may be coming later".
- 不需要放任何东西进去。GitIgnore。只需空签入。gitignore。将来可能会填充许多文件夹,此答案中的方法将永远不会添加任何文件。所以我会非常谨慎地使用这个答案的方法。
- @实际上,greenasjade并没有完全按照要求执行,因为目录不是空的。正如其他用户所说,以"git"作为前缀是一个坏主意,因为它会误导用户——这不是一个"git感知"策略。
- 尽管添加.gitignore确实可以保证目录保持为空,但只要有文件要提交,就可以删除.gitignore。这很简单也很容易。
- 这是解决这个问题的最佳方案,因为按设计,Git不允许您存储空文件夹,并且.GitIgnore可以确保它保持为空。
- @绿色翡翠是一个很好的观点,但有时这正是需要的。在我的例子中,这是针对WordPress插件的缓存文件夹(需要存在错误,否则会抛出错误,但您永远不想提交任何缓存文件)。
- @绿色翡翠什么?对于所有的意图和目的来说,它绝对不是一个空目录!例如,如果python脚本在文件夹中查找文件,它将看到这个文件,为什么存在.gitignore文件可能会产生显著的差异。
- 我认为@johnee提出的readme解决方案应该与这个解决方案一起使用,.gitignore文件提供了一个关于我们想要避免的版本控制之外的内容的解释,而readme文件解释了目录的用途,这两个部分都是非常重要的信息。
- @Pedromanoel我把你要放在README文件中的文件写在.gitignore文件中(作为注释)。
- "只添加自述文件"解决方案的问题是,应用程序多次下降到目录中,并设置(临时)文件中的值,这些文件放在这个原本是空的目录中。我喜欢强迫Git保持空白的想法,因为这可能是应用程序想要/需要的。
- 这对于不想签入任何二进制文件但不想让用户手动创建文件夹(以防生成系统无法处理)的源代码外生成非常有用。
- 找出1个不同点:1.)一个空文件夹,2.)一个包含.gitignore文件的文件夹。;-)
- @卡洛坎普德也来这里说这个!我把一个.gitignore放在一个空目录中,其中有一个注释"这个空目录需要签入git"。当你真的想把一些东西放到目录中,而忘记你的聪明的时候,这个答案可能会带来问题。
- @greenasjade后者更像是一个.gitkeep用例。
- 这非常适合缓存文件夹。
- 从技术上讲,这不是一个空目录…
- 好的建议——不需要忽略文件本身——要么创建文件并强制添加(echo"*"> .gitignore; git add -f .gitignore;),要么添加文件并编辑它(`touch.git ignore;git add.git ignore;echo"*">.git ignore)。这会删除一些无意义的"但不要忽略.gitignore"规则。
- @格林纳斯杰德,如果我理解正确的答案,这并不完全符合行动计划的要求。这将创建一个包含一个文件的目录,而不是一个空目录。在我的例子中,我想要一个空目录。
- "回购中为空"。在您的工作副本中,是的,您有.gitignore文件。大多数人都认为.git某些文件在工作目的上是"不存在的":即,出于所有意图和目的,它被认为是一个空目录。
- 这就是我需要的。谢谢。我只需要一个"日志"文件夹来放置日志文件,但我不想在Git中添加任何这些日志文件。如果目录不存在,PHP会抛出一个错误。
- 不幸的是,这会导致一个非空目录,它只有一个隐藏文件。
- @greenasjade,但稍后添加文件时,您可能希望删除此占位符.gitignore。当你这样做的时候,文件会被跟踪。我不是说你的观点是错误的,只是一个真正的边缘案例。
- 通常,目录的要点是包含文件。如果您想将一个空目录添加到存储库中,它最终可能会包含文件,至少在其中一个存储库中或发布中是如此。但您可能不希望这些文件成为存储库的一部分,否则它可能已经包含一个或多个这些文件,或者您可以等到添加它们。因此,对于在存储库中需要一个"空"目录的主要情况,这个解决方案是完美的。
不能。请参阅Git常见问题解答。
Currently the design of the git index
(staging area) only permits files to
be listed, and nobody competent enough
to make the change to allow empty
directories has cared enough about
this situation to remedy it.
Directories are added automatically
when adding files inside them. That
is, directories never have to be added
to the repository, and are not tracked
on their own.
You can say"git add " and it
will add files in there.
If you really need a directory to
exist in checkouts you should create a
file in it. .gitignore works well for
this purpose; you can leave it empty,
or fill in the names of files you
expect to show up in the directory.
- 下面的答案更好。低层软件Git不允许这样做的事实对我来说和当我需要一个空目录时如何实际使用Git没什么关系。添加2行。GitIgnore对我来说似乎是可以接受的。
- 如果你想把文件移到一个新目录中,他们不能通过git mv来移动,因为git会抱怨新目录不在版本控制之下
- 对于这个常见的问题,你可以在互联网上阅读"不可能,你不能,等等"。.gitignore技巧是一个常见的答案,可以满足许多需求。不过,可以让git跟踪一个真正空的目录,请看我的答案。
- 尽管我越想它,它就越像"空字符串的sha hash",如果它存在的话,它实际上就是一个空树的定义良好的标识符,除非它不可能分辨出对象是树还是一个blob。
- 感谢您添加常见问题解答的摘录。它完美地回答了我最近提出的一个问题。.gitignore提供了一个比我刚添加了一个空文件更好的选项。至少.gitignore更能说明目的。
- 我见过很多回购协议都使用一个名为.gitkeep的空文件来实现这一目的。
- 试图在我的目录中添加文件然后提交,但是Git说Error:pathspec 'app/src/someDir/.gitkeep' did not match any file(s) known to git.有什么想法吗?
- 啊,这太令人沮丧了,Git无法正确处理空目录!我在丑陋的.gitkeep中进行黑客攻击,但我也需要排除所有文件,所以我必须排除.gitkeep。如此丑陋的黑客应该是简单的…
- @阿玛拉:你说"下面"是指什么?答案的顺序正在改变…
在目录中创建一个名为.gitkeep的空文件,并添加该文件。
- 我增加了一个鼓励创建.keep的答案。
- Git还没有规定.gitkeep,它将让人们对它的意义进行第二次猜测,这将导致他们进入谷歌搜索,谷歌搜索将引导他们来到这里。应为git本身使用的文件和目录保留.git前缀约定。
- @T-Mart"应该保留.git前缀约定…"为什么?Git要求预约吗?
- 没有。关键是它可能会令人困惑。
- 在这种情况下,README或ABOUT文件将同样好或更好。给下一个家伙留个便条,就像我们以前在URL之前做的那样。
- 如果编写的单元测试应该在空目录上测试代码,则不起作用…
- @我觉得这一点都不令人困惑。事实上,我认为称之为GitKeep非常直观。我觉得这听起来很矛盾。所以这只是个人品味的问题。
- @苏布丽卡,每件事都会让人困惑&175;()175;
- 使用.keep的理由很好。在简单和不容易混淆之间取得良好的平衡。另一个答案stackoverflow.com/a/21422128/832230如果您采用了.gitkeep习惯,请在您的存储库中运行它:git mv .gitkeep .keep。
您可以将一个自述文件放在目录中,并解释为什么要将这个目录(否则为空)放在存储库中。
- +1,好建议,空目录没有任何意义,除非将来使用。因此,在其中创建一个自述文件,并写下这个目录的用途以及将来要放在那里的文件。这就解决了两个问题。
- 我同意。空文件夹很烦人,应该在所有正确处理的任何类型的存储库中解释。
- @伊利厄斯胡说八道。在许多情况下,包含空目录的目录结构可能是非常理想的(比如MVC应用程序,您需要一个模型目录,但还没有开始创建任何模型,或者您计划稍后向其中添加共享视图的共享视图目录)。此外,在每一个文件中放入一个自述文件是多余的,因为很明显它们是用来做什么的,而且很容易忘记在每一个文件中放入一个自述文件。在添加其他文件时,必须记住删除自述文件。基本上,Git应该绝对允许空目录。
- :s/empty/non-existent
- @杰兹:我不同意。重点是Git被设计用来控制(和索引)源代码。重要的是,提交的ID是内容的散列。也就是说,它必须有内容。树的每个部分不需要自述,只需要叶节点。如果您有想要放置代码的地方,但没有代码,而且您甚至不会花时间回送"place for models">>自述,那么您拥有的是一个想法而不是提交。Git对此不感兴趣。说"我希望运行中的应用程序有XYZ空目录"是一个运行时问题,而不是源代码问题。用你的安装人员来处理。
- @Joeatzberger Web应用程序呢?当目录丢失时,是否应该授予Web/Application Server创建目录的权限?这是一个强大的安全问题,也是一个需要不断检查的小性能问题。除了Git克隆之外,我是否应该创建一个需要特殊代码运行(例如,创建缓存文件夹)的Web应用程序?现在,我需要添加一个自述文件、一个安装脚本和时间来处理那些不需要查看任何内容的人,希望它能正常工作。有时没有文件的目录树在构建/安装过程中也会用到。
- @Joeatzberger这是一个缺失的特性,不是有意的限制。Git常见问题解答:目前,Git索引(临时区域)的设计只允许列出文件,而且没有人有足够的能力进行更改以允许空目录,他们已经足够关心这种情况来解决它。
- @JBO5112是的,您所指的"特殊代码"是我提到的"安装程序"。您的webapp安装已经需要处理创建数据库、本地配置、拉取依赖项或100个其他操作,但是有几个空目录超出了它?尝试Gradle、Passenger、Chef、一个原始makefile等。在创建目录和安装应用程序的其他(可能更复杂/危险)工作之间没有安全区别。如果您真的没有DEPS、CONFIG、DB等,也没有安装程序,那么就使用自述文件。任何情况下都不需要你同时这么做。
- 你的FAQ引文说这是设计。它描述代码的当前状态(不包括该特性)。它还提到了所有的Git贡献者,他们中没有一个足够关心改变它。我想说的是,这也比任何功能愿望书更能体现他们的"意图"。你可能会想到那些写了世界上最好的版本控制的人,那就是我们可以自由享受的人:他们疯了吗?意思是?无能的?或者他们可能只是以不同的方式理解这一点?
- @Joeatzberger在我看来,它是一个缺失的特性,对于维护人员来说还不够重要,因为它需要大量的重新设计。记住,Git是由LinusTorvalds在2周内构建和部署的,因为他对现有的版本控制感到失望。如果这是他们打算忽略的功能,那么FAQ可能会说这是故意不允许的,或者"永久性地设计Git索引",而不是在邮件列表上讨论如何实现"当前设计"以外的功能。
- 我的Web应用程序案例是,多个短期开发人员正在提取/克隆代码并访问同一个数据库(不理想,但我有理由)。它没有安装程序;没有DEPS、配置等管理;没有自述文件。它必须先稳定并产生更多的安装。有时代码会被推送到生产中。在一个单独的项目中,我有一个服务器代码,它创建了一个冗长的目录结构(没有文件),对新客户帐户具有一些复杂的权限。通过管理模板副本而不是代码,这将更容易维护。厨师太过分了,没有其他的帮助。
- @jez为什么要删除自述文件?除了根目录外,目录中的自述文件非常有用,特别是当存储库位于GitHub上时,它会自动在每个目录中显示自述文件。
- 我建议将名为PLACEHOLDER的文件而不是README的文件用于子目录。
- 这是我最终决定的路线,当我看到人们谈论这一点时,我想到了这一点。它用于保存像lib和obj这样的文件夹,这是我构建过程的一部分。好吧,对于其他开发人员来说,自述是多余的,但是对于刚开始的人来说,当我开始自述时,我肯定会从中受益。我认为这取决于项目及其使用方式。
- 可能还有一个关于文件夹将包含的文件类型的描述。
在Linux上,这将创建一个名为.keep的空文件。这个名字比.gitkeep更受欢迎,因为前者对git不可知,后者对git是特定的。其次,正如另一位用户所指出的,应该为Git本身使用的文件和目录保留.git前缀约定。
或者,如另一个答案所述,目录可以包含描述性的README或README.md文件。
当然,这要求文件的存在不会导致应用程序中断。
- 这对于一个初始的裸目录很好,但是如果它开始填充文件呢?然后Git会注意到它们并将它们作为未跟踪的文件来声明。这里选择的答案可以更优雅地工作,允许保留一个目录,然后安全地忽略内容。
- 问题和主要的普遍关注是添加一个空目录。如果以后它有一个常驻文件,显然删除.keep文件,或者忽略它。如果要忽略目录中的文件,则完全是另一个问题。
- 有人建议,git clean -nd | sed s/'^Would remove '// | xargs -I{} touch"{}.keep"将在所有未跟踪的空目录中执行此操作。
- 不喜欢这个解决方案,很难猜测这个文件的作用。此外,如果您正在开发环境中生成文件(如日志或图像等),这不会阻止这些文件被版本控制并进入生产环境,这并不好。
- Windows不喜欢没有名字的文件,并且需要特殊的魔力来完成这一点(又称为类似于bash的终端应用程序或等效程序)。
- @A-B-B我知道,这就是我所说的"特殊魔法"。但是无论如何,这不是一个真正的解决方案,因为asker请求一个"空目录",并且根据定义,这不是空的。我实际上想要一个完全空的目录,用于一个特定的用例,而这个目录不被Git覆盖。
- 优雅:.keep文件与commit消息一起显示了"保留"项目结构的意图。添加自述或关于我认为会引起更多的混乱…
- 在.gitkeep上使用.keep的原因是很好的。在简单和不容易混淆之间取得良好的平衡。名称空间似乎很重要,不应该因为.git....看起来像git自己的文件名称空间而被破坏。其他文档可以转到项目全局自述、编码样式指南或本地自述。如果您采用了.gitkeep习惯,只需找到文件并将其重命名:git mv .gitkeep .keep。拥抱变革!Git文档推荐的.gitignore解决方案似乎是一种黑客解决方案,而且过于复杂。
- 另一方面,问题是非常依赖于git的,因为除非是因为版本控制了项目,否则您不会遇到这个问题。
为什么我们需要空的版本化文件夹
首先要做的是:
An empty directory cannot be part of a tree under the Git versioning system.
它根本不会被跟踪。但有些场景中"版本控制"空目录可能有意义,例如:
- 搭建一个预定义的文件夹结构,使其可供存储库的每个用户/贡献者使用;或者,作为上述的一种特殊情况,为临时文件(如cache/或logs/目录)创建一个文件夹,我们希望在其中提供文件夹,但.gitignore其内容
- 与上述相关,有些项目在没有文件夹的情况下无法工作(这通常是一个设计糟糕的项目的提示,但这是一个经常发生的现实场景,可能会出现,例如,需要解决的权限问题)。
一些建议的解决方法
许多用户建议:
放置一个README文件或另一个包含某些内容的文件,以使目录不为空,或
创建一个带有"逆向逻辑"(即包括所有文件)的.gitignore文件,其目的与方法1相同。
虽然这两个解决方案都可以工作,但我发现它们与Git版本控制的有意义的方法是不一致的。
- 为什么你要把虚假的文件或自述文件放在你的项目中?
- 为什么用.gitignore来做一件事情(保存文件),这与它的目的(不包括文件)正好相反,即使它是可能的?
.gitkeep方法
使用一个名为.gitkeep的空文件,以强制在版本控制系统中存在该文件夹。
虽然这似乎没有什么大的区别:
您使用的文件具有保存文件夹的单一目的。你不想把任何你不想放的信息放在那里。
例如,您应该使用自述文件以及包含有用信息的自述文件,而不是作为保留文件夹的借口。
分离关注点总是一件好事,您仍然可以添加一个.gitignore来忽略不需要的文件。
命名它.gitkeep使它从文件名本身(以及对其他开发人员,这对于共享项目和Git存储库的核心目的之一很好)非常清楚和简单,该文件是
- 与代码无关的文件(因为前导点和名称)
- 一个与git明显相关的文件
- 它的目的(keep)在其意义上是明确的、一致的和语义上相反的,可以忽略。
采用
我看到过非常重要的框架(如laravel、angular cli)采用的.gitkeep方法。
- 您错过了一个想法—保留和清空文件夹的原因是什么(例如/logs、/tmp、/uploads)?是-保持文件夹为空。:)因此,如果要保持文件夹为空,则必须忽略其中的文件。
- @罗曼纳伦斯坦:不一定。可能是您创建了一个具有给定结构的回购,该结构可以稍后填充。这些文件将在创建后立即添加到repo中,并且开始删除或编辑会很烦人。gitignore文件(而且很危险,因为您可能甚至没有意识到它们没有被跟踪:git正在忽略它们)
- 另一个用例:我把我的/etc保存在版本控制中。有些目录是空的,但我想在我的repo中跟踪它们(它们必须在那里,否则一些工具将无法工作)。但我不想忽略那里的文件:只要我一删除cx1(0)个新文件就可以出现,我当然不想忽略。
- 投反对票:冗长的回答。
- @贝南姆:我会投反对票,但我对S.O.meta的研究显示,只要它们提供足够的细节和清晰,对每个读者(以及每个技能水平)都有用,就不会担心冗长的答案。尽管如此,我对任何批评都非常开放,感谢你公开宣布了原因,我非常肯定。
- 如果你编辑你的答案,用任何其他非git前缀的文件名替换.gitkeep,我认为这是最好和最有用的答案。原因:我认为应该为git指定的文件保留".git*",而这只是一个占位符。当我看到这一点时,我的第一个猜测是,例如".gitkeep"文件将被自动忽略(这将是一个很好的功能),但事实并非如此,对吗?
- @桑托斯,你可以编辑我的帖子,对社区有用,而不是幼稚地吹嘘一个非母语的人,无益地污染评论,这与一般的聪明行为是一致的。这就是为什么编辑是为了,顺便说一句。不管怎样,谢谢免费的课,非常感谢:)
- 感谢@cranio为您提供出色的职位,upvote。您可以通过添加一个选项来改进它。保留
- 嗨@cranio,你能看看这个问题吗?stackoverflow.com/q/50495317/7644562
- 我想知道为什么人们很难理解为什么要向Git添加"空"文件夹。你必须从某个地方开始,对吗?所以,通常你从你的项目文件夹结构开始,唉,在项目开始的时候,那里什么都没有。一旦项目报告完成,团队工作人员就可以克隆并开始使用相同的结构。
如其他答案所述,Git无法在其临时区域中表示空目录。(参见Git常见问题解答)但是,如果出于您的目的,一个目录足够空,如果它只包含一个.gitignore文件,那么您只能通过以下方式在空目录中创建.gitignore文件:
1
| 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 \;。
- 因为OSX几乎在每个Directoy中都创建了一个.ds_存储文件,所以这在那里不起作用。唯一的(危险的!)我发现的解决方法是,首先通过find . -name .DS_Store -exec rm {} \;删除所有.ds存储文件,然后使用这个答案中的首选变体。请确保只在正确的文件夹中执行此操作!
- 有人知道在Windows中从命令行执行此操作的方法吗?我在Ruby和Python中看到过一些解决方案,但是如果可以管理的话,我想要一个准系统的解决方案。
- @泽贝克,你应该把.DS_Store放在.gitignore里。请参阅上的此链接以进行设置。
- @阿克汉在.gitignore上加了些东西,对find命令的-empty旗没有影响。我的意见是删除目录树中的.DS_Store文件,因此可以应用-empty标志。
安迪·莱斯特是对的,但是如果你的目录只是空的,而不是空的,你可以把一个空的.gitignore文件放在里面作为解决方法。
另外,这是一个实现问题,而不是一个基本的Git存储设计问题。正如在Git邮件列表中多次提到的,这一点没有实现的原因是没有人足够关心提交补丁,而不是不能或不应该这样做。
- 我就是这么说的。这两个段落都在我发布的FAQ片段中进行了说明。
- 我认为旁白是没有价值的,知道它是有用的——它是可以修复的,只是不要期待它很快就会出现,因为大多数情况下都有如此简单的解决方法。
- 对不起,我没有读最后一段,虽然我读了第一段,但我不知道为什么我要重复这些信息。
- 当然,这个额外的答案确实有助于指出事实。
- 我在这里看到了这样一个例子:如果目录不存在,并且默认情况下它是空的,那么构建就会失败,但它不需要是空的。创建.gitignore是正确的。
Ruby on Rails日志文件夹创建方式:
1
| mkdir log && touch log/.gitkeep && git add log/.gitkeep |
现在日志目录将包含在树中。它在部署时非常有用,因此不必编写生成日志目录的例程。
日志文件可以通过发出
1
| echo log/dev.log >> .gitignore |
但你可能知道。
- 这与RubyonRails有什么关系?
- @QuolonelQuestions github.com/rails/rails/blob/master/activerecord/test/migrati‌&8203;ons/…
Git不跟踪空目录。有关更多说明,请参阅Git常见问题解答。建议的解决方法是将.gitignore文件放在空目录中。我不喜欢这个解决方案,因为UNIX约定"隐藏"了.gitignore。也没有解释为什么目录是空的。
我建议在空目录中放置一个自述文件,解释为什么目录是空的,以及为什么需要在Git中跟踪它。在准备好自述文件后,就Git而言,目录不再是空的。
真正的问题是,为什么您需要git中的空目录?通常,您有一些构建脚本可以在编译/运行之前创建空目录。如果没有,那就做一个。这比在Git中放置空目录要好得多。
所以你有一些原因,为什么你需要在git中有一个空目录。把这个原因放到自述文件中。这样其他开发人员(以及将来的您)就知道为什么需要空目录。您还将知道,当需要空目录的问题得到解决时,可以删除空目录。
要列出每个空目录,请使用以下命令:
1
| find -name .git -prune -o -type d -empty -print |
要在每个空目录中创建占位符自述文件,请执行以下操作:
1 2
| find -name .git -prune -o -type d -empty -exec sh -c \
"echo this directory needs to be empty because reasons > {}/README.emptydir" \; |
要忽略目录中除自述文件以外的所有内容,请在.gitignore中放置以下行:
1 2 3 4
| path/to/emptydir/*
!path/to/emptydir/README.emptydir
path/to/otheremptydir/*
!path/to/otheremptydir/README.emptydir |
或者,您可以将每个自述文件排除在外,不被忽略:
1 2 3
| path/to/emptydir/*
path/to/otheremptydir/*
!README.emptydir |
要列出已创建的每个自述文件,请执行以下操作:
1
| find -name README.emptydir |
警告:这个调整并不是真正有效的结果。抱歉给您带来不便。
以下原始邮件:
我在玩Git内部时找到了一个解决方案!
假设您在存储库中。
创建空目录:
1
| $ mkdir path/to/empty-folder |
使用管道命令和空树sha-1将其添加到索引中:
1 2
| $ git update-index --index-info
040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 path/to/empty-folder |
键入命令,然后输入第二行。按enter,然后按ctrl+d终止输入。注:格式为模式[空格]类型[空格]sha-1hash[制表符]路径(制表符很重要,答案格式不保留)。
就是这样!空文件夹在索引中。你所要做的就是承诺。
这个解决方案很短,显然很好用(见编辑!)但这不是那么容易记住的…
空树sha-1可以通过在其中创建一个新的空git存储库,cd并发出git write-tree来找到,后者输出空树sha-1。
编辑:
我找到这个解决方案后就一直在使用它。它的工作方式似乎与创建子模块完全相同,只是在任何地方都没有定义模块。这会导致发布git submodule init|update时出错。问题是,git update-index将040000 tree部分重写为160000 commit。
此外,放置在该路径下的任何文件都不会被Git注意到,因为它认为它们属于其他存储库。这很讨厌,因为它很容易被忽视!
但是,如果您还没有(并且不会)使用存储库中的任何Git子模块,"空"文件夹将保持为空,或者如果您希望Git知道它的存在并忽略其内容,则可以进行此调整。按照通常的方式使用子模块需要更多的步骤来进行调整。
- 将空文件夹放入索引并提交之后,是否可以使用预期的结果来执行git svn dcommit?
- 这种调整不太可能与其他任何工具一起使用。正如警告和编辑中所述,我不鼓励使用它,除非在非常有限的情况下。
- 出于好奇,它在github用户界面上确实有效:github.com/cirosantilli/test-empty-subdir,但是当您克隆它时,它不会被签出。
- 当然,这就是为什么禁止搅乱git内部的原因。
- @cirosantilli六件事法轮功包轩i got this type of empty directory github.com/abhisekp/empty-dir
- @阿披塞克普这怎么可能?
- @在软件世界里,没有什么是不可能的。实际上,我是按照答案来做的。
- @阿披塞克普(我的意思是他们为什么看起来不一样?)
- @皮鲁雷斯,我认为西罗桑蒂利没有正确地遵循指示。
假设您需要一个名为tmp的空目录:
1 2 3 4 5
| $ mkdir tmp
$ touch tmp/.gitignore
$ git add tmp
$ echo '*' > tmp/.gitignore
$ git commit -m 'Empty directory' tmp |
换句话说,您需要先将.git ignore文件添加到索引中,然后才能告诉git忽略它(以及空目录中的其他所有内容)。
- 有两件事:您可以只"echo'*'>tmp/.gitignore"而不是触摸,并且"git commit-m"不会提交在将文件添加到索引后所做的更改。
- touch file; echo bla > file给出了file: File exists;在这种情况下,使用rm file; touch file; echo something >> file是最安全的(可能还有许多其他的解决方案;-)
- 如果你只做echo bla > file,你就不会得到file: File exists,因为>会覆盖已经存在的文件,或者如果不存在的话创建一个新的文件。
- /bin/sh文化假设!*如果"这里"是csh,并且设置了变量noclobber,那么您确实会得到file: File exists。如果有人说"我明白了",不要以为他们是白痴,回答"不,你不明白"。*c2.com/cgi/wiki?美国文化假设
- @如果有人决定使用与其他人不同的外壳,他们应该明确声明,如果他们遇到问题。与国籍不同,每个人都可以自由选择贝壳。
- @塞尔多姆尼迪也许他们在寻求帮助,因为他们甚至不知道他们使用的是与其他人不同的外壳。
可能添加一个空目录看起来是阻力最小的路径,因为您有希望该目录存在的脚本(可能是因为它是生成二进制文件的目标)。另一种方法是根据需要修改脚本以创建目录。
1 2
| mkdir --parents .generated/bin ## create a folder for storing generated binaries
mv myprogram1 myprogram2 .generated/bin ## populate the directory as needed |
在本例中,您可以将一个(断开的)符号链接签入到目录中,这样您就可以在不使用".generated"前缀的情况下访问它(但这是可选的)。
1 2
| ln -sf .generated/bin bin
git add bin |
当您想清理源代码树时,您只需:
1
| rm -rf .generated ## this should be in a"clean" script or in a makefile |
如果采用通常建议的方法签入一个几乎为空的文件夹,则删除内容的复杂性很小,而不同时删除".gitignore"文件。
通过向根目录中添加以下内容,可以忽略所有生成的文件。gitignore:
- 注意:我建议的符号链接在干净的签出中是"断开的",因为.generated目录最初并不存在。一旦你做了你的构建,它就不会再被破坏了。
- 我同意在某些情况下这是一个非常好的主意,但在其他情况下(例如分发一个项目,其中您有一个空的框架,其中包含诸如models/和views/之类的文件夹),您希望用户手头上有这些目录,而不是手动读取文档,并且期望他们运行某种类型的克隆repo后的安装脚本。我认为这个答案与@john mee的自述答案结合起来,应该涵盖大多数情况,如果不是所有的情况。
我也面临着空目录的问题。使用占位符文件的问题是,如果不再需要它们,则需要创建它们并删除它们(因为后来添加了子目录或文件)。使用大型的源代码树管理这些占位符文件可能很麻烦,而且容易出错。
这就是为什么我决定编写一个开源工具来自动管理这些占位符文件的创建/删除。它是为.NET平台编写的,运行在Mono(.NET for Linux)和Windows下。
看看:http://code.google.com/p/markemptydirs
你做不到,不幸的是永远也做不到。这是莱纳斯·托瓦尔德自己做的决定。他知道什么对我们有好处。
在我读过一次的某个地方,有一句咆哮。
我发现了re:空目录..,但可能还有另一个。
你必须和解决方法一起生活…不幸的是。
- 我知道你把这个作为一个坏论点的例子,但是我很欣赏这个链接,因为它实际上是一个合理的反对跟踪目录的论点。;-)
- 这个答案似乎不一致,因为在引用线程的下一篇文章中,LinusTorvald说他希望他们需要添加目录跟踪:markmail.org/message/libip4vpvvxhyqbl。事实上,他说他"会欢迎[增加对跟踪空目录的支持]的补丁。"
- 帕特里克,他也用"白痴"这个词。我怀疑他的措词能使这里的人满意,所以我认为他不会自己在git中实现"白痴"的东西。
我喜欢@artur79和@mjs给出的答案,所以我一直在使用两者的组合,并将其作为我们项目的标准。
1
| find . -type d -empty -exec touch {}/.gitkeep \; |
但是,只有少数开发人员在Mac或Linux上工作。在Windows上做了很多工作,我找不到一个等效的简单的一行程序来完成相同的工作。有些人很幸运,因为其他原因安装了Cygwin,但仅仅为这个开了Cygwin的处方就显得杀伤力太大了。
编辑以获得更好的解决方案
因此,由于我们的大多数开发人员已经安装了Ant,我想到的第一件事就是将一个Ant构建文件组合起来,独立于平台完成这一任务。这里仍然可以找到这个
但是,我后来认为最好将其制作成一个小的实用程序命令,所以我使用Python重新创建了它,并将其发布到了pypi中。只需运行以下命令即可安装:
它允许您递归地创建和删除.gitkeep文件,还允许您向它们添加消息,以便您的对等方了解这些目录为什么重要。最后一点是奖励。我想如果.gitkeep文件能够自我记录就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| $ 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. |
希望你觉得它有用。
当你添加一个.gitignore文件时,如果你想在其中放置任何数量的内容(你想让git忽略),你可能想添加一行只有星号*的内容,以确保你不会意外添加被忽略的内容。
杰米·弗洛诺的解决方案非常有效。这里有一个稍微增强的版本来保持.htaccess:
1 2 3 4 5
| # Ignore everything in this directory
*
# Except this file
!.gitignore
!.htaccess |
使用此解决方案,您可以提交一个空文件夹,例如/log、/tmp或/cache,文件夹将保持为空。
- 他想保留一个空目录而不是一个文件。
- 我也提到过它将保留.htaccess。示例:如果一个软件有一个日志文件目录(如oxid eshop),该目录不能通过Web访问,则该目录中有一个.htaccess。如果将上述.gitignore放到文件夹中,.htaccess将不会被合并,文件夹将可以通过Web访问。
- 如果您有一个.htaccess文件在版本控制下,那么您已经有了包含该文件的目录在版本控制下了。因此,问题已经解决了,.gitignore文件变得不相关。
- @Wallacoo与你的问题有关,你是对的,尽管这个文件是有用的,我会把它用于一个上传目录,在这个目录中文件应该受到.htaccess的保护。与罗马人的解释相反,.htaccess文件将被提交,因为它被忽略规则排除。[旧线,我知道]
如前所述,不可能添加空目录,但这里有一个一行程序向所有目录添加空的.gitignore文件。
ruby -e 'require"fileutils" ; Dir.glob(["target_directory","target_directory/**"]).each { |f| FileUtils.touch(File.join(f,".gitignore")) if File.directory?(f) }'
为了方便取用,我把它塞进了一个耙子里。
- 我宁愿用find . -type d -empty -print0 | xargs --null bash -c 'for a; do { echo"*"; echo"!.gitignore"; } >>"$a/.gitignore"; done' --。
这是一个黑客,但它的工作很有趣(Git2.2.1)。类似于@teka的建议,但更容易记住:
- 向任何存储库添加子模块(git submodule add path_to_repo)
- 这将添加一个文件夹和一个文件.submodules。做出改变。
- 删除.submodules文件并提交更改。
现在,您有了一个在签出提交时创建的目录。不过,有趣的是,如果您查看此文件的树对象的内容,您将得到:
fatal: Not a valid object name
b64338b90b4209263b50244d18278c0999867193
但我不鼓励使用它,因为它可能会在将来的Git版本中停止工作。这可能会导致存储库损坏。
- 致命的黑客
- 这实际上是可行的,但我想混淆了Intellij的该死…:
没有办法让Git跟踪目录,所以唯一的解决方案是在您希望Git跟踪的目录中添加一个占位符文件。
文件可以命名并包含您想要的任何内容,但大多数人使用名为.gitkeep的空文件(尽管有些人更喜欢VCS不可知的.keep)。
前缀.将其标记为隐藏文件。
另一个想法是添加一个README文件,解释该目录将用于什么目的。
我总是构建一个函数来检查我想要的文件夹结构,并在项目中为我构建它。这解决了这个问题,因为空文件夹由代理保存在Git中。
1 2 3 4 5 6 7 8
| 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中,但我确信大多数语言都支持相同的功能,并且由于应用程序负责创建文件夹,所以文件夹将始终存在。
- 所以我们都在同一个页面上,我不再这样做了。这是浪费时间。《江户公约》是一个更好的做法。
- 我不明白这是怎么浪费时间的。当您的templatePath明显是动态的时,您不能使用.gitkeep解决方案。即使使用非动态文件夹结构,您也应该添加更多内容,而不是删除检查目录的非常好的解决方案,例如检查权限和chmod文件。在global.gitignore中添加一种标记目录的方法对我来说是完美的。类似于keep/path/to/dir
你不能。这是Git维护人员的故意设计决定。基本上,像git这样的源代码管理系统的目的是管理源代码,空目录不是源代码。Git也经常被描述为内容跟踪器,同样,空目录不是内容(实际上恰恰相反),因此它们不被跟踪。
- 我反对这种观点。结构就是内容,而你所说的一切都有助于内容。
- 空文件也不是源代码或内容。只是一个名字。然而Git会很高兴地跟踪空文件。我不认为这是一个故意设计的决定,让git拒绝跟踪空目录。我认为跟踪空目录是一项根本不需要99%时间的功能,因此他们不必费心做额外的工作来使其正常工作。如果有人非常想要这个特性来实现它,Git可以做到。我怀疑git维护人员会反对这样一个补丁,如果它是正确的。
- @Tobyalen这里是最新的FAQ链接。最上面的答案也是FAQ推荐的,有更精确的说明。
- 这是一个缺失的特性(低优先级),而不是有意的限制。Git常见问题解答:目前,Git索引(临时区域)的设计只允许列出文件,而且没有人有足够的能力进行更改以允许空目录,他们已经足够关心这种情况来解决它。
- 不太同意。我可以找到各种原因来跟踪空文件夹。例如,我正在为我的项目开发一个非常轻量级的PHP MVC框架。我有用于放置模型、视图等的特定文件夹。当我基于框架创建新网站时,这些文件夹是空的,因为默认情况下没有模型或视图,但我确实需要该文件夹存在,否则框架将无法工作!
如果要添加一个文件夹,该文件夹将在多个语义目录中存储大量临时数据,那么一种方法是将类似这样的内容添加到根目录中。
/app/data/**/*.*
!/app/data/**/*.md
然后,您可以提交描述性readme.md文件(或空白文件,无所谓,只要您可以像在本例中使用*.md)那样在每个目录中唯一地针对它们,以确保目录都是repo的一部分,但文件(带扩展名)被忽略。限制:目录名中不允许使用.!
您可以使用XML/images文件或其他文件填充所有这些目录,并随着应用程序开发所需的存储空间的增加,在/app/data/下添加更多目录(其中readme.md文件用于详细描述每个存储目录的用途)。
不需要通过为每个新目录创建一个新的.gitignore来进一步更改您的.gitignore或分散。也许不是最聪明的解决方案,但很简洁,忽略智慧,总是为我工作。又好又简单!;)
有时您必须处理写得不好的库或软件,它们需要一个"真正的"空目录和现有目录。放一个简单的.gitignore或.keep可能会破坏它们并导致错误。在这些情况下,以下内容可能会有所帮助,但不能保证……
首先创建所需目录:
然后您向这个目录添加一个中断的符号链接(但是在上面描述的用例以外的任何其他情况下,请使用一个README和一个解释):
1
| ln -s .this.directory empty/.keep |
要忽略此目录中的文件,可以将其添加到根目录.gitignore中:
1
| echo"/empty">> .gitignore |
要添加被忽略的文件,请使用参数强制它:
提交之后,索引中有一个中断的符号链接,Git创建了目录。断开的链接有一些优点,因为它不是常规文件,并且指向没有常规文件。因此,它甚至符合问题的一部分(不包含任何文件),不是出于意图,而是出于意义,我猜:
此命令显示空结果,因为此目录中不存在任何文件。因此,大多数应用程序(在一个目录中获取所有文件)通常看不到这个链接,至少在它们执行"文件存在"或"可读"操作时。即使某些脚本在那里也找不到任何文件:
1 2 3 4 5
| $ php -r"var_export(glob('empty/.*'));"
array (
0 => 'empty/.',
1 => 'empty/..',
) |
但我强烈建议仅在特殊情况下使用此解决方案,在空目录中编写良好的README通常是更好的解决方案。(我不知道这是否适用于Windows文件系统…)
再增加一个选项。
假设您想在git中添加一个目录,在与git相关的所有目的中,该目录都应该保持为空,并且永远不会跟踪其内容,那么这里多次建议的.gitignore就可以做到这一点。
如前所述,格式为:
现在,如果您想在命令行中一下子完成此操作,而在要添加的目录中,您可以执行:
1
| $ echo"*"> .gitignore && echo '!.gitignore' >> .gitignore && git add .gitignore |
我自己有一个shell脚本,我用它来做这个。将脚本命名为您想说的任何内容,然后将其添加到include路径的某个位置,或者直接引用它:
1 2 3 4 5 6 7 8 9 10 11
| #!/bin/bash
dir=''
if ["$1" !="" ]; then
dir="$1/"
fi
echo"*"> $dir.gitignore && \
echo '!.gitignore' >> $dir.gitignore && \
git add $dir.gitignore |
有了这个,您可以从您想要添加的目录中执行它,或者引用目录作为它的第一个也是唯一的参数:
1
| $ ignore_dir ./some/directory |
另一个选项(响应@greenasjade的评论),如果您希望跟踪一个空文件夹,该文件夹将来可能包含被跟踪的文件,但现在是空的,您可以从.gitignore文件中操作*,并将其签入。基本上,所有的文件都是说"不要忽略我",否则,目录是空的并被跟踪。
您的.gitignore文件如下:
就是这样,检查一下,你有一个空的,但仍被跟踪的目录,你可以在以后的某个时候跟踪文件。
我建议在文件中保留一行的原因是它给出了.gitignore的目的。否则,可能会有人想把它去掉。如果在行上方放置注释,可能会有所帮助。
有时,我的存储库中的文件夹将只包含被认为是"内容"的文件,也就是说,它们不是我关心的被版本控制的文件,因此不应该提交。使用git的.git ignore文件,可以忽略整个目录。但有时将文件夹放在回购协议中是有益的。这里有一个很好的解决方案来满足这个需求。
我过去所做的是将.gitignore文件放在repo的根目录下,然后排除文件夹,如下所示:
1 2
| /app/some-folder-to-exclude
/another-folder-to-exclude/* |
但是,这些文件夹不会成为回购的一部分。您可以在其中添加类似于自述文件的内容。但是您必须告诉应用程序不要担心处理任何自述文件。
如果您的应用程序依赖于存在的文件夹(尽管是空的),您可以简单地将.gitignore文件添加到相关文件夹中,并使用它来实现两个目标:
告诉Git文件夹中有一个文件,它使Git将其添加到repo中。告诉Git忽略这个文件夹的内容,减去这个文件本身。以下是要放入空目录中的.gitignore文件:
第一行(*)告诉Git忽略这个目录中的所有内容。第二行告诉Git不要忽略.git ignore文件。您可以将此文件填充到要添加到存储库的每个空文件夹中。
您可以将此代码保存为create_readme.php,并从Git项目的根目录运行php代码。
它将向所有空目录添加自述文件,以便这些目录随后被添加到索引中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php
$path = realpath('.');
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name => $object){
if ( is_dir($name) && ! is_empty_folder($name) ){
echo"$name
" ;
exec("touch".$name."/"."README");
}
}
function is_empty_folder($folder) {
$files = opendir($folder);
while ($file = readdir($files)) {
if ($file != '.' && $file != '..')
return true; // Not empty
}
}
?> |
然后做
1 2
| git commit -m"message"
git push |