Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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 36 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 – V3ss0n 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

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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