问题
How can I add an empty directory (that contains no files) to a Git repository?
回答1:
Another way to make a directory stay (almost) empty (in the repository) is to create a .gitignore
file inside that directory that contains these four lines:
# Ignore everything in this directory
*
# Except this file
!.gitignore
Then you don't have to get the order right the way that you have to do in m104's solution.
This also gives the benefit that files in that directory won't show up as "untracked" when you do a git status.
Making @GreenAsJade's comment persistent:
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".
回答2:
You can't. See the Git FAQ.
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 <dir>
" 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.
回答3:
Create an empty file called .gitkeep
in the directory, and add that.
回答4:
You could always put a README file in the directory with an explanation of why you want this, otherwise empty, directory in the repository.
回答5:
touch .keep
On Linux, this creates an empty file named .keep
. This name is preferred over .gitkeep
as the former is agnostic to Git, whereas the latter is specific to Git. Secondly, as another user has noted, the .git
prefix convention should be reserved for files and directories that Git itself uses.
Alternatively, as noted in another answer, the directory can contain a descriptive README or README.md file instead.
Of course this requires that the presence of the file won't cause your application to break.
回答6:
Why would we need empty versioned folders
First things first:
An empty directory cannot be part of a tree under the Git versioning system.
It simply won't be tracked. But there are scenarios in which "versioning" empty directories can be meaningful, for example:
- scaffolding a predefined folder structure, making it available to every user/contributor of the repository; or, as a specialized case of the above, creating a folder for temporary files, such as a
cache/
orlogs/
directories, where we want to provide the folder but.gitignore
its contents - related to the above, some projects won't work without some folders (which is often a hint of a poorly designed project, but it's a frequent real-world scenario and maybe there could be, say, permission problems to be addressed).
Some suggested workarounds
Many users suggest:
- Placing a
README
file or another file with some content in order to make the directory non-empty, or - Creating a
.gitignore
file with a sort of "reverse logic" (i.e. to include all the files) which, at the end, serves the same purpose of approach #1.
While both solutions surely work I find them inconsistent with a meaningful approach to Git versioning.
- Why are you supposed to put bogus files or READMEs that maybe you don't really want in your project?
- Why use
.gitignore
to do a thing (keeping files) that is the very opposite of what it's meant for (excluding files), even though it is possible?
.gitkeep approach
Use an empty file called .gitkeep
in order to force the presence of the folder in the versioning system.
Although it may seem not such a big difference:
You use a file that has the single purpose of keeping the folder. You don't put there any info you don't want to put.
For instance, you should use READMEs as, well, READMEs with useful information, not as an excuse to keep the folder.
Separation of concerns is always a good thing, and you can still add a
.gitignore
to ignore unwanted files.Naming it
.gitkeep
makes it very clear and straightforward from the filename itself (and also to other developers, which is good for a shared project and one of the core purposes of a Git repository) that this file is- A file unrelated to the code (because of the leading dot and the name)
- A file clearly related to Git
- Its purpose (keep) is clearly stated and consistent and semantically opposed in its meaning to ignore
Adoption
I've seen the .gitkeep
approach adopted by very important frameworks like Laravel, Angular-CLI.
回答7:
As described in other answers, Git is unable to represent empty directories in its staging area. (See the Git FAQ.) However, if, for your purposes, a directory is empty enough if it contains a .gitignore
file only, then you can create .gitignore
files in empty directories only via:
find . -type d -empty -exec touch {}/.gitignore \;
回答8:
Andy Lester is right, but if your directory just needs to be empty, and not empty empty, you can put an empty .gitignore
file in there as a workaround.
As an aside, this is an implementation issue, not a fundamental Git storage design problem. As has been mentioned many times on the Git mailing list, the reason that this has not been implemented is that no one has cared enough to submit a patch for it, not that it couldn’t or shouldn’t be done.
回答9:
The Ruby on Rails log folder creation way:
mkdir log && touch log/.gitkeep && git add log/.gitkeep
Now the log directory will be included in the tree. It is super-useful when deploying, so you won't have to write a routine to make log directories.
The logfiles can be kept out by issuing,
echo log/dev.log >> .gitignore
but you probably knew that.
回答10:
Git does not track empty directories. See the Git FAQ for more explanation. The suggested workaround is to put a .gitignore
file in the empty directory. I do not like that solution, because the .gitignore
is "hidden" by Unix convention. Also there is no explanation why the directories are empty.
I suggest to put a README file in the empty directory explaining why the directory is empty and why it needs to be tracked in Git. With the README file in place, as far as Git is concerned, the directory is no longer empty.
The real question is why do you need the empty directory in git? Usually you have some sort of build script that can create the empty directory before compiling/running. If not then make one. That is a far better solution than putting empty directories in git.
So you have some reason why you need an empty directory in git. Put that reason in the README file. That way other developers (and future you) know why the empty directory needs to be there. You will also know that you can remove the empty directory when the problem requiring the empty directory has been solved.
To list every empty directory use the following command:
find -name .git -prune -o -type d -empty -print
To create placeholder READMEs in every empty directory:
find -name .git -prune -o -type d -empty -exec sh -c \
"echo this directory needs to be empty because reasons > {}/README.emptydir" \;
To ignore everything in the directory except the README file put the following lines in your .gitignore
:
path/to/emptydir/*
!path/to/emptydir/README.emptydir
path/to/otheremptydir/*
!path/to/otheremptydir/README.emptydir
Alternatively, you could just exclude every README file from being ignored:
path/to/emptydir/*
path/to/otheremptydir/*
!README.emptydir
To list every README after they are already created:
find -name README.emptydir
回答11:
WARNING: This tweak is not truly working as it turns out. Sorry for the inconvenience.
Original post below:
I found a solution while playing with Git internals!
- Suppose you are in your repository.
Create your empty directory:
$ mkdir path/to/empty-folder
Add it to the index using a plumbing command and the empty tree SHA-1:
$ git update-index --index-info 040000 tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 path/to/empty-folder
Type the command and then enter the second line. Press Enter and then Ctrl + D to terminate your input. Note: the format is mode [SPACE] type [SPACE] SHA-1hash [TAB] path (the tab is important, the answer formatting does not preserve it).
That's it! Your empty folder is in your index. All you have to do is commit.
This solution is short and apparently works fine (see the EDIT!), but it is not that easy to remember...
The empty tree SHA-1 can be found by creating a new empty Git repository, cd
into it and issue git write-tree
, which outputs the empty tree SHA-1.
EDIT:
I've been using this solution since I found it. It appears to work exactly the same way as creating a submodule, except that no module is defined anywhere.
This leads to errors when issuing git submodule init|update
.
The problem is that git update-index
rewrites the 040000 tree
part into 160000 commit
.
Moreover, any file placed under that path won't ever be noticed by Git, as it thinks they belong to some other repository. This is nasty as it can easily be overlooked!
However, if you don't already (and won't) use any Git submodules in your repository, and the "empty" folder will remain empty or if you want Git to know of its existence and ignore its content, you can go with this tweak. Going the usual way with submodules takes more steps that this tweak.
回答12:
Maybe adding an empty directory seems like it would be the path of least resistance because you have scripts that expect that directory to exist (maybe because it is a target for generated binaries). Another approach would be to modify your scripts to create the directory as needed.
mkdir --parents .generated/bin ## create a folder for storing generated binaries
mv myprogram1 myprogram2 .generated/bin ## populate the directory as needed
In this example, you might check in a (broken) symbolic link to the directory so that you can access it without the ".generated" prefix (but this is optional).
ln -sf .generated/bin bin
git add bin
When you want to clean up your source tree you can just:
rm -rf .generated ## this should be in a "clean" script or in a makefile
If you take the oft-suggested approach of checking in an almost-empty folder, you have the minor complexity of deleting the contents without also deleting the ".gitignore" file.
You can ignore all of your generated files by adding the following to your root .gitignore:
.generated
回答13:
Let's say you need an empty directory named tmp :
$ mkdir tmp
$ touch tmp/.gitignore
$ git add tmp
$ echo '*' > tmp/.gitignore
$ git commit -m 'Empty directory' tmp
In other words, you need to add the .gitignore file to the index before you can tell Git to ignore it (and everything else in the empty directory).
回答14:
I've been facing the issue with empty directories, too. The problem with using placeholder files is that you need to create them, and delete them, if they are not necessary anymore (because later on there were added sub-directories or files. With big source trees managing these placeholder files can be cumbersome and error prone.
This is why I decided to write an open source tool which can manage the creation/deletion of such placeholder files automatically. It is written for .NET platform and runs under Mono (.NET for Linux) and Windows.
Just have a look at: http://code.google.com/p/markemptydirs
回答15:
I like the answers by @Artur79 and @mjs so I've been using a combination of both and made it a standard for our projects.
find . -type d -empty -exec touch {}/.gitkeep \;
However, only a handful of our developers work on Mac or Linux. A lot work on Windows and I could not find an equivalent simple one-liner to accomplish the same there. Some were lucky enough to have Cygwin installed for other reasons, but prescribing Cygwin just for this seemed overkill.
Edit for a better solution
So, since most of our developers already have Ant installed, the first thing I thought of was to put together an Ant build file to accomplish this independently of the platform. This can still be found here
However, I later thought It would be better to make this into a small utility command, so I recreated it using Python and published it to the PyPI here. You can install it by simply running:
pip3 install gitkeep2
It will allow you to create and remove .gitkeep
files recursively, and it will also allow you to add messages to them for your peers to understand why those directories are important. This last bit is bonus. I thought it would be nice if the .gitkeep
files could be self-documenting.
$ 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.
I hope you find it useful.
回答16:
You can't and unfortunately will never be able to. This is a decision made by Linus Torvald himself. He knows what's good for us.
There is a rant out there somewhere I read once.
I found Re: Empty directories.., but maybe there is another one.
You have to live with the workarounds...unfortunately.
回答17:
When you add a .gitignore
file, if you are going to put any amount of content in it (that you want Git to ignore) you might want to add a single line with just an asterisk *
to make sure you don't add the ignored content accidentally.
回答18:
As mentioned it's not possible to add empty directories, but here is a one liner that adds empty .gitignore files to all directories.
ruby -e 'require "fileutils" ; Dir.glob(["target_directory","target_directory/**"]).each { |f| FileUtils.touch(File.join(f, ".gitignore")) if File.directory?(f) }'
I have stuck this in a Rakefile for easy access.
回答19:
The solution of Jamie Flournoy works great. Here is a bit enhanced version to keep the .htaccess
:
# Ignore everything in this directory
*
# Except this file
!.gitignore
!.htaccess
With this solution you are able to commit a empty folder, for example /log
, /tmp
or /cache
and the folder will stay empty.
回答20:
I always build a function to check for my desired folder structure and build it for me within the project. This gets around this problem as the empty folders are held in Git by proxy.
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");
}
This is in PHP, but I am sure most languages support the same functionality, and because the creation of the folders is taken care of by the application, the folders will always be there.
回答21:
Here is a hack, but it's funny that it works (Git 2.2.1). Similar to what @Teka suggested, but easier to remember:
- Add a submodule to any repository (
git submodule add path_to_repo
) - This will add a folder and a file
.submodules
. Commit a change. - Delete
.submodules
file and commit the change.
Now, you have a directory that gets created when commit is checked out. An interesting thing though is that if you look at the content of tree object of this file you'll get:
fatal: Not a valid object name b64338b90b4209263b50244d18278c0999867193
I wouldn't encourage to use it though since it may stop working in the future versions of Git. Which may leave your repository corrupted.
回答22:
There's no way to get Git to track directories, so the only solution is to add a placeholder file within the directory that you want Git to track.
The file can be named and contain anything you want, but most people use an empty file named .gitkeep
(although some people prefer the VCS-agnostic .keep
).
The prefixed .
marks it as a hidden file.
Another idea would be to add a README
file explaining what the directory will be used for.
回答23:
If you want to add a folder that will house a lot of transient data in multiple semantic directories, then one approach is to add something like this to your root .gitignore...
/app/data/**/*.*
!/app/data/**/*.md
Then you can commit descriptive README.md files (or blank files, doesn't matter, as long as you can target them uniquely like with the *.md
in this case) in each directory to ensure that the directories all remain part of the repo but the files (with extensions) are kept ignored. LIMITATION: .
's are not allowed in the directory names!
You can fill up all of these directories with xml/images files or whatever and add more directories under /app/data/
over time as the storage needs for your app develop (with the README.md files serving to burn in a description of what each storage directory is for exactly).
There is no need to further alter your .gitignore
or decentralise by creating a new .gitignore
for each new directory. Probably not the smartest solution but is terse gitignore-wise and always works for me. Nice and simple! ;)
回答24:
You can't. This is an intentional design decision by the Git maintainers. Basically, the purpose of a Source Code Management System like Git is managing source code and empty directories aren't source code. Git is also often described as a content tracker, and again, empty directories aren't content (quite the opposite, actually), so they are not tracked.
回答25:
An easy way to do this is by adding a .gitkeep
file to the directory you wish to (currently) keep empty.
See this SOF answer for further info - which also explains why some people find the competing convention of adding a .gitignore file (as stated in many answers here) confusing.
回答26:
Many have already answered this question. Just adding a PowerShell version here.
Find all the empty folders in the directory
Add a empty .gitkeep file in there
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}
回答27:
Adding one more option to the fray.
Assuming you would like to add a directory to git
that, for all purposes related to git
, should remain empty and never have it's contents tracked, a .gitignore
as suggested numerous times here, will do the trick.
The format, as mentioned, is:
*
!.gitignore
Now, if you want a way to do this at the command line, in one fell swoop, while inside the directory you want to add, you can execute:
$ echo "*" > .gitignore && echo '!.gitignore' >> .gitignore && git add .gitignore
Myself, I have a shell script that I use to do this. Name the script whatever you whish, and either add it somewhere in your include path, or reference it directly:
#!/bin/bash
dir=''
if [ "$1" != "" ]; then
dir="$1/"
fi
echo "*" > $dir.gitignore && \
echo '!.gitignore' >> $dir.gitignore && \
git add $dir.gitignore
With this, you can either execute it from within the directory you wish to add, or reference the directory as it's first and only parameter:
$ ignore_dir ./some/directory
Another option (in response to a comment by @GreenAsJade), if you want to track an empty folder that MAY contain tracked files in the future, but will be empty for now, you can ommit the *
from the .gitignore
file, and check that in. Basically, all the file is saying is "do not ignore me", but otherwise, the directory is empty and tracked.
Your .gitignore
file would look like:
!.gitignore
That's it, check that in, and you have an empty, yet tracked, directory that you can track files in at some later time.
The reason I suggest keeping that one line in the file is that it gives the .gitignore
purpose. Otherwise, some one down the line may think to remove it. It may help if you place a comment above the line.
回答28:
Sometimes you have to deal with bad written libraries or software, which need a "real" empty and existing directory. Putting a simple .gitignore
or .keep
might break them and cause a bug. The following might help in these cases, but no guarantee...
First create the needed directory:
mkdir empty
Then you add a broken symbolic link to this directory (but on any other case than the described use case above, please use a README
with an explanation):
ln -s .this.directory empty/.keep
To ignore files in this directory, you can add it in your root .gitignore
:
echo "/empty" >> .gitignore
To add the ignored file, use a parameter to force it:
git add -f empty/.keep
After the commit you have a broken symbolic link in your index and git creates the directory. The broken link has some advantages, since it is no regular file and points to no regular file. So it even fits to the part of the question "(that contains no files)", not by the intention but by the meaning, I guess:
find empty -type f
This commands shows an empty result, since no files are present in this directory. So most applications, which get all files in a directory usually do not see this link, at least if they do a "file exists" or a "is readable". Even some scripts will not find any files there:
$ php -r "var_export(glob('empty/.*'));"
array (
0 => 'empty/.',
1 => 'empty/..',
)
But I strongly recommend to use this solution only in special circumstances, a good written README
in an empty directory is usually a better solution. (And I do not know if this works with a windows filesystem...)
回答29:
You can save this code as create_readme.php and run the PHP code from the root directory of your Git project.
> php create_readme.php
It will add README files to all directories that are empty so those directories would be then added to the index.
<?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
}
}
?>
Then do
git commit -m "message"
git push
回答30:
Sometimes I have repositories with folders that will only ever contain files considered to be "content"—that is, they are not files that I care about being versioned, and therefore should never be committed. With Git's .gitignore file, you can ignore entire directories. But there are times when having the folder in the repo would be beneficial. Here's a excellent solution for accomplishing this need.
What I've done in the past is put a .gitignore file at the root of my repo, and then exclude the folder, like so:
/app/some-folder-to-exclude
/another-folder-to-exclude/*
However, these folders then don't become part of the repo. You could add something like a README file in there. But then you have to tell your application not to worry about processing any README files.
If your app depends on the folders being there (though empty), you can simply add a .gitignore file to the folder in question, and use it to accomplish two goals:
Tell Git there's a file in the folder, which makes Git add it to the repo. Tell Git to ignore the contents of this folder, minus this file itself. Here is the .gitignore file to put inside your empty directories:
*
!.gitignore
The first line (*) tells Git to ignore everything in this directory. The second line tells Git not to ignore the .gitignore file. You can stuff this file into every empty folder you want added to the repository.
来源:https://stackoverflow.com/questions/115983/how-can-i-add-an-empty-directory-to-a-git-repository