如何将空目录(不包含文件)添加到 Git 存储库?
checkout
。
使目录保持(几乎)空(在存储库中)的另一种方法是在该目录中创建一个 .gitignore
文件,其中包含以下四行:
# Ignore everything in this directory
*
# Except this file
!.gitignore
这样您就不必像在 m104 的 solution 中那样正确地获得订单了。
这也带来了好处,即当您执行 git status 时,该目录中的文件不会显示为“未跟踪”。
使 @GreenAsJade 的评论持久化:
我认为值得注意的是,这个解决方案正是问题所要求的,但也许不是许多查看这个问题的人一直在寻找的。此解决方案保证目录保持为空。它说“我真的不想在这里签入文件”。与“我这里还没有要签入的文件,但我需要这里的目录,文件可能稍后会出现”相反。
你不能。请参阅 Git FAQ。
目前 git 索引(暂存区)的设计只允许列出文件,并且没有足够能力进行更改以允许空目录的人足够关心这种情况来补救它。在目录中添加文件时会自动添加目录。也就是说,目录永远不必添加到存储库中,并且不会自行跟踪。你可以说“git add
.gitignore
技巧是一个常见的答案,可以满足许多需求。然而有可能让 git track 成为一个真正空的目录,see my answer
.gitkeep
的空文件。
在目录中创建一个名为 .gitkeep
的空文件,然后添加它。
.gitkeep
不是 Git 规定的,它会让人们第二次猜测它的含义,这将引导他们到谷歌搜索,这将引导他们到这里。 .git
前缀约定应保留给 Git 本身使用的文件和目录。
.git
前缀约定......”为什么? git 是否请求此预订?
README
或 ABOUT
文件会同样好或更好。给下一个人留个便条,就像我们在 URL 之前所做的那样。
您始终可以在目录中放置一个 README 文件,并说明您为什么要在存储库中使用此目录,否则为空目录。
touch .placeholder
在 Linux 上,这会创建一个名为 .placeholder
的空文件。值得一提的是,这个名称对 git 来说是不可知的,并且这种方法用于系统中的其他各个地方,例如 /etc/cron.d/.placeholder
。其次,正如另一位用户所指出的,.git
前缀约定可以保留给 Git 本身用于配置目的的文件和目录。
或者,如另一个 answer 中所述,目录可以包含描述性 README.md
file。
无论哪种方式,这都要求文件的存在不会导致您的应用程序中断。
.keep
文件或忽略它。相反,如果要忽略目录中的文件,那将是一个完全不同的问题。
git clean -nd | sed s/'^Would remove '// | xargs -I{} touch "{}.keep"
在所有未跟踪的空目录中执行此操作。
.keep
文件连同提交消息 显示了“保留”项目结构的意图。添加自述文件或关于我认为会引起更多混乱...
为什么我们需要空的版本化文件夹
第一件事:
在 Git 版本控制系统下,空目录不能是树的一部分。
它根本不会被跟踪。但是在某些情况下,“版本控制”空目录可能是有意义的,例如:
搭建预定义的文件夹结构,使其可供存储库的每个用户/贡献者使用;或者,作为上述的特殊情况,为临时文件创建一个文件夹,例如 cache/ 或 logs/ 目录,我们希望在其中提供文件夹但 .gitignore 其内容
与上述相关,某些项目在没有某些文件夹的情况下将无法工作(这通常暗示项目设计不佳,但这是一个常见的现实场景,也许可能存在需要解决的权限问题)。
一些建议的解决方法
许多用户建议:
放置一个 README 文件或另一个包含某些内容的文件以使目录非空,或者使用一种“反向逻辑”(即包含所有文件)创建一个 .gitignore 文件,最后服务于方法#1的相同目的。
虽然这两种解决方案都有效,但我发现它们与有意义的 Git 版本控制方法不一致。
为什么你应该在你的项目中放置你可能并不真正想要的伪造文件或自述文件?
为什么要使用 .gitignore 来做与它的用途(不包括文件)完全相反的事情(保存文件),即使它是可能的?
.gitkeep 方法
使用名为 .gitkeep
的 empty 文件以强制该文件夹存在于版本控制系统中。
虽然看起来差别不大:
您使用的文件仅用于保存文件夹。你不要放任何你不想放的信息。例如,您应该使用自述文件作为包含有用信息的自述文件,而不是作为保留文件夹的借口。关注点分离总是一件好事,您仍然可以添加 .gitignore 来忽略不需要的文件。
将其命名为 .gitkeep 可以从文件名本身(以及其他开发人员,这对于共享项目和 Git 存储库的核心目的之一)来说非常清晰和直接,该文件是与代码无关的文件(由于前导点和名称)与 Git 明确相关的文件其目的(保留)已明确说明且一致且语义相反,其含义可忽略
与代码无关的文件(因为前导点和名称)
与 Git 明显相关的文件
它的目的(保持)被清楚地陈述并且在其含义上是一致的和语义上相反的以忽略
采用
我已经看到 Laravel、Angular-CLI 等非常重要的框架采用了 .gitkeep
方法。
.gitkeep
替换为任何其他非 git 前缀的文件名,您会得到我的支持,我认为这是最好和最有用的答案。原因:我认为“.git*”应该保留给 git 规定的文件,而这只是一个占位符。当我看到它时,我的第一个猜测是,例如“.gitkeep”文件会被自动忽略(这将是一个不错的功能),但事实并非如此,对吧?
如其他答案中所述,Git 无法在其暂存区域中表示空目录。 (请参阅 Git FAQ。)但是,如果出于您的目的,如果一个目录仅包含一个 .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 {} \;
删除所有 .DS_Store 文件,然后使用此答案中的首选变体。请务必仅在正确的文件夹中执行此操作!
.gitignore
添加内容对 find
命令的 -empty
标志没有影响。我的评论是关于删除目录树中的 .DS_Store
文件,因此可以应用 -empty
标志。
Andy Lester 是对的,但如果您的目录只是需要为空,而不是 empty 为空,您可以在其中放置一个空的 .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 中需要一个空目录。把这个原因放在 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
警告:事实证明,这个调整并没有真正起作用。带来不便敬请谅解。
原帖如下:
我在玩 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-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
在此示例中,您可能会签入到目录的(损坏的)符号链接,以便您可以在没有“.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
目录最初不存在。一旦您进行构建,它将不再被破坏。
在该目录中添加一个 .gitkeep 文件并提交它。
touch .gitkeep
它是 git 遵循的标准。
我喜欢 @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.
希望对你有帮助。
ls -r -dir | ?{$_.getFileSystemInfos().Count -eq 0} | %{ni -p $_.FullName -n .gitkeep}
你不能,不幸的是永远也不能。这是 Linus Torvald 自己做出的决定。他知道什么对我们有好处。
我读过一次的地方有一篇咆哮。
我找到了 Re: Empty directories..,但也许还有另一个。
你必须忍受这些变通方法......不幸的是。
我也一直面临空目录的问题。使用占位符文件的问题是,如果不再需要它们,您需要创建它们并删除它们(因为后来添加了子目录或文件。使用大型源树管理这些占位符文件可能很麻烦并且会出错易于。
这就是为什么我决定编写一个开源工具来自动管理此类占位符文件的创建/删除。它是为 .NET 平台编写的,可在 Mono(.NET for Linux)和 Windows 下运行。
看看:http://code.google.com/p/markemptydirs
这个解决方案对我有用。
1. 将 .gitignore 文件添加到您的空目录:
*
*/
!.gitignore
* 忽略文件夹中的所有文件
*/ 忽略子目录
!.gitignore 包含 .gitignore 文件
2. 然后删除缓存,暂存文件,提交并推送:
git rm -r --cached .
git add . // or git stage .
git commit -m ".gitignore fix"
git push
添加 .gitignore
文件时,如果要在其中放入任意数量的内容(您希望 Git 忽略),您可能需要添加仅带有星号 *
的单行,以确保您没有t 意外添加被忽略的内容。
阅读 @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 提交非常困难……
没有办法让 Git 跟踪目录,因此唯一的解决方案是在您希望 Git 跟踪的目录中添加一个占位符文件。
该文件可以命名并包含您想要的任何内容,但大多数人使用名为 .gitkeep
的空文件(尽管有些人更喜欢与 VCS 无关的 .keep
)。
前缀 .
将其标记为隐藏文件。
另一个想法是添加一个 README
文件来解释目录的用途。
如前所述,不可能添加空目录,但这是一个将空 .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' --
许多人已经回答了这个问题。只需在此处添加 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"
The solution of 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 版本中停止工作。这可能会使您的存储库损坏。
如果您想添加一个文件夹,该文件夹将在多个语义目录中容纳大量临时数据,那么一种方法是将类似这样的内容添加到您的根 .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
有时您必须处理糟糕的编写库或软件,它们需要一个“真正的”空目录和现有目录。放置一个简单的 .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 文件系统......)
一种简单的方法是将 .gitkeep
文件添加到您希望(当前)保持为空的目录中。
有关更多信息,请参阅此 SOF answer - 这也解释了为什么有些人发现添加 .gitignore 文件的竞争约定(如这里的许多答案所述)令人困惑。
你不能。这是 Git 维护人员有意的设计决定。基本上,像 Git 这样的源代码管理系统的目的是管理源代码,而空目录不是源代码。 Git 也经常被描述为内容跟踪器,同样,空目录不是内容(实际上恰恰相反),因此它们不会被跟踪。
不定期副业成功案例分享
.gitignore
文件中的README
的文档(作为注释)。