如何将空目录(不包含文件)添加到Git存储库?
如何将空目录(不包含文件)添加到Git存储库?
Answers:
使目录保持(在存储库中)几乎为空的另一种方法是.gitignore
在该目录内创建一个包含以下四行的文件:
# Ignore everything in this directory
*
# Except this file
!.gitignore
这样,您就不必像m104 解决方案中那样正确地获得订单。
这也带来了好处,当您执行git状态时,该目录中的文件不会显示为“未跟踪”。
使@GreenAsJade的评论持续存在:
我认为值得一提的是,该解决方案恰好满足了该问题的要求,但也许并不是许多关注此问题的人一直在寻找。此解决方案确保目录保持为空。它说:“我真的不希望在这里签入文件”。与“我还没有任何文件可以在这里签入,但是我需要在这里的目录,文件可能稍后再来”相反。
README
内部的.gitignore
文档(作为注释)。
你不能 请参阅Git常见问题解答。
当前,git索引(临时区域)的设计仅允许列出文件,并且没有足够的能力来进行更改以允许空目录的人对此情况已经足够在意,以进行补救。
在目录中添加文件时会自动添加目录。也就是说,目录永远不必添加到存储库,也不需要单独跟踪。
您可以说“
git add <dir>
”,它将在其中添加文件。如果您确实需要在结帐中存在目录,则应在其中创建一个文件。.gitignore为此很好地工作;您可以将其保留为空,或填写您希望在目录中显示的文件名。
git mv
因为git会抱怨新目录不受版本控制
.gitignore
技巧是一个常见的回答,满足多种需求。但是有可能使git跟踪一个真正的空目录,请参阅我的答案
.gitkeep
为此目的而使用称为空文件的存储库。
.gitkeep
在目录中创建一个名为的空文件,然后添加它。
.keep
。
.gitkeep
尚未由Git规定,并将让人们第二次猜测其含义,这将导致他们进入google搜索,这将导致他们进入此处。该.git
前缀约定应为文件和目录保留了Git本身使用。
.git
前缀约定应该保留...”为什么?git是否要求此保留?
README
或ABOUT
文件将是一样好或更好。给下一个家伙留下笔记,就像我们以前都在URL之前一样。
您总是可以将README文件放在目录中,并说明为什么要在存储库中使用此目录(否则为空)。
touch .keep
在Linux上,这将创建一个名为的空文件.keep
。就其价值而言,此名称与Git无关,而与Git无关.gitkeep
。其次,正如另一个用户所指出的,.git
前缀约定应该保留给Git本身使用的文件和目录。
或者,如另一个答案中所述,目录可以包含描述性文件README
或README.md
文件。
当然,这要求文件的存在不会导致应用程序中断。
.keep
文件或不理会它。如果要忽略目录中的文件,则完全是另一个问题。
git clean -nd | sed s/'^Would remove '// | xargs -I{} touch "{}.keep"
在所有未跟踪的空目录中执行此操作。
首先要注意的是:
空目录 在Git版本控制系统下,不能成为树的一部分。
它根本不会被跟踪。但是在某些情况下,“版本化”空目录可能很有意义,例如:
cache/
或logs/
目录)创建一个文件夹.gitignore
许多用户建议:
README
文件或其他文件放入某些内容,以使目录为非空目录,或者.gitignore
具有某种“反向逻辑”(即包括所有文件)的文件,最后,该文件具有与方法1相同的目的。虽然这两种解决方案都能正常工作,但我发现它们与有意义的Git版本控制方法不一致。
.gitignore
做某事(保留文件)与本意相反(不包括文件)呢?使用一个空文件名为.gitkeep
,以强制在版本控制系统中存在该文件夹。
尽管看起来差别不大:
您使用具有单个保持文件夹的目的。您不会在此处放置任何您不想放置的信息。
例如,您应该使用自述文件以及具有有用信息的自述文件,而不是保留文件夹的借口。
关注点分离始终是一件好事,您仍然可以添加.gitignore
忽略不必要的文件。
.gitkeep
从文件名本身(以及其他开发人员,这对于共享项目和Git存储库的核心目的之一而言),从文件名本身起,它的名称变得非常清楚和直接。
我已经看到了.gitkeep
非常重要的框架(例如Laravel和Angular-CLI)采用的方法。
.gitkeep
为任何其他非git前缀的文件名,您将得到我的认可,我认为这是最好,最有用的答案。原因:我认为应该为git规定的文件保留“ .git *”,但这只是一个占位符。我的第一个猜测是,例如,“。gitkeep”文件将被自动忽略(这将是一个不错的功能),但事实并非如此,对吧?
如其他答案所述,Git无法在其暂存区域中表示空目录。(请参阅Git常见问题解答。)但是,如果出于您的目的,如果目录.gitignore
仅包含文件,则该目录足够空,则.gitignore
只能通过以下方式在空目录中创建文件:
find . -type d -empty -exec touch {}/.gitignore \;
find . -name .git -prune -o -type d -empty -exec touch {}/.gitignore \;
find * -type d -empty -exec touch {}/.gitignore \;
find . -name .DS_Store -exec rm {} \;
,然后使用此答案中的首选变体。确保仅在正确的文件夹中执行此操作!
.gitignore
的-empty
标志没有影响find
。我的评论是关于删除.DS_Store
目录树中的文件的,因此-empty
可以应用该标志。
安迪·莱斯特(Andy Lester)是对的,但是如果您的目录只需要为空,而不是空目录,则可以.gitignore
在其中放置一个空文件作为解决方法。
顺便说一句,这是一个实现问题,而不是基本的Git存储设计问题。正如在Git邮件列表中多次提到的那样,未实现此问题的原因是,没有人愿意为此提交补丁,而不是无法或不应该这样做。
在Ruby on Rails的日志文件夹的创建方式:
mkdir log && touch log/.gitkeep && git add log/.gitkeep
现在,日志目录将包含在树中。部署时它非常有用,因此您无需编写例程即可创建日志目录。
可以通过发出以下命令来保留日志文件:
echo log/dev.log >> .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
警告:事实证明,这种调整并没有真正起作用。抱歉给你带来不便。
原始帖子如下:
我在玩Git内部构件时找到了解决方案!
创建您的空目录:
$ mkdir path/to/empty-folder
使用管道命令和空树SHA-1将其添加到索引:
$ git update-index --index-info
040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 path/to/empty-folder
键入命令,然后输入第二行。按Enter,然后按Ctrl+ D终止输入。注意:格式为模式 [SPACE] 类型 [SPACE] SHA-1hash [TAB]路径(标签是很重要的,答案格式不保留它)。
而已!空文件夹在索引中。您要做的就是提交。
该解决方案很短,并且显然可以正常工作(请参见编辑!),但是它并不容易记住...
可以通过在其中创建一个新的空Git存储库cd
并发出issue 来找到空树SHA-1 git write-tree
,该存储库输出空树SHA-1。
编辑:
自找到以来,我一直在使用此解决方案。它看起来与创建子模块完全相同,但是在任何地方都没有定义模块。这会导致发行时出错git submodule init|update
。问题是git update-index
将040000 tree
零件重写为160000 commit
。
而且,放在该路径下的任何文件都不会被Git注意到,因为它认为它们属于其他存储库。这很讨厌,因为它很容易被忽略!
但是,如果您尚未(也不会)使用存储库中的任何Git子模块,并且“空”文件夹将保持为空,或者如果您希望Git知道其存在并忽略其内容,则可以使用这个调整。使用子模块的常规方法将花费更多的步骤进行此调整。
git svn dcommit
获得所需的结果?
假设您需要一个名为tmp的空目录:
$ mkdir tmp
$ touch tmp/.gitignore
$ git add tmp
$ echo '*' > tmp/.gitignore
$ git commit -m 'Empty directory' tmp
换句话说,您需要将.gitignore文件添加到索引中,然后才能告诉Git忽略它(以及空目录中的所有其他内容)。
echo bla > file
您将不会得到,file: File exists
因为>
它将覆盖该文件(如果已存在)或创建一个新文件(如果不存在)。
/bin/sh
文化假设!*如果“这里”是csh
且noclobber
设置了变量,则确实会得到file: File exists
。如果有人说“我明白了”,请不要以为他们是白痴,然后回答“不,您不要”。* c2.com/cgi/wiki?AmericanCulturalAssumption
也许添加一个空目录似乎是阻力最小的路径,因为您有希望该目录存在的脚本(也许因为它是生成的二进制文件的目标)。另一种方法是修改脚本以根据需要创建目录。
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
.generated
目录最初不存在。完成构建后,它将不再被破坏。
我也一直面临着空目录的问题。使用占位符文件的问题是,如果不再需要它们,则需要创建它们并删除它们(因为稍后添加了子目录或文件。使用大的源代码树来管理这些占位符文件可能很麻烦且出错)易于。
这就是为什么我决定编写一个开源工具,该工具可以自动管理此类占位符文件的创建/删除。它是为.NET平台编写的,可在Mono(Linux的.NET)和Windows下运行。
我喜欢@ 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.
希望对你有帮助。
您不能而且很遗憾将永远无法。这是Linus Torvald本人做出的决定。他知道什么对我们有好处。
我曾经读过的某处有一只咆哮。
我发现Re:空目录..,但也许还有另一个。
不幸的是,您必须忍受变通办法。
如前所述,不可能添加空目录,但这是一个将空.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' --
Jamie Flournoy的解决方案效果很好。这是保留以下内容的增强版本.htaccess
:
# Ignore everything in this directory
*
# Except this file
!.gitignore
!.htaccess
有了这个解决方案,您可以提交一个空文件夹,例如/log
,/tmp
或者/cache
和文件夹将保持为空。
我总是构建一个函数来检查所需的文件夹结构,并在项目中为我构建它。由于空文件夹由代理保存在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
公约是一个更好的做法。
这是一个hack,但是很有趣,它可以工作(Git 2.2.1)。与@Teka建议类似,但更容易记住:
git submodule add path_to_repo
).submodules
。提交更改。.submodules
文件并提交更改。现在,您有一个在检出提交时创建的目录。但是,有趣的是,如果查看此文件的树对象的内容,则会得到:
致命的:无效的对象名称b64338b90b4209263b50244d18278c0999867193
我不鼓励使用它,因为它可能会在以后的Git版本中停止工作。这可能会使您的存储库损坏。
许多人已经回答了这个问题。只需在此处添加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}
如果要添加一个在多个语义目录中包含大量瞬态数据的文件夹,则一种方法是在根.gitignore中添加类似的内容。
/app/data/**/*.*
!/app/data/**/*.md
然后,您可以*.md
在每个目录中提交描述性的README.md文件(或空白文件,没关系,只要您可以像在这种情况下一样以它们为唯一目标)就可以确保目录都保留在存储库中,但是文件(带有扩展名)将被忽略。局限性:.
目录名称中不允许使用!
您可以使用xml / images文件或其他文件填充所有这些目录,并在以下目录中添加更多目录 /app/data/
随着应用程序存储需求的发展在一段时间内(README.md文件用于烧录每个存储目录的描述)究竟)。
无需.gitignore
通过.gitignore
为每个新目录创建新目录来进一步更改目录或分散目录。可能不是最聪明的解决方案,但简洁明了,并且始终对我有用。漂亮又简单!;)
在竞争中增加了一个选项。
假设您要在其中添加目录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评论),如果你想跟踪一个空文件夹是MAY包含跟踪文件在未来,但将是空的,现在,你可以ommit的*
从.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子模块引用阅读@ofavre和@ stanislav-bashkyrtsev的答案来创建GIT目录,令我感到惊讶的是,没有人提出这个想法的简单修改,以使整个过程理智而安全:
与其添加一个假的子模块到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,因此您必须手动检查参考提交ID是否正在e84d7b81f0033399e325b8037ed2b801a5c994e0
使用git submodule status
在添加回购后。
还没本地的解决方案,但没有人我们大概可以有最好的得到他们的手真的,真的在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提交非常困难……
你不能 这是Git维护者的有意设计决定。基本上,像Git这样的源代码管理系统的目的是管理源代码,而空目录不是源代码。Git通常也被描述为内容跟踪器,同样,空目录也不是内容(实际上恰恰相反),因此它们不会被跟踪。
您可以将此代码另存为create_readme.php并从Git项目的根目录运行PHP代码。
> php create_readme.php
它将自述文件添加到所有空目录中,以便将这些目录添加到索引中。
<?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\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
checkout
与当前版本的Git一起使用。