Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

In my project, I am using Mercurial and a folder in when the user can upload file. But since the user will upload files, the folder is empty.

I don't know how I can add this folder to my project without putting any file inside.

Do you know how I can do ?

share|improve this question
up vote 40 down vote accepted

Mercurial only keeps track of files, not directories.

One solution is to add a .empty file to your repository:

$ touch uploads/.empty
$ hg add uploads/.empty
share|improve this answer
Yes, that is indeed the correct solution: Mercurial is only keeping track of files, not directories. Another solution is to create the empty directories when you deploy your software. – Martin Geisler Dec 21 '09 at 23:23
I'm thinking naming it .hgempty might give a better clue as to what it's for – User Oct 9 '12 at 20:40
Yes or .hgkeep – Natim Oct 10 '12 at 7:28
Might as well go for verbose: .hgkeepifempty :) – Daniel Sokolowski Feb 25 '13 at 19:40

I have created a python script that automates the process of creating/deleting those files.

Here's the script's source:


# Copyright (c) 2011 Ernesto Mendez (
# Dual licensed under the MIT and GPL licenses:

# Version 1.0.0
# - Initial Release

from __future__ import generators
import sys
from optparse import OptionParser
import os

def main():
    # Process arguments

    if len(args) > 1:
        parser.error('Too many arguments')

    elif len(args) == 0:
        parser.error('Missing filename')

    if not os.path.exists(
        parser.error("%s: No such directory" %

    filename = args[0]

    # Create generator

    filetree = dirwalk(os.path.abspath(

    # Walk directory tree, create files

    if options.remove == True:

        removed = ['Removing the following files: \n']
        cmd = "rm"

        for file in filetree:
            if (os.path.basename(file) == filename):
                cmd += " %s" % fixpath(file)

        if cmd != "rm":
            for f in removed: print f
            print "No files named '%s' found" % filename

    # Walk directory tree, delete files


        created = ["Creating the following files:\n"]
        cmd = "touch"

        for file in filetree:
            if (os.path.isdir(file)):
                created.append("%s%s" % (file, filename))
                cmd += " " + fixpath("%s%s" % (file, filename))

        if cmd != "touch":
            for f in created: print f
            print "No empty directories found"

def dirwalk(dir, giveDirs=1):
    for f in os.listdir(dir):
        fullpath = os.path.join(dir, f)
        if os.path.isdir(fullpath) and not os.path.islink(fullpath):
            if not len(os.listdir(fullpath)):
                yield fullpath + os.sep
                for x in dirwalk(fullpath):  # recurse into subdir
                    if os.path.isdir(x):
                        if giveDirs:
                            yield x
                        yield x
            yield fullpath

def wrap(text, width):
    return reduce(lambda line, word, width=width: '%s%s%s' % (line, ' \n'[(len(line)-line.rfind('\n')-1 + len(word.split('\n', 1)[0] ) >= width)], word), text.split(' ') )

def fixpath(p):
    return shellquote(os.path.normpath(p))

def shellquote(s):
    return "'" + s.replace("'", "'\\''") + "'"

def init_options():
    global parser, options, args
    parser = OptionParser(usage="usage: %prog [options] filename", description="Add or Remove placeholder files for SCM (Source Control Management) tools that do not support empty directories.")
    parser.add_option("-p", "--path", dest="directory", help="search within PATH", metavar="PATH")
    parser.add_option("-r", "--remove", dest="remove", action="store_true", help="remove FILE from PATH, if it's the only file on PATH")

    (options, args) = parser.parse_args()

if __name__ == '__main__':
share|improve this answer
The link is dead. – Natim Oct 10 '12 at 7:30
True, updated link... – der Oct 11 '12 at 22:20
host it on bitbucket (or ) github , old pastebin is old – Phyo Arkar Lwin Dec 10 '12 at 15:28
-1, that script exemplifies nti-patterns and bad practices. – Nikratio Oct 5 '15 at 18:32

You simply do the following:

mkdir images && touch images/.hgkeep
hg add images/.hgkeep
hg commit -m"Add the images folder as an empty folder"

Note the following as a consideration when you do this:

In your case you might be uploading images in your development environment, so I would also recommend adding the following to your .hgignore file so you don't accidentally commit images you did not intend to commit:


The rule will ignore everything on images/** except the .hgkeep file you need to add an "empty" folder to version control. The reason why this rule is important, is that any files in that folder (ie. images/test-image.png will look like a new non-versioned file in your hg status if you don't ignore that pattern.

share|improve this answer
Please read the question again carefully. Your answer does not answer the original question, which asked "how to add an empty folder" not "How to ignore a folder" – DavidPostill Jun 26 '15 at 22:18
You're right. I've updated my answer to actually answer the question. I've altered my advice and left it because it's important to know and 99% of the time a desired behavior. – Paul Redmond Jul 1 '15 at 17:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .