如何将空目录(不包含文件)添加到Git存储库?
你不能 请参阅Git常见问题解答 。
当前,git索引(临时区域)的设计仅允许列出文件,并且没有足够的能力来进行更改以允许空目录的人已经足够在意这种情况以进行纠正。
在目录中添加文件时会自动添加目录。 也就是说,目录永远不必添加到存储库,也不需要单独跟踪。
您可以说“
git add
”,它将在其中添加文件。如果您确实需要在结帐中存在目录,则应在其中创建一个文件。 .gitignore为此很好地工作; 您可以将其保留为空,或填写您希望在目录中显示的文件名。
安迪·莱斯特(Andy Lester)是对的,但是如果您的目录只需要为空,而不是空目录,则可以在其中放置一个空的.gitignore
文件作为解决方法。
顺便说一句,这是一个实现问题,而不是基本的Git存储设计问题。 正如在Git邮件列表中多次提到的那样,未实现此问题的原因是,没有人愿意为此提交补丁,而不是无法或不应该这样做。
你不能 这是Git维护者的有意设计决定。 基本上,像Git这样的源代码管理系统的目的是管理源代码,而空目录不是源代码。 Git通常也被描述为内容跟踪器,同样,空目录也不是内容(实际上恰恰相反),因此它们不会被跟踪。
我也一直面临着空目录的问题。 使用占位符文件的问题是,如果不再需要它们,则需要创建它们并删除它们(因为稍后添加了子目录或文件。使用大的源代码树来管理这些占位符文件可能很麻烦且出错)易于。
这就是为什么我决定编写一个开源工具,该工具可以自动管理此类占位符文件的创建/删除。 它是为.NET平台编写的,可在Mono(Linux的.NET)和Windows下运行。
看看: http : //code.google.com/p/markemptydirs
添加.gitignore
文件时,如果要在其中添加任何数量的内容(您希望Git忽略),则可能需要添加仅带有星号*
一行,以确保您不添加意外地忽略了内容。
Ruby on Rails日志文件夹的创建方式:
mkdir log && touch log/.gitkeep && git add log/.gitkeep
现在,日志目录将包含在树中。 部署时它非常有用,因此您无需编写例程即可创建日志目录。
可以通过发出以下命令来保留日志文件:
echo log/dev.log >> .gitignore
但您可能知道这一点。
假设您需要一个名为tmp的空目录:
$ mkdir tmp
$ touch tmp/.gitignore
$ git add tmp
$ echo '*' > tmp/.gitignore
$ git commit -m 'Empty directory' tmp
换句话说,您需要将.gitignore文件添加到索引中,然后才能告诉Git忽略它(以及空目录中的所有其他内容)。
第一件事:
在Git版本控制系统下,空目录不能成为树的一部分 。
它根本不会被跟踪。 但是在某些情况下,“版本化”空目录可能很有意义,例如:
cache/
或logs/
目录)创建一个文件夹,我们要在其中提供该文件夹,但是.gitignore
它的内容 许多用户建议:
README
文件或其他文件放入某些内容,以使目录为非空,或者 .gitignore
文件,最后,该方法具有与方法1相同的目的。 虽然这两种解决方案都能正常工作,但我发现它们与有意义的Git版本控制方法不一致。
.gitignore
做某事( 保留文件)却与它的意图( 排除文件)相反呢? 使用一个名为.gitkeep
的空文件,以强制该文件夹存在于版本控制系统中。
尽管看起来差别不大:
您可以使用具有保持文件夹的单一用途的文件。 您不会在此处放置任何您不想放置的信息。
例如,您应该使用自述文件以及具有有用信息的自述文件,而不是保留文件夹的借口。
关注点分离总是一件好事,您仍然可以添加.gitignore
来忽略不需要的文件。
将其命名为.gitkeep
可以使文件名本身(以及其他开发人员)非常清楚,直接,这对于共享项目和Git存储库的核心目的之一都非常有用,即该文件是
我已经看到非常重要的框架(例如Laravel , Angular-CLI)采用了.gitkeep
方法。
touch .keep
在Linux上,这将创建一个名为.keep
的空文件。 该名称优于.gitkeep
因为前者对Git不可知,而后者特定于Git。 其次,正如另一个用户所指出的, .git
前缀约定应保留给Git本身使用的文件和目录。
或者,如另一个答案所述 ,该目录可以包含描述性README
或README.md
文件 。
当然,这要求文件的存在不会导致应用程序中断。
Jamie Flournoy的解决方案效果很好。 这是保留.htaccess
增强版本:
# Ignore everything in this directory
*
# Except this file
!.gitignore
!.htaccess
使用此解决方案,您可以提交一个空文件夹,例如/log
, /tmp
或/cache
并且该文件夹将保持为空。
这是一个hack,但是很有趣,它可以工作(Git 2.2.1)。 与@Teka建议类似,但更容易记住:
git submodule add path_to_repo
) .submodules
。 提交更改。 .submodules
文件并提交更改。 现在,您有一个在检出提交时创建的目录。 但是,有趣的是,如果查看此文件的树对象的内容,则会得到:
致命的:无效的对象名称b64338b90b4209263b50244d18278c0999867193
我不鼓励使用它,因为它可能会在以后的Git版本中停止工作。 这可能会使您的存储库损坏。
您不能而且很遗憾将永远无法。 这是Linus Torvald本人做出的决定。 他知道什么对我们有好处。
我曾经读过的某处有一只咆哮。
我发现Re:空目录.. ,但也许还有另一个。
不幸的是,您必须忍受变通办法。
无法让Git跟踪目录,因此唯一的解决方案是在要跟踪Git的目录中添加一个占位符文件。
可以命名该文件并包含所需的任何内容,但是大多数人都使用一个名为.gitkeep
的空文件(尽管有些人更喜欢与VCS无关的.keep
)。
前缀.
将其标记为隐藏文件。
另一个想法是添加一个README
文件,说明该目录的用途。
在竞争中增加了一个选项。
假设您想向git
添加一个目录,出于与git
相关的所有目的,该目录应保持为空,并且永远不要对其内容进行跟踪,这里建议多次使用.gitignore
来解决问题。
如前所述,格式为:
*
!.gitignore
现在,如果你想有一个办法做到这一点在命令行中,一举,而目录内您要添加,你可以执行:
$ echo "*" > .gitignore && echo '!.gitignore' >> .gitignore && git add .gitignore
我自己有一个用于执行此操作的shell脚本。 随意命名脚本,然后将其添加到包含路径中的某个位置,或直接引用它:
#!/bin/bash
dir=''
if [ "$1" != "" ]; then
dir="$1/"
fi
echo "*" > $dir.gitignore && \
echo '!.gitignore' >> $dir.gitignore && \
git add $dir.gitignore
这样,您可以在要添加的目录中执行它,也可以引用该目录作为它的第一个也是唯一的参数:
$ ignore_dir ./some/directory
另一个选项(响应@GreenAsJade的评论),如果您想跟踪将来可能包含跟踪文件但现在为空的空文件夹,则可以从.gitignore
文件中省略*
,然后检查在基本上,所有的文件说的是“不要不理我 ”,但除此之外,该目录为空和跟踪。
您的.gitignore
文件如下所示:
!.gitignore
就这样,签入,您将拥有一个空的但尚未跟踪的目录,以后可以在其中跟踪文件。
我建议在文件中保留一行的原因是它提供了.gitignore
目的。 否则,某些人可能会考虑将其删除。 如果您将注释放在行上方,则可能会有所帮助。
有时,您必须处理不良的书面库或软件,这些库或软件需要“真实”的空目录和现有目录。 放置简单的.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文件系统...)
有时,我的存储库中的文件夹将只包含被视为“内容”的文件-也就是说,它们不是我关心版本控制的文件,因此不应提交。 使用Git的.gitignore文件,您可以忽略整个目录。 但是有时候,将文件夹包含在存储库中将是有益的。 这是满足此需求的绝佳解决方案。
我过去做过的事情是将.gitignore文件放在存储库的根目录,然后排除该文件夹,如下所示:
/app/some-folder-to-exclude
/another-folder-to-exclude/*
但是,这些文件夹不会成为存储库的一部分。 您可以在其中添加类似README文件的内容。 但是随后您必须告诉您的应用程序不要担心处理任何自述文件。
如果您的应用程序依赖于那里的文件夹(尽管是空的),则只需将.gitignore文件添加到有问题的文件夹中,并使用它来实现两个目标:
告诉Git文件夹中有一个文件,这使Git将其添加到存储库中。 告诉Git忽略此文件夹的内容,减去该文件本身。 这是.gitignore文件,放在您的空目录中:
*
!.gitignore
第一行(*)告诉Git忽略此目录中的所有内容。 第二行告诉Git不要忽略.gitignore文件。 您可以将该文件填充到要添加到存储库的每个空文件夹中。
如果要添加一个在多个语义目录中包含大量瞬态数据的文件夹,则一种方法是在根.gitignore中添加类似的内容。
/app/data/**/*.* !/app/data/**/*.md
然后,您可以在每个目录中提交描述性的README.md文件(或空白文件,不要紧,只要可以像在这种情况下使用*.md
那样将它们作为唯一目标即可),以确保目录都保留在回购,但文件(带有扩展名)被忽略。 限制: .
目录名称中不允许使用!
您可以使用xml / images文件或其他文件填充所有这些目录,并随着/app/data/
存储需求的发展,在/app/data/
下添加更多目录(其中README.md文件用于刻录对什么内容的描述)每个存储目录都是针对的)。
无需通过为每个新目录创建一个新的.gitignore
来进一步更改.gitignore
或进行分散。 可能不是最聪明的解决方案,但简洁明了,并且始终对我有用。 漂亮又简单! ;)
我喜欢@ Artur79和@mjs的答案,所以我一直将两者结合使用,并使其成为我们项目的标准。
find . -type d -empty -exec touch {}/.gitkeep \;
但是,只有少数开发人员可以在Mac或Linux上工作。 在Windows上进行了大量工作,我找不到在其中完成相同功能的等效简单工具。 有些人很幸运因为其他原因安装了Cygwin ,但是仅仅为此开处方Cygwin似乎有些过头。
编辑以获得更好的解决方案
因此,由于大多数开发人员已经安装了Ant ,因此我想到的第一件事就是将Ant构建文件放在一起以独立于平台来完成此任务。 仍然可以在这里找到
但是 ,我后来认为最好将其变成一个小的实用程序命令,因此我使用Python重新创建了该命令并将其发布到此处的PyPI。 您可以通过简单地运行它来安装它:
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.
希望对你有帮助。
您总是可以将README文件放在目录中,并说明为什么要在存储库中使用此目录(否则为空)。
我总是构建一个函数来检查所需的文件夹结构,并在项目中为我构建它。 由于空文件夹由代理保存在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
文件添加到您希望(当前)保持为空的目录中。
请参阅此SOF答案以获取更多信息-这也解释了为什么有些人觉得添加.gitignore文件的竞争惯例令人困惑(如此处许多答案所述)。
如前所述,不可能添加空目录,但这是一个将空.gitignore文件添加到所有目录的衬板。
ruby -e 'require "fileutils" ; Dir.glob(["target_directory","target_directory/**"]).each { |f| FileUtils.touch(File.join(f, ".gitignore")) if File.directory?(f) }'
我将其粘贴在Rakefile中以便于访问。
许多人已经回答了这个问题。 只需在此处添加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}
如其他答案所述,Git无法在其暂存区域中表示空目录。 (请参阅Git常见问题解答 。)但是,如果出于您的目的,如果目录仅包含.gitignore
文件,则该目录足够空,则只能通过以下方式在空目录中创建.gitignore
文件:
find . -type d -empty -exec touch {}/.gitignore \;
Git不会跟踪空目录。 有关更多说明,请参见Git FAQ 。 建议的解决方法是将.gitignore
文件放在空目录中。 我不喜欢这种解决方案,因为.gitignore
被Unix约定“隐藏”。 也没有解释为什么目录为空。
我建议将README文件放在空目录中,解释为什么该目录为空以及为什么需要在Git中对其进行跟踪。 就README文件而言,就Git而言,该目录不再为空。
真正的问题是,为什么在git中需要空目录? 通常,您具有某种构建脚本,可以在编译/运行之前创建空目录。 如果没有,那就做一个。 这比将空目录放入git更好。
因此,您有某些原因为什么需要在git中使用一个空目录。 将该原因放在自述文件中。 这样,其他开发人员(以及您将来的开发人员)就会知道为什么需要存在空目录。 您还将知道,当解决了要求空目录的问题后,就可以删除空目录。
要列出每个空目录,请使用以下命令:
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
另外,您可以排除每个自述文件而忽略它们:
path/to/emptydir/*
path/to/otheremptydir/*
!README.emptydir
在创建每个自述文件后列出它们:
find -name README.emptydir
您可以将此代码另存为create_readme.php并从Git项目的根目录运行PHP代码。
> php create_readme.php
它将自述文件添加到所有空目录中,以便将这些目录添加到索引中。
$object){
if ( is_dir($name) && ! is_empty_folder($name) ){
echo "$name\n" ;
exec("touch ".$name."/"."README");
}
}
function is_empty_folder($folder) {
$files = opendir($folder);
while ($file = readdir($files)) {
if ($file != '.' && $file != '..')
return true; // Not empty
}
}
?>
然后做
git commit -m "message"
git push
也许添加一个空目录似乎是阻力最小的路径,因为您有希望该目录存在的脚本(也许因为它是生成的二进制文件的目标)。 另一种方法是修改脚本以根据需要创建目录 。
mkdir --parents .generated/bin ## create a folder for storing generated binaries
mv myprogram1 myprogram2 .generated/bin ## populate the directory as needed
在此示例中,您可以签入到该目录的(断开)符号链接,以便您可以在没有“ .generation”前缀的情况下访问它(但这是可选的)。
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
在目录中创建一个名为.gitkeep
的空文件,并将其添加。
警告:事实证明,这种调整并没有真正起作用。 抱歉给你带来不便。
原始帖子如下:
我在玩Git内部工具时找到了解决方案!
创建您的空目录:
$ mkdir path/to/empty-folder
使用管道命令和空树SHA-1将其添加到索引:
$ git update-index --index-info 040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 path/to/empty-folder
键入命令,然后输入第二行。 按Enter ,然后按Ctrl + D终止输入。 注意:格式为模式 [空格] 类型 [空格] SHA-1散列[TAB]路径(选项卡很重要,答案格式不会保留它)。
而已! 空文件夹在索引中。 您要做的就是提交。
这个解决方案很短,显然可以正常工作( 请参阅EDIT! ),但是它并不容易记住...
可以通过创建一个新的空Git存储库,将其插入cd
并发出git write-tree
来找到空树SHA-1,该输出将输出空树SHA-1。
编辑:
自找到以来,我一直在使用此解决方案。 它看起来与创建子模块完全相同,但是在任何地方都没有定义模块。 这在发出git submodule init|update
时导致错误。 问题是git update-index
将040000 tree
部分重写为160000 commit
。
而且,放在该路径下的任何文件都不会被Git注意到,因为它认为它们属于其他存储库。 这很讨厌,因为它很容易被忽略!
但是,如果您尚未(也不会)使用存储库中的任何Git子模块,并且“空”文件夹将保持为空,或者如果您希望Git知道其存在并忽略其内容,则可以使用这个调整。 使用子模块的常规方法将花费更多的步骤进行此调整。
使目录保持(在存储库中)几乎为空的另一种方法是在该目录内创建一个.gitignore
文件,该文件包含以下四行:
# Ignore everything in this directory
*
# Except this file
!.gitignore
这样一来,您就不必像m104 解决方案中那样正确地获得订单。
这也带来了好处,当您执行git状态时,该目录中的文件不会显示为“未跟踪”。
使@GreenAsJade的评论持续存在:
我认为值得一提的是,该解决方案恰好满足了该问题的要求,但也许并不是很多关注此问题的人一直在寻找。 此解决方案确保目录保持为空。 它说:“我真的不希望在这里签入文件”。 与“我还没有任何文件可以在这里签入,但是我需要在这里的目录,文件可能稍后再来”相反。