45

I deleted all files from a directory in my work folder, but the directory itself still exists. After pushing the changes to a remote repository (GitHub) I checked my project and noticed that the directory was gone. Is it possible that Git deletes empty folders?

  • 25
    Git does not delete empty folder but it has no concept of folders therefore it does not track folders (git only tracks paths to your files, not folders, it treats file paths like how you'd treat URLs on a website). The standard way to keep an empty folder in your project is to add a README file so git can track that file instead. – slebetman Aug 18 at 19:39
  • 50
    @slebetman Actually, as mentioned in my answer, the commonly accepted way to keep an empty directory is to add a .gitkeep file, not a README, as a .gitkeep file will usually not be listed (due to starting with a .) when browsing directories. .gitkeep files are therefore meant to be (almost) invisible. A README on the other hand by its naming implies some meaning – it almost tells you that there is something that should be in there, but it's not. – slhck Aug 18 at 20:59
  • 4
    @slebetman I understand. It's a matter of preference, I suppose. I see both ways listed here, but personally I've most come across the former. – slhck Aug 18 at 21:42
  • 21
    @slebetman - you don't "open" a .gitkeep file, it's a zero byte file used only to tell git to track the folder. And it's a de facto standard, so there is no reason to ever check why it was added. It's only ever added to keep the folder, that's why it's called gitKEEP. – Davor Aug 19 at 10:31
  • 7
    @slebetman - uh, yeah, README is standard, but for a completely different thing. It has nothing to do with preserving empty directories, which is the only reason why gitkeep would ever exist. Using a wrong thing is exactly what would confuse people. – Davor Aug 20 at 11:19
94

Why is the directory not shown?

Git does not track directories; it only tracks files.

If there are no files in a directory, that directory does not “exist” to Git when adding or removing files. Particularly, a directory will disappear from Git's index when you've deleted all files from it and add that change to the index. Vice-versa, a directory will not be added via git add if it's empty.

In other words: If you can see the directory locally in your file browser, but it disappeared from GitHub, you most likely removed all files from the directory, added that change to the index, and committed and pushed it.

How do I track an empty directory, then?

If you want to explicitly track an empty directory, you have to create a file in it. Since Git won't track empty directories, you have to trick it into doing so by adding a file in the directory to Git's index.

Usually, people store a file called .gitkeep in a directory that they wish to track, but where the directory should stay empty for the time being. You can give the file any other name, of course, but the name .gitkeep is a convention. The .gitkeep file (due to starting with a .) will not be shown by file listings on most systems.

Instead of .gitkeep, some users also like to put a README file there instead, ideally with a short description of why the directory has to exist in the first place.

Example

$ mkdir foo
$ git init
$ git add .
$ git ls-files   # which files does Git know about?
                 # apparently, none
$ touch foo/bar  # create a file in the directory
$ git add .
$ git ls-files   # does Git know about it now?
foo/bar          # yep!

Here, the foo directory only gets added to the index once a file is in it.

What if I really want to track an empty directory?

That all said, in principle, the underlying data structure allows Git to store an empty directory, since it would be represented by an empty “tree”. Some further reading here and here.

  • 12
    cannot is somewhat misleading. Structure of object files (trees and blobs) supports empty directories. It just deliberately decided not to track empty directories – RiaD Aug 19 at 1:07
  • @RiaD Good point. I updated my answer to be a bit more precise. – slhck Aug 19 at 7:35
  • 3
    Git does not even track files, it tracks file contents. That's why it can recognize renamed files on the fly. – Davor Aug 20 at 13:02
  • 5
    @Davor Well, that's a bit of a matter of definition. Yes, it tracks file content primarily, but it also tracks the paths that point to that content. The tree entries that Git stores are filenames, and they point to the actual content. – slhck Aug 20 at 14:36
  • 1
    @Worse_Username Yes, but Git is not using exactly the same concepts here. In my answer, I was talking about the Git frontend, which basically lets you add file contents to the index. The directories in which the files reside are the trees. Please have a look at the first link in my answer: “All the content is stored as tree and blob objects, with trees corresponding to UNIX directory entries and blobs corresponding more or less to inodes or file contents” – slhck Aug 21 at 11:39
6

Add the following .gitignore file to the folders you wish to include in your repo.

# Ignore everything in this directory
*
# Except this file
!.gitignore

Adding .gitkeep works but isn’t an official solution. See https://stackoverflow.com/questions/7229885/what-are-the-differences-between-gitignore-and-gitkeep

  • 27
    This will indeed ensure Git tracks the empty directory, but it will also prevent Git from tracking any other files in that directory — so this is for if you want a directory that should always stay empty in Git. – NobodyNada - Reinstate Monica Aug 19 at 0:52
  • 3
    I think @NobodyNada's comment should be part of this answer. Some people might want their Git project to contain a directory that is empty and never tracked (like a build directory?) – TomTsagk Aug 19 at 9:44
  • 17
    There's no such thing as an "official" solution. You just can't have empty directories in git, period. Adding a file, any file to the directory works because then it's no longer an empty directory. This is perfectly documented, "official" behaviour. .gitignore is in the documentation, unlike other file names you might use, because it does unrelated stuff: make git ignore specific files. That doesn't make it a better solution to this problem. On the contrary, that makes it confusing as people will expect it to do that other stuff, and not just be there to keep the directory. – FrederikVds Aug 19 at 11:37
  • I tried editing the answer to include NobodyNada's point, but the edit was rejected. Hopefully nobody misses the comment and loses data. – chicks Aug 20 at 12:15
2

Git does not track folders. In order to refrain from accumulating messes, when the index changes from (indirectly) referencing a directory to not referencing it (by doing something like git rm on the last registered file in the directory), Git tries removing the directory before it loses track of it by it no longer being in the index. If Git is successful because the directory has indeed become empty (and does not contain unregistered files), the directory will be gone, if not, it will stick around since Git no longer has notice of it.

1

Git might delete folders if you ran git clean with -dffx (possibly even with a subset of those options).

As @TRiG mentions in the comments, if the directory is empty when you commit, it won’t show up in, e.g., GitHub, because git doesn’t track directories (it track files)—the tree where those files were is no longer relevant because there are no files, so there is no tree.

Without more detail, it’s practically impossible for us to properly answer your underlying questions (what happened?).

  • The OP "deleted all files from a directory" and committed those changes. So I believe it's quite clear what happened. – slhck Aug 19 at 7:36
  • @slhck not so—how did they delete? rm -rf? git clean? Drag and drop to the recycle bin? What does « checked my project » mean, and which directory was gone? – D. Ben Knoble Aug 19 at 12:21
  • To me, it's pretty reasonable to assume that it was rm foo/* (or any other method of deleting), git add foo, then commit and push. When you check your project on GitHub (as the OP indicated), the directory will be gone. – slhck Aug 19 at 13:05
  • 1
    @slhck i see a lot of assumptions—the deletion, as mentioned. Checking on GitHub? Where is that mentioned? I prefer not to assume I know the steps to reproduce something until I know them—ive been blinded to the true cause of bugs that way before. – D. Ben Knoble Aug 19 at 13:16
  • 2
    Deleting all files from a directly, not running git clean -d or similar, comitting, and pushing will have the observed effect (the empty directory still exists locally, but has disappeared from the remote project). – TRiG Aug 19 at 14:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.