{"thread":{"id":"8542","subject":"Adding empty directory gives bogus error message","startedAt":"2007-06-10T20:46:48Z","lastAt":"2007-06-12T21:51:04Z","messageCount":16,"participants":["Jonas Fonseca","Jeff King","Johannes Schindelin","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"44636","messageId":"20070610204648.GA32214@diku.dk","threadId":"8542","inReplyTo":null,"subject":"Adding empty directory gives bogus error message","fromName":"Jonas Fonseca","fromEmail":"fonseca@diku.dk","sentAt":"2007-06-10T20:46:48Z","receivedAt":"2007-06-10T20:46:48Z","isPatch":false,"sender":{"key":"fonseca@diku.dk","avatar":"https://gravatar.com/avatar/f82f3ad698717c51873b020c750a92438c820a24056dc39fe4d07baa10a92264?d=mp&s=160"},"body":"Hello,\n\nDuring a talk with madduck on #git today, we stumbled upon this\nconfusing error message:\n\n  $ mkdir repo\n  $ cd repo/\n  $ git init\n  Initialized empty Git repository in .git/\n  $ mkdir empty\n  $ git add empty/\n  The following paths are ignored by one of your .gitignore files:\n  empty/ (directory)\n  Use -f if you really want to add them.\n  $ git add -f empty/\n  fatal: unable to index file empty/\n\nFirst, it misleads the user by assuming that something was added to\n.gitignore or another exclude file, and the second error message is not\nvery helpful.\n\nLooking at the code, I am not sure how this can be fixed. Simply\nprinting a warning when finding \"some\" empty directory might do, but it\nis not the best way to help somebody new to git. Refusing to add\nanything when finding an empty directory deep in some hierarchy is not a\ngood option either.\n\nGit 1.4 silently did nothing, so 1.5 at least tries to be more clueful.\nAnyway, I thought I would mention it and see what happens. ;)\n\n-- \nJonas Fonseca\n"},{"id":"44720","messageId":"20070611123045.GA28814@coredump.intra.peff.net","threadId":"8542","inReplyTo":"20070610204648.GA32214@diku.dk","subject":"Re: Adding empty directory gives bogus error message","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-06-11T12:30:45Z","receivedAt":"2007-06-11T12:30:45Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Jun 10, 2007 at 10:46:48PM +0200, Jonas Fonseca wrote:\n\n> During a talk with madduck on #git today, we stumbled upon this\n> confusing error message:\n> \n>   $ mkdir repo\n>   $ cd repo/\n>   $ git init\n>   Initialized empty Git repository in .git/\n>   $ mkdir empty\n>   $ git add empty/\n>   The following paths are ignored by one of your .gitignore files:\n>   empty/ (directory)\n>   Use -f if you really want to add them.\n>   $ git add -f empty/\n>   fatal: unable to index file empty/\n\nUrgh, that's ugly. The problem is that git-add sticks\nassumed-to-be-ignored stuff back into the list of files found by\nread_directory, but with some special ignored flags (which aren't used\nanywhere else!). When the assumption is wrong (because the path is\n_actually_ just empty), you get the bogus message, and when you try to\nforce it, you get an error from elsewhere in the code.\n\nPatch series will be out momentarily.\n\n-Peff\n"},{"id":"44725","messageId":"20070611133944.GA7008@coredump.intra.peff.net","threadId":"8542","inReplyTo":"20070611123045.GA28814@coredump.intra.peff.net","subject":"[PATCH 1/3] refactor dir_add_name","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-06-11T13:39:44Z","receivedAt":"2007-06-11T13:39:44Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This is in preparation for keeping two entry lists in the\ndir object.\n\nThis patch adds and uses the alloc_grow macro, which\nimplements the commonly used idiom of growing a dynamic\narray using the alloc_nr function (not just in dir.c, but\neverywhere).\n\nWe also move creation of a dir_entry to dir_entry_new.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n\nIf we like the alloc_grow approach, there are a lot of places where we\ncan drop a 3-5 line conditional into a single line. I find it much more\nreadable, but others may disagree.\n\n cache.h |    6 ++++++\n dir.c   |   23 +++++++++++------------\n 2 files changed, 17 insertions(+), 12 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 5e7381e..f771519 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -224,6 +224,12 @@ extern void verify_filename(const char *prefix, const char *name);\n extern void verify_non_filename(const char *prefix, const char *name);\n \n #define alloc_nr(x) (((x)+16)*3/2)\n+#define alloc_grow(x, nr, alloc) do { \\\n+\tif(nr >= alloc) { \\\n+\t\talloc = alloc_nr(alloc); \\\n+\t\tx = xrealloc((x), alloc * sizeof(*(x))); \\\n+\t} \\\n+} while(0)\n \n /* Initialize and use the cache information */\n extern int read_index(struct index_state *);\ndiff --git a/dir.c b/dir.c\nindex f543f50..e810258 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -271,27 +271,26 @@ int excluded(struct dir_struct *dir, const char *pathname)\n \treturn 0;\n }\n \n-struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)\n-{\n+static\n+struct dir_entry *dir_entry_new(const char *pathname, int len) {\n \tstruct dir_entry *ent;\n-\n-\tif (cache_name_pos(pathname, len) >= 0)\n-\t\treturn NULL;\n-\n-\tif (dir->nr == dir->alloc) {\n-\t\tint alloc = alloc_nr(dir->alloc);\n-\t\tdir->alloc = alloc;\n-\t\tdir->entries = xrealloc(dir->entries, alloc*sizeof(ent));\n-\t}\n \tent = xmalloc(sizeof(*ent) + len + 1);\n \tent->ignored = ent->ignored_dir = 0;\n \tent->len = len;\n \tmemcpy(ent->name, pathname, len);\n \tent->name[len] = 0;\n-\tdir->entries[dir->nr++] = ent;\n \treturn ent;\n }\n \n+struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)\n+{\n+\tif (cache_name_pos(pathname, len) >= 0)\n+\t\treturn NULL;\n+\n+\talloc_grow(dir->entries, dir->nr, dir->alloc);\n+\treturn dir->entries[dir->nr++] = dir_entry_new(pathname, len);\n+}\n+\n enum exist_status {\n \tindex_nonexistent = 0,\n \tindex_directory,\n-- \n1.5.2.1.958.gbaa74-dirty\n"},{"id":"44723","messageId":"20070611133950.GB7008@coredump.intra.peff.net","threadId":"8542","inReplyTo":"20070611123045.GA28814@coredump.intra.peff.net","subject":"[PATCH 2/3] dir_struct: add collect_ignored option","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-06-11T13:39:50Z","receivedAt":"2007-06-11T13:39:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"When set, this option will cause read_directory to keep\ntrack of which entries were ignored. While this shouldn't\neffect functionality in most cases, it can make warning\nmessages to the user much more useful.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n dir.c |   12 ++++++++++++\n dir.h |    5 ++++-\n 2 files changed, 16 insertions(+), 1 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex e810258..1ffc1e5 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -291,6 +291,15 @@ struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int\n \treturn dir->entries[dir->nr++] = dir_entry_new(pathname, len);\n }\n \n+struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)\n+{\n+\tif(cache_name_pos(pathname, len) >= 0)\n+\t\treturn NULL;\n+\n+\talloc_grow(dir->ignored, dir->ignored_nr, dir->ignored_alloc);\n+\treturn dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len);\n+}\n+\n enum exist_status {\n \tindex_nonexistent = 0,\n \tindex_directory,\n@@ -463,6 +472,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co\n \t\t\t\tcontinue;\n \n \t\t\texclude = excluded(dir, fullname);\n+\t\t\tif (exclude && dir->collect_ignored)\n+\t\t\t\tdir_add_ignored(dir, fullname, baselen + len);\n \t\t\tif (exclude != dir->show_ignored) {\n \t\t\t\tif (!dir->show_ignored || DTYPE(de) != DT_DIR) {\n \t\t\t\t\tcontinue;\n@@ -609,6 +620,7 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i\n \tread_directory_recursive(dir, path, base, baselen, 0, simplify);\n \tfree_simplify(simplify);\n \tqsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);\n+\tqsort(dir->ignored, dir->ignored_nr, sizeof(*dir->ignored), cmp_name);\n \treturn dir->nr;\n }\n \ndiff --git a/dir.h b/dir.h\nindex 172147f..c94f3cb 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -31,11 +31,14 @@ struct exclude_list {\n \n struct dir_struct {\n \tint nr, alloc;\n+\tint ignored_nr, ignored_alloc;\n \tunsigned int show_ignored:1,\n \t\t     show_other_directories:1,\n \t\t     hide_empty_directories:1,\n-\t\t     no_gitlinks:1;\n+\t\t     no_gitlinks:1,\n+\t\t     collect_ignored:1;\n \tstruct dir_entry **entries;\n+\tstruct dir_entry **ignored;\n \n \t/* Exclude info */\n \tconst char *exclude_per_dir;\n-- \n1.5.2.1.958.gbaa74-dirty\n"},{"id":"44724","messageId":"20070611133956.GC7008@coredump.intra.peff.net","threadId":"8542","inReplyTo":"20070611123045.GA28814@coredump.intra.peff.net","subject":"[PATCH 3/3] builtin-add: simplify (and increase accuracy of) exclude handling","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-06-11T13:39:56Z","receivedAt":"2007-06-11T13:39:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Previously, the code would always set up the excludes, and then manually\npick through the pathspec we were given, assuming that non-added but\nexisting paths were just ignored. This was mostly correct, but would\nerroneously mark a totally empty directory as 'ignored'.\n\nInstead, we now use the collect_ignored option of dir_struct, which\nunambiguously tells us whether a path was ignored. This simplifies the\ncode, and means empty directories are now just not mentioned at all.\n\nFurthermore, we now conditionally ask dir_struct to respect excludes,\ndepending on whether the '-f' flag has been set. This means we don't have\nto pick through the result, checking for an 'ignored' flag; ignored entries\nwere either added or not in the first place.\n\nWe can safely get rid of the special 'ignored' flags to dir_entry, which\nwere not used anywhere else.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin-add.c |   89 ++++++++++++++++++++++++++++++--------------------------\n dir.c         |    1 -\n dir.h         |    4 +--\n 3 files changed, 49 insertions(+), 45 deletions(-)\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 1591171..8988930 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -19,6 +19,23 @@ static const char builtin_add_usage[] =\n static int take_worktree_changes;\n static const char *excludes_file;\n \n+static int in_pathspec(const char *k, const char **pathspec) {\n+\twhile(*pathspec) {\n+\t\tif (!strcmp(k, *pathspec))\n+\t\t\treturn 1;\n+\t\tpathspec++;\n+\t}\n+\treturn 0;\n+}\n+\n+static void prune_ignored(struct dir_struct *dir, const char **pathspec) {\n+\tint i;\n+\tfor (i = 0; i < dir->ignored_nr; i++) {\n+\t\tif (!in_pathspec(dir->ignored[i]->name, pathspec))\n+\t\t\tdir->ignored[i] = NULL;\n+\t}\n+}\n+\n static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)\n {\n \tchar *seen;\n@@ -40,42 +57,29 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p\n \tdir->nr = dst - dir->entries;\n \n \tfor (i = 0; i < specs; i++) {\n-\t\tstruct stat st;\n-\t\tconst char *match;\n-\t\tif (seen[i])\n-\t\t\tcontinue;\n-\n-\t\tmatch = pathspec[i];\n-\t\tif (!match[0])\n-\t\t\tcontinue;\n-\n-\t\t/* Existing file? We must have ignored it */\n-\t\tif (!lstat(match, &st)) {\n-\t\t\tstruct dir_entry *ent;\n-\n-\t\t\tent = dir_add_name(dir, match, strlen(match));\n-\t\t\tent->ignored = 1;\n-\t\t\tif (S_ISDIR(st.st_mode))\n-\t\t\t\tent->ignored_dir = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tdie(\"pathspec '%s' did not match any files\", match);\n+\t\tif(!seen[i] && !file_exists(pathspec[i]))\n+\t\t\tdie(\"pathspec '%s' did not match any files\",\n+\t\t\t\t\tpathspec[i]);\n \t}\n }\n \n-static void fill_directory(struct dir_struct *dir, const char **pathspec)\n+static void fill_directory(struct dir_struct *dir, const char **pathspec,\n+\t\tint ignored_too)\n {\n \tconst char *path, *base;\n \tint baselen;\n \n \t/* Set up the default git porcelain excludes */\n \tmemset(dir, 0, sizeof(*dir));\n-\tdir->exclude_per_dir = \".gitignore\";\n-\tpath = git_path(\"info/exclude\");\n-\tif (!access(path, R_OK))\n-\t\tadd_excludes_from_file(dir, path);\n-\tif (!access(excludes_file, R_OK))\n-\t\tadd_excludes_from_file(dir, excludes_file);\n+\tif (!ignored_too) {\n+\t\tdir->collect_ignored = 1;\n+\t\tdir->exclude_per_dir = \".gitignore\";\n+\t\tpath = git_path(\"info/exclude\");\n+\t\tif (!access(path, R_OK))\n+\t\t\tadd_excludes_from_file(dir, path);\n+\t\tif (!access(excludes_file, R_OK))\n+\t\t\tadd_excludes_from_file(dir, excludes_file);\n+\t}\n \n \t/*\n \t * Calculate common prefix for the pathspec, and\n@@ -93,8 +97,10 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)\n \n \t/* Read the directory and prune it */\n \tread_directory(dir, path, base, baselen, pathspec);\n-\tif (pathspec)\n+\tif (pathspec) {\n+\t\tprune_ignored(dir, pathspec);\n \t\tprune_directory(dir, pathspec, baselen);\n+\t}\n }\n \n static void update_callback(struct diff_queue_struct *q,\n@@ -160,6 +166,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \tconst char **pathspec;\n \tstruct dir_struct dir;\n \tint add_interactive = 0;\n+\tint has_ignored;\n \n \tfor (i = 1; i < argc; i++) {\n \t\tif (!strcmp(\"--interactive\", argv[i]) ||\n@@ -219,13 +226,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t}\n \tpathspec = get_pathspec(prefix, argv + i);\n \n-\tfill_directory(&dir, pathspec);\n+\tfill_directory(&dir, pathspec, ignored_too);\n \n \tif (show_only) {\n \t\tconst char *sep = \"\", *eof = \"\";\n \t\tfor (i = 0; i < dir.nr; i++) {\n-\t\t\tif (!ignored_too && dir.entries[i]->ignored)\n-\t\t\t\tcontinue;\n \t\t\tprintf(\"%s%s\", sep, dir.entries[i]->name);\n \t\t\tsep = \" \";\n \t\t\teof = \"\\n\";\n@@ -237,25 +242,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \tif (read_cache() < 0)\n \t\tdie(\"index file corrupt\");\n \n-\tif (!ignored_too) {\n-\t\tint has_ignored = 0;\n-\t\tfor (i = 0; i < dir.nr; i++)\n-\t\t\tif (dir.entries[i]->ignored)\n-\t\t\t\thas_ignored = 1;\n-\t\tif (has_ignored) {\n-\t\t\tfprintf(stderr, ignore_warning);\n-\t\t\tfor (i = 0; i < dir.nr; i++) {\n-\t\t\t\tif (!dir.entries[i]->ignored)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tfprintf(stderr, \"%s\", dir.entries[i]->name);\n-\t\t\t\tif (dir.entries[i]->ignored_dir)\n-\t\t\t\t\tfprintf(stderr, \" (directory)\");\n-\t\t\t\tfputc('\\n', stderr);\n-\t\t\t}\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Use -f if you really want to add them.\\n\");\n-\t\t\texit(1);\n+\thas_ignored = 0;\n+\tfor (i = 0; i < dir.ignored_nr; i++) {\n+\t\tif (dir.ignored[i])\n+\t\t\thas_ignored = 1;\n+\t}\n+\tif (has_ignored) {\n+\t\tfprintf(stderr, ignore_warning);\n+\t\tfor (i = 0; i < dir.ignored_nr; i++) {\n+\t\t\tif (dir.ignored[i])\n+\t\t\t\tfprintf(stderr, \"%s\\n\", dir.ignored[i]->name);\n \t\t}\n+\t\tfprintf(stderr, \"Use -f if you really want to add them.\\n\");\n+\t\texit(1);\n \t}\n \n \tfor (i = 0; i < dir.nr; i++)\ndiff --git a/dir.c b/dir.c\nindex 1ffc1e5..d903a49 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -275,7 +275,6 @@ static\n struct dir_entry *dir_entry_new(const char *pathname, int len) {\n \tstruct dir_entry *ent;\n \tent = xmalloc(sizeof(*ent) + len + 1);\n-\tent->ignored = ent->ignored_dir = 0;\n \tent->len = len;\n \tmemcpy(ent->name, pathname, len);\n \tent->name[len] = 0;\ndiff --git a/dir.h b/dir.h\nindex c94f3cb..ec0e8ab 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -13,9 +13,7 @@\n \n \n struct dir_entry {\n-\tunsigned int ignored : 1;\n-\tunsigned int ignored_dir : 1;\n-\tunsigned int len : 30;\n+\tunsigned int len;\n \tchar name[FLEX_ARRAY]; /* more */\n };\n \n"},{"id":"44727","messageId":"Pine.LNX.4.64.0706111512580.4059@racer.site","threadId":"8542","inReplyTo":"20070611133944.GA7008@coredump.intra.peff.net","subject":"Re: [PATCH 1/3] refactor dir_add_name","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-11T14:13:14Z","receivedAt":"2007-06-11T14:13:14Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 11 Jun 2007, Jeff King wrote:\n\n> If we like the alloc_grow approach, there are a lot of places where we \n> can drop a 3-5 line conditional into a single line. I find it much more \n> readable, but others may disagree.\n\nI like it!\n\nCiao,\nDscho\n"},{"id":"44730","messageId":"20070611150122.GA11020@diku.dk","threadId":"8542","inReplyTo":"20070611133956.GC7008@coredump.intra.peff.net","subject":"Re: [PATCH 3/3] builtin-add: simplify (and increase accuracy of) exclude handling","fromName":"Jonas Fonseca","fromEmail":"fonseca@diku.dk","sentAt":"2007-06-11T15:01:23Z","receivedAt":"2007-06-11T15:01:23Z","isPatch":true,"sender":{"key":"fonseca@diku.dk","avatar":"https://gravatar.com/avatar/f82f3ad698717c51873b020c750a92438c820a24056dc39fe4d07baa10a92264?d=mp&s=160"},"body":"Hej Jeff,\n\nThanks for looking into this and making these patches. :)\n\nJeff King <peff@peff.net> wrote Mon, Jun 11, 2007:\n>  builtin-add.c |   89 ++++++++++++++++++++++++++++++--------------------------\n>  dir.c         |    1 -\n>  dir.h         |    4 +--\n>  3 files changed, 49 insertions(+), 45 deletions(-)\n> \n> diff --git a/builtin-add.c b/builtin-add.c\n> index 1591171..8988930 100644\n> --- a/builtin-add.c\n> +++ b/builtin-add.c\n> @@ -160,6 +166,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n>  \tconst char **pathspec;\n>  \tstruct dir_struct dir;\n>  \tint add_interactive = 0;\n> +\tint has_ignored;\n>  \n>  \tfor (i = 1; i < argc; i++) {\n>  \t\tif (!strcmp(\"--interactive\", argv[i]) ||\n> @@ -237,25 +242,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n>  \tif (read_cache() < 0)\n>  \t\tdie(\"index file corrupt\");\n>  \n> -\tif (!ignored_too) {\n> -\t\tint has_ignored = 0;\n> -\t\tfor (i = 0; i < dir.nr; i++)\n> -\t\t\tif (dir.entries[i]->ignored)\n> -\t\t\t\thas_ignored = 1;\n> -\t\tif (has_ignored) {\n> -\t\t\tfprintf(stderr, ignore_warning);\n> -\t\t\tfor (i = 0; i < dir.nr; i++) {\n> -\t\t\t\tif (!dir.entries[i]->ignored)\n> -\t\t\t\t\tcontinue;\n> -\t\t\t\tfprintf(stderr, \"%s\", dir.entries[i]->name);\n> -\t\t\t\tif (dir.entries[i]->ignored_dir)\n> -\t\t\t\t\tfprintf(stderr, \" (directory)\");\n> -\t\t\t\tfputc('\\n', stderr);\n> -\t\t\t}\n> -\t\t\tfprintf(stderr,\n> -\t\t\t\t\"Use -f if you really want to add them.\\n\");\n> -\t\t\texit(1);\n> +\thas_ignored = 0;\n> +\tfor (i = 0; i < dir.ignored_nr; i++) {\n> +\t\tif (dir.ignored[i])\n> +\t\t\thas_ignored = 1;\n> +\t}\n> +\tif (has_ignored) {\n> +\t\tfprintf(stderr, ignore_warning);\n> +\t\tfor (i = 0; i < dir.ignored_nr; i++) {\n> +\t\t\tif (dir.ignored[i])\n> +\t\t\t\tfprintf(stderr, \"%s\\n\", dir.ignored[i]->name);\n>  \t\t}\n> +\t\tfprintf(stderr, \"Use -f if you really want to add them.\\n\");\n> +\t\texit(1);\n>  \t}\n>  \n>  \tfor (i = 0; i < dir.nr; i++)\n\nI think you could even get rid of has_ignored with something like this.\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 8988930..da6ab11 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -166,7 +166,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \tconst char **pathspec;\n \tstruct dir_struct dir;\n \tint add_interactive = 0;\n-\tint has_ignored;\n \n \tfor (i = 1; i < argc; i++) {\n \t\tif (!strcmp(\"--interactive\", argv[i]) ||\n@@ -242,12 +241,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \tif (read_cache() < 0)\n \t\tdie(\"index file corrupt\");\n \n-\thas_ignored = 0;\n-\tfor (i = 0; i < dir.ignored_nr; i++) {\n-\t\tif (dir.ignored[i])\n-\t\t\thas_ignored = 1;\n-\t}\n-\tif (has_ignored) {\n+\tif (dir.ignored_nr) {\n \t\tfprintf(stderr, ignore_warning);\n \t\tfor (i = 0; i < dir.ignored_nr; i++) {\n \t\t\tif (dir.ignored[i])\n\n-- \nJonas Fonseca\n"},{"id":"44733","messageId":"20070611155425.GA9316@coredump.intra.peff.net","threadId":"8542","inReplyTo":"20070611150122.GA11020@diku.dk","subject":"Re: [PATCH 3/3] builtin-add: simplify (and increase accuracy of) exclude handling","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-06-11T15:54:25Z","receivedAt":"2007-06-11T15:54:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 11, 2007 at 05:01:23PM +0200, Jonas Fonseca wrote:\n\n> Thanks for looking into this and making these patches. :)\n\nNo problem. I had run it across it before and it was on my \"look into\nthis\" list...thank you for providing a test case. :)\n\n> I think you could even get rid of has_ignored with something like this.\n\nNope, I had originally wanted to do that, but the dir_struct.ignored\nlist contains _all_ ignored items, not just those that were originally\nin the pathspec. The prune_ignored call sets uninteresting ones to\nNULL.  That function could compact the list and re-set ignored_nr, but\nit doesn't currently do so.\n\nAn even more elegant solution would be for read_directory to mark\nwhether an ignored file comes from a pathspec, or was found through\nrecursion. That would be more efficient, and it would remove the\nprune_ignored thing, which is IMHO a little hack-ish.\n\nI don't have time to work on it now, but I might look at it more tonight\nor tomorrow (but please, if you are interested, take a crack at it).\n\n-Peff\n"},{"id":"44736","messageId":"7vk5uaqx3q.fsf@assigned-by-dhcp.pobox.com","threadId":"8542","inReplyTo":"20070611133944.GA7008@coredump.intra.peff.net","subject":"Re: [PATCH 1/3] refactor dir_add_name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-11T16:23:05Z","receivedAt":"2007-06-11T16:23:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> If we like the alloc_grow approach, there are a lot of places where we\n> can drop a 3-5 line conditional into a single line. I find it much more\n> readable, but others may disagree.\n\nI like the readability, but\n\n>  cache.h |    6 ++++++\n>  dir.c   |   23 +++++++++++------------\n>  2 files changed, 17 insertions(+), 12 deletions(-)\n>\n> diff --git a/cache.h b/cache.h\n> index 5e7381e..f771519 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -224,6 +224,12 @@ extern void verify_filename(const char *prefix, const char *name);\n>  extern void verify_non_filename(const char *prefix, const char *name);\n>  \n>  #define alloc_nr(x) (((x)+16)*3/2)\n> +#define alloc_grow(x, nr, alloc) do { \\\n> +\tif(nr >= alloc) { \\\n> +\t\talloc = alloc_nr(alloc); \\\n> +\t\tx = xrealloc((x), alloc * sizeof(*(x))); \\\n> +\t} \\\n> +} while(0)\n\nworry a bit about macro safety.  I think the presence of an\nassignment to alloc and x would make sure we would catch an\nerror to pass non lvalue as 'alloc' and 'x', so it may be Ok as\nis.  A comment before the macro, and a space between 'if' and\nopening parenthesis, would be good things to have.\n"},{"id":"44749","messageId":"20070611191554.GA32151@diku.dk","threadId":"8542","inReplyTo":"20070611155425.GA9316@coredump.intra.peff.net","subject":"Re: [PATCH 3/3] builtin-add: simplify (and increase accuracy of) exclude handling","fromName":"Jonas Fonseca","fromEmail":"fonseca@diku.dk","sentAt":"2007-06-11T19:15:54Z","receivedAt":"2007-06-11T19:15:54Z","isPatch":true,"sender":{"key":"fonseca@diku.dk","avatar":"https://gravatar.com/avatar/f82f3ad698717c51873b020c750a92438c820a24056dc39fe4d07baa10a92264?d=mp&s=160"},"body":"Jeff King <peff@peff.net> wrote Mon, Jun 11, 2007:\n> On Mon, Jun 11, 2007 at 05:01:23PM +0200, Jonas Fonseca wrote:\n> > I think you could even get rid of has_ignored with something like this.\n> \n> Nope, I had originally wanted to do that, but the dir_struct.ignored\n> list contains _all_ ignored items, not just those that were originally\n> in the pathspec. The prune_ignored call sets uninteresting ones to\n> NULL.  That function could compact the list and re-set ignored_nr, but\n> it doesn't currently do so.\n\nAh, I see.\n\n> An even more elegant solution would be for read_directory to mark\n> whether an ignored file comes from a pathspec, or was found through\n> recursion. That would be more efficient, and it would remove the\n> prune_ignored thing, which is IMHO a little hack-ish.\n> \n> I don't have time to work on it now, but I might look at it more tonight\n> or tomorrow (but please, if you are interested, take a crack at it).\n\nYes, I think it might be nice for me to do if you don't mind. I would\nlike some more experience with the git code. Maybe even redo the whole\npatch series to also fix the concerns about the alloc_grow macro.\n\n-- \nJonas Fonseca\n"},{"id":"44750","messageId":"20070611194651.GA15309@coredump.intra.peff.net","threadId":"8542","inReplyTo":"7vk5uaqx3q.fsf@assigned-by-dhcp.pobox.com","subject":"Re: [PATCH 1/3] refactor dir_add_name","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-06-11T19:46:51Z","receivedAt":"2007-06-11T19:46:51Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 11, 2007 at 09:23:05AM -0700, Junio C Hamano wrote:\n\n> > +#define alloc_grow(x, nr, alloc) do { \\\n> > +\tif(nr >= alloc) { \\\n> > +\t\talloc = alloc_nr(alloc); \\\n> > +\t\tx = xrealloc((x), alloc * sizeof(*(x))); \\\n> > +\t} \\\n> > +} while(0)\n> \n> worry a bit about macro safety.  I think the presence of an\n\nAgreed. The multiple evaluation of 'x' means that growing foo[i++] will\ncause quite a confusing bug. I would prefer it as an inline, but at\nleast the sizeof requires macro magic. Not to mention the ugliness of\nmoving all those lvalues as pointers. But we could do something like\n(totally untested):\n\n#define alloc_grow(x, nr, alloc) \\\n  alloc_grow_helper(&(x), nr, &(alloc), sizeof(*(x)))\n\ninline\nvoid alloc_grow_helper(void **x, int nr, int *alloc, int size)\n{\n  if (nr >= *alloc) {\n    *alloc = alloc_nr(*alloc);\n    *x = xrealloc(*x, *alloc * size);\n  }\n}\n\nHorribly ugly (I'm seeing stars!) but probably a bit safer in the long\nrun, and nobody needs to look at it most of the time. :)\n\nWhat do you think?\n\n> assignment to alloc and x would make sure we would catch an\n> error to pass non lvalue as 'alloc' and 'x', so it may be Ok as\n\nEven lvalues can have side effects, so multiple evaluation is still a\nproblem.\n\n> is.  A comment before the macro, and a space between 'if' and\n> opening parenthesis, would be good things to have.\n\nYes, sorry, my fingers are always forgetting the git whitespace\nconventions. I (or Jonas) will submit a better commented version, but do\nlet us know which version you like.\n\n-Peff\n"},{"id":"44751","messageId":"20070611194810.GB15309@coredump.intra.peff.net","threadId":"8542","inReplyTo":"20070611191554.GA32151@diku.dk","subject":"Re: [PATCH 3/3] builtin-add: simplify (and increase accuracy of) exclude handling","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-06-11T19:48:10Z","receivedAt":"2007-06-11T19:48:10Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Jun 11, 2007 at 09:15:54PM +0200, Jonas Fonseca wrote:\n\n> > I don't have time to work on it now, but I might look at it more tonight\n> > or tomorrow (but please, if you are interested, take a crack at it).\n> \n> Yes, I think it might be nice for me to do if you don't mind. I would\n> like some more experience with the git code. Maybe even redo the whole\n> patch series to also fix the concerns about the alloc_grow macro.\n\nGreat, feel free to rework the series as you see fit. My \"tonight\"\ntimeframe was a bit optimistic anyway, as we have a new baby here. :)\n\n-Peff\n"},{"id":"44803","messageId":"7v7iq9lk76.fsf@assigned-by-dhcp.pobox.com","threadId":"8542","inReplyTo":"20070611194651.GA15309@coredump.intra.peff.net","subject":"Re: [PATCH 1/3] refactor dir_add_name","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-12T07:13:01Z","receivedAt":"2007-06-12T07:13:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> ... But we could do something like\n> (totally untested):\n>\n> #define alloc_grow(x, nr, alloc) \\\n>   alloc_grow_helper(&(x), nr, &(alloc), sizeof(*(x)))\n>\n> inline\n> void alloc_grow_helper(void **x, int nr, int *alloc, int size)\n> {\n>   if (nr >= *alloc) {\n>     *alloc = alloc_nr(*alloc);\n>     *x = xrealloc(*x, *alloc * size);\n>   }\n> }\n>\n> Horribly ugly (I'm seeing stars!) but probably a bit safer in the long\n> run, and nobody needs to look at it most of the time. :)\n>\n> What do you think?\n\nThat looks ugly and also I am curious what the generated\nassembly would look like.  Hopefully the compiler is clever\nenough to generate the same code, but I dunno.\n\nUnless somebody else more versed with C preprocessor tricks\ncomes along and offers a better advice, I would go with the\nearlier simpler one with a big fat warning.  I however would\nprefer all caps name for a magic macro like this, whose sole\npoint is a huge side effect.\n\nAnyway, it appears that Jonas picked up your patch to polish up,\nso I won't touch this series until that resurfaces.\n"},{"id":"44826","messageId":"20070612121939.GB25145@coredump.intra.peff.net","threadId":"8542","inReplyTo":"7v7iq9lk76.fsf@assigned-by-dhcp.pobox.com","subject":"Re: [PATCH 1/3] refactor dir_add_name","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2007-06-12T12:19:39Z","receivedAt":"2007-06-12T12:19:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jun 12, 2007 at 12:13:01AM -0700, Junio C Hamano wrote:\n\n> That looks ugly and also I am curious what the generated\n> assembly would look like.  Hopefully the compiler is clever\n> enough to generate the same code, but I dunno.\n\nI was curious, too...the assembly generated by gcc -O2 is identical for\nboth versions.\n\n> Unless somebody else more versed with C preprocessor tricks\n> comes along and offers a better advice, I would go with the\n> earlier simpler one with a big fat warning.  I however would\n> prefer all caps name for a magic macro like this, whose sole\n> point is a huge side effect.\n\nAgreed on the all-caps (in either case) because of the side effects.\nThe more I think about it, I think the inline'd version is better.\nMultiple evaluation pre-processor bugs are _nasty_ to find, and while\nthe implementation is ugly, it's better to contain the ugliness to one\nspot than to introduce a dangerous interface that will be used all over.\n\nI'm a bit rusty on my preprocessor tricks, but ISTR that there really\nisn't a good way to portably avoid the problems. gcc has typeof, which\nwe could use to make temporary copies (which gcc would presumably\noptimize out), but I imagine we don't want to be gcc-specific. We could\nconditionally use that construct, but maybe at that point we're getting\nas ugly as the inline).\n\n-Peff\n"},{"id":"44874","messageId":"20070612214214.GA21858@diku.dk","threadId":"8542","inReplyTo":"20070611155425.GA9316@coredump.intra.peff.net","subject":"Re: [PATCH 3/3] builtin-add: simplify (and increase accuracy of) exclude handling","fromName":"Jonas Fonseca","fromEmail":"fonseca@diku.dk","sentAt":"2007-06-12T21:42:14Z","receivedAt":"2007-06-12T21:42:14Z","isPatch":true,"sender":{"key":"fonseca@diku.dk","avatar":"https://gravatar.com/avatar/f82f3ad698717c51873b020c750a92438c820a24056dc39fe4d07baa10a92264?d=mp&s=160"},"body":"From: Jeff King <peff@peff.net>\n\nPreviously, the code would always set up the excludes, and then manually\npick through the pathspec we were given, assuming that non-added but\nexisting paths were just ignored. This was mostly correct, but would\nerroneously mark a totally empty directory as 'ignored'.\n\nInstead, we now use the collect_ignored option of dir_struct, which\nunambiguously tells us whether a path was ignored. This simplifies the\ncode, and means empty directories are now just not mentioned at all.\n\nFurthermore, we now conditionally ask dir_struct to respect excludes,\ndepending on whether the '-f' flag has been set. This means we don't have\nto pick through the result, checking for an 'ignored' flag; ignored entries\nwere either added or not in the first place.\n\nWe can safely get rid of the special 'ignored' flags to dir_entry, which\nwere not used anywhere else.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Jonas Fonseca <fonseca@diku.dk>\n---\n builtin-add.c |   69 +++++++++++++++++---------------------------------------\n dir.c         |   16 +++++++++++-\n dir.h         |    4 +--\n 3 files changed, 36 insertions(+), 53 deletions(-)\n\n Jeff King <peff@peff.net> wrote Mon, Jun 11, 2007:\n > On Mon, Jun 11, 2007 at 05:01:23PM +0200, Jonas Fonseca wrote:\n > > I think you could even get rid of has_ignored with something like this.\n > \n > Nope, I had originally wanted to do that, but the dir_struct.ignored\n > list contains _all_ ignored items, not just those that were originally\n > in the pathspec. The prune_ignored call sets uninteresting ones to\n > NULL.  That function could compact the list and re-set ignored_nr, but\n > it doesn't currently do so.\n > \n > An even more elegant solution would be for read_directory to mark\n > whether an ignored file comes from a pathspec, or was found through\n > recursion. That would be more efficient, and it would remove the\n > prune_ignored thing, which is IMHO a little hack-ish.\n\n OK, I tried to do this, however, I got a bit confused with the intended\n behavior. Anyway, it passes the test suite, is silent for empty\n directories and will only show exact matches of the pathspec (this was\n the confusing part) as ignored items.\n\ndiff --git a/builtin-add.c b/builtin-add.c\nindex 1591171..ad6aca8 100644\n--- a/builtin-add.c\n+++ b/builtin-add.c\n@@ -40,42 +40,29 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p\n \tdir->nr = dst - dir->entries;\n \n \tfor (i = 0; i < specs; i++) {\n-\t\tstruct stat st;\n-\t\tconst char *match;\n-\t\tif (seen[i])\n-\t\t\tcontinue;\n-\n-\t\tmatch = pathspec[i];\n-\t\tif (!match[0])\n-\t\t\tcontinue;\n-\n-\t\t/* Existing file? We must have ignored it */\n-\t\tif (!lstat(match, &st)) {\n-\t\t\tstruct dir_entry *ent;\n-\n-\t\t\tent = dir_add_name(dir, match, strlen(match));\n-\t\t\tent->ignored = 1;\n-\t\t\tif (S_ISDIR(st.st_mode))\n-\t\t\t\tent->ignored_dir = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tdie(\"pathspec '%s' did not match any files\", match);\n+\t\tif(!seen[i] && !file_exists(pathspec[i]))\n+\t\t\tdie(\"pathspec '%s' did not match any files\",\n+\t\t\t\t\tpathspec[i]);\n \t}\n }\n \n-static void fill_directory(struct dir_struct *dir, const char **pathspec)\n+static void fill_directory(struct dir_struct *dir, const char **pathspec,\n+\t\tint ignored_too)\n {\n \tconst char *path, *base;\n \tint baselen;\n \n \t/* Set up the default git porcelain excludes */\n \tmemset(dir, 0, sizeof(*dir));\n-\tdir->exclude_per_dir = \".gitignore\";\n-\tpath = git_path(\"info/exclude\");\n-\tif (!access(path, R_OK))\n-\t\tadd_excludes_from_file(dir, path);\n-\tif (!access(excludes_file, R_OK))\n-\t\tadd_excludes_from_file(dir, excludes_file);\n+\tif (!ignored_too) {\n+\t\tdir->collect_ignored = 1;\n+\t\tdir->exclude_per_dir = \".gitignore\";\n+\t\tpath = git_path(\"info/exclude\");\n+\t\tif (!access(path, R_OK))\n+\t\t\tadd_excludes_from_file(dir, path);\n+\t\tif (!access(excludes_file, R_OK))\n+\t\t\tadd_excludes_from_file(dir, excludes_file);\n+\t}\n \n \t/*\n \t * Calculate common prefix for the pathspec, and\n@@ -219,13 +206,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \t}\n \tpathspec = get_pathspec(prefix, argv + i);\n \n-\tfill_directory(&dir, pathspec);\n+\tfill_directory(&dir, pathspec, ignored_too);\n \n \tif (show_only) {\n \t\tconst char *sep = \"\", *eof = \"\";\n \t\tfor (i = 0; i < dir.nr; i++) {\n-\t\t\tif (!ignored_too && dir.entries[i]->ignored)\n-\t\t\t\tcontinue;\n \t\t\tprintf(\"%s%s\", sep, dir.entries[i]->name);\n \t\t\tsep = \" \";\n \t\t\teof = \"\\n\";\n@@ -237,25 +222,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)\n \tif (read_cache() < 0)\n \t\tdie(\"index file corrupt\");\n \n-\tif (!ignored_too) {\n-\t\tint has_ignored = 0;\n-\t\tfor (i = 0; i < dir.nr; i++)\n-\t\t\tif (dir.entries[i]->ignored)\n-\t\t\t\thas_ignored = 1;\n-\t\tif (has_ignored) {\n-\t\t\tfprintf(stderr, ignore_warning);\n-\t\t\tfor (i = 0; i < dir.nr; i++) {\n-\t\t\t\tif (!dir.entries[i]->ignored)\n-\t\t\t\t\tcontinue;\n-\t\t\t\tfprintf(stderr, \"%s\", dir.entries[i]->name);\n-\t\t\t\tif (dir.entries[i]->ignored_dir)\n-\t\t\t\t\tfprintf(stderr, \" (directory)\");\n-\t\t\t\tfputc('\\n', stderr);\n-\t\t\t}\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Use -f if you really want to add them.\\n\");\n-\t\t\texit(1);\n+\tif (dir.ignored_nr) {\n+\t\tfprintf(stderr, ignore_warning);\n+\t\tfor (i = 0; i < dir.ignored_nr; i++) {\n+\t\t\tfprintf(stderr, \"%s\\n\", dir.ignored[i]->name);\n \t\t}\n+\t\tfprintf(stderr, \"Use -f if you really want to add them.\\n\");\n+\t\texit(1);\n \t}\n \n \tfor (i = 0; i < dir.nr; i++)\ndiff --git a/dir.c b/dir.c\nindex 1ffc1e5..f3a6757 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -275,7 +275,6 @@ static\n struct dir_entry *dir_entry_new(const char *pathname, int len) {\n \tstruct dir_entry *ent;\n \tent = xmalloc(sizeof(*ent) + len + 1);\n-\tent->ignored = ent->ignored_dir = 0;\n \tent->len = len;\n \tmemcpy(ent->name, pathname, len);\n \tent->name[len] = 0;\n@@ -432,6 +431,18 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli\n \treturn 0;\n }\n \n+static int in_pathspec(const char *path, int len, const struct path_simplify *simplify)\n+{\n+\tif (simplify) {\n+\t\tfor (; simplify->path; simplify++) {\n+\t\t\tif (len == simplify->len\n+\t\t\t    && !memcmp(path, simplify->path, len))\n+\t\t\t\treturn 1;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n /*\n  * Read a directory tree. We currently ignore anything but\n  * directories, regular files and symlinks. That's because git\n@@ -472,7 +483,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co\n \t\t\t\tcontinue;\n \n \t\t\texclude = excluded(dir, fullname);\n-\t\t\tif (exclude && dir->collect_ignored)\n+\t\t\tif (exclude && dir->collect_ignored\n+\t\t\t    && in_pathspec(fullname, baselen + len, simplify))\n \t\t\t\tdir_add_ignored(dir, fullname, baselen + len);\n \t\t\tif (exclude != dir->show_ignored) {\n \t\t\t\tif (!dir->show_ignored || DTYPE(de) != DT_DIR) {\ndiff --git a/dir.h b/dir.h\nindex c94f3cb..ec0e8ab 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -13,9 +13,7 @@\n \n \n struct dir_entry {\n-\tunsigned int ignored : 1;\n-\tunsigned int ignored_dir : 1;\n-\tunsigned int len : 30;\n+\tunsigned int len;\n \tchar name[FLEX_ARRAY]; /* more */\n };\n \n-- \n1.5.2.1.958.g264c-dirty\n\n-- \nJonas Fonseca\n"},{"id":"44876","messageId":"20070612215104.GB21858@diku.dk","threadId":"8542","inReplyTo":"7v7iq9lk76.fsf@assigned-by-dhcp.pobox.com","subject":"Re: [PATCH 1/3] refactor dir_add_name","fromName":"Jonas Fonseca","fromEmail":"fonseca@diku.dk","sentAt":"2007-06-12T21:51:04Z","receivedAt":"2007-06-12T21:51:04Z","isPatch":true,"sender":{"key":"fonseca@diku.dk","avatar":"https://gravatar.com/avatar/f82f3ad698717c51873b020c750a92438c820a24056dc39fe4d07baa10a92264?d=mp&s=160"},"body":"Junio C Hamano <gitster@pobox.com> wrote Tue, Jun 12, 2007:\n> Anyway, it appears that Jonas picked up your patch to polish up,\n> so I won't touch this series until that resurfaces.\n\nMy idea was to put the nr, alloc, and entries members into a separate\nstruct dir_entry_list, which should allow the dir_add_* functions to be\n\"united\" and thus somewhat remove the need for alloc_grow. However,\nafter spending some time on it, changing dir.nr to dir.entry_list.nr\netc. reduced readability so much that I ended up trying to make other\ncleanups and the simplicity of the series was lost.\n\nAnyway, I don't think I can come up with a more polished version without\nadding a few cleanup patches along the way. So I think apart from the\namended version of 3/3 I will take back my intension to polish it up.\n\n-- \nJonas Fonseca\n"}]}