tl;dr create a .keep file to check-in folders in git and add the following lines to your .gitignore to ignore the files within:

# ignore files in folder foo
foo/*

# but keep the folder
!foo/.keep

This method is useful for the following cases:

  1. You want to push a directory structure to git before having files.
  2. You want to check-in a directory but not the files.
  3. You just want to push an empty folder — lol.

Remember that this is not a git feature or anything like that, this is done using an undocumented file name convention (keep or gitkeep) and the prefix to negate a pattern ⧉.

Just create an empty folder and create a 0kb file called .keep

$ mkdir logs
$ touch logs/.keep

You can call it .keep or .gitkeep, they are useful for the exact same thing and the name of it its just a convention (Rails and some Node generators). This file is going to allow git to include the directory. You can delete it after you add the first file.

If you want to ignore everything inside the foo directory but you also want to check-in this folder, add the following lines in your .gitignore

# ignore all logs files
logs/*

# don't ignore keep files
!.keep

If you create a new file inside logs directory it is going to be ignored but the directory (because of the .keep file) is going to be checked-in.

Further explanation

Consider the following scenario. We create a git repository.

$ mkdir test && cd $_
$ git init
Initialized empty Git repository in /route/test/.git/

Then we create a logs folder that we want to check-in.

$ mkdir logs
$ git status
nothing to commit

In order to save those files we need to create a file called .keep with no content.

$ touch logs/.keep
new file:   logs/.keep
$ git commit -am 'Adds log directory'

Now, if you also want be able to check-in the folder, but not its content — makes sense for a logs file, add the following content in your .gitignore file.

# ignore files in folder logs
logs/*

# but please keep the folder
!logs/.keep

Disclaimer: Git will know if you didn’t put the word please in the comment. This won’t work if you miss it.

Commit that and now if we create new files in the folder or do any change to existing files, these are not going to be checked-in by git.

$ touch logs/development.log
$ git status
  nothing to commit, working directory clean

$ touch logs/production.log
$ git status
  nothing to commit, working directory clean

That’s it. Thanks for reading.