{"thread":{"id":"3476","subject":"cg-status and empty directories","startedAt":"2006-02-27T14:43:32Z","lastAt":"2006-03-26T21:37:33Z","messageCount":7,"participants":["Jim MacBaine","Andreas Ericsson","Petr Baudis","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"16818","messageId":"3afbacad0602270643k9fdd255w8f3769ad77c54e65@mail.gmail.com","threadId":"3476","inReplyTo":null,"subject":"cg-status and empty directories","fromName":"Jim MacBaine","fromEmail":"jmacbaine@gmail.com","sentAt":"2006-02-27T14:43:32Z","receivedAt":"2006-02-27T14:43:32Z","isPatch":false,"sender":{"key":"jmacbaine@gmail.com","avatar":null},"body":"Hello,\n\nShort story: Recently I noticed a change in the way, cogito handles\nempty directories.  Before, empty directories have been silently\nignored. Now cg-status always lists the status of empty directories as\nunknown, but it still refuses to add them. If there is a good reason\nfor this behaviour, can someone enlighten me?\n\nLong story: I'm using cogito to track and distribute changes on the\n/etc directories of a few (almost) identical machines.  Whenever I\ninstall a package which modifies somthing in /etc, I commit those\nchanges.  But with cg-status reporting all the empty directories as\n\"unknown\", my brain needs a long time to parse the list and find the\nreally unknown files which shall be put under version control.\n\nMany packages put empty directories under /etc, and although only a\nfew of those directories are actually needed, the automatic removal of\nthose packages will fail if I remove the empty directories manually.  \nEqually, the removal will fail, if I put a .placeholder file into\nthose direrectories and cg-add it.  Is there a simple way out?\n\nRegards,\nJim\n"},{"id":"16820","messageId":"44031941.1020806@op5.se","threadId":"3476","inReplyTo":"3afbacad0602270643k9fdd255w8f3769ad77c54e65@mail.gmail.com","subject":"Re: cg-status and empty directories","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-02-27T15:22:41Z","receivedAt":"2006-02-27T15:22:41Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Jim MacBaine wrote:\n> Hello,\n> \n> Short story: Recently I noticed a change in the way, cogito handles\n> empty directories.  Before, empty directories have been silently\n> ignored. Now cg-status always lists the status of empty directories as\n> unknown, but it still refuses to add them. If there is a good reason\n> for this behaviour, can someone enlighten me?\n> \n> Long story: I'm using cogito to track and distribute changes on the\n> /etc directories of a few (almost) identical machines.  Whenever I\n> install a package which modifies somthing in /etc, I commit those\n> changes.  But with cg-status reporting all the empty directories as\n> \"unknown\", my brain needs a long time to parse the list and find the\n> really unknown files which shall be put under version control.\n> \n> Many packages put empty directories under /etc, and although only a\n> few of those directories are actually needed, the automatic removal of\n> those packages will fail if I remove the empty directories manually.  \n> Equally, the removal will fail, if I put a .placeholder file into\n> those direrectories and cg-add it.  Is there a simple way out?\n> \n\nI'm afraid not.\n\nYou should also note that git doesn't track permissions exactly. It just \nnotices an execution bit and uses it to determine if it should write the \nworking tree using (0666 ^ umask) or (0777 ^ umask). This makes it \nfairly unsuitable for /etc tracking unless you add some sort of \npermission restoring thing to it.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"16841","messageId":"3afbacad0602271039v21a255adndb7a2cbd2992c67a@mail.gmail.com","threadId":"3476","inReplyTo":"44031941.1020806@op5.se","subject":"Re: cg-status and empty directories","fromName":"Jim MacBaine","fromEmail":"jmacbaine@gmail.com","sentAt":"2006-02-27T18:39:51Z","receivedAt":"2006-02-27T18:39:51Z","isPatch":false,"sender":{"key":"jmacbaine@gmail.com","avatar":null},"body":"On 2/27/06, Andreas Ericsson <ae@op5.se> wrote:\n\n> I'm afraid not.\n>\n> You should also note that git doesn't track permissions exactly. It just\n> notices an execution bit and uses it to determine if it should write the\n> working tree using (0666 ^ umask) or (0777 ^ umask). This makes it\n> fairly unsuitable for /etc tracking unless you add some sort of\n> permission restoring thing to it.\n\nI'm aware of those limitations. It is not a backup mechanism at all\nand permissions are handled by a small perl script.\n\nHowever, I'm just curious to know, why cg-status suddenly started to\ncare about empty directories.\n\nRegards,\nJim\n"},{"id":"17991","messageId":"20060326142505.GL18185@pasky.or.cz","threadId":"3476","inReplyTo":"3afbacad0602270643k9fdd255w8f3769ad77c54e65@mail.gmail.com","subject":"[PATCH] Do not ever list empty directories in git-ls-files --others","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-03-26T14:25:05Z","receivedAt":"2006-03-26T14:25:05Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"  Hi,\n\nDear diary, on Mon, Feb 27, 2006 at 03:43:32PM CET, I got a letter\nwhere Jim MacBaine <jmacbaine@gmail.com> said that...\n> Many packages put empty directories under /etc, and although only a\n> few of those directories are actually needed, the automatic removal of\n> those packages will fail if I remove the empty directories manually.  \n> Equally, the removal will fail, if I put a .placeholder file into\n> those direrectories and cg-add it.  Is there a simple way out?\n\n  this is caused by git-ls-files behaviour - we now call it with\nthe --directory argument which is nice since it will show a non-empty\nunknown directory as a single entry and won't list all its contents.\nWhat is not so nice is the side-effect you are describing, and I tend\nto agree that if the directory is empty, it should not be listed.\n\n---\n\nWithout the --directory flag, git-ls-files wouldn't ever list directories,\nproducing no output for empty directories, which is good since they cannot\nbe added and they bear no content, even untracked one (if Git ever starts\ntracking directories on their own, this should obviously change since the\ncontent notion will change).\n\nWith the --directory flag however, git-ls-files would list even empty\ndirectories. This patch fixes this.\n\nSigned-off-by: Petr Baudis <pasky@suse.cz>\n---\n\n ls-files.c |   19 ++++++++++++++-----\n 1 files changed, 14 insertions(+), 5 deletions(-)\n\ndiff --git a/ls-files.c b/ls-files.c\nindex e42119c..4502b51 100644\n--- a/ls-files.c\n+++ b/ls-files.c\n@@ -258,11 +258,12 @@ static int dir_exists(const char *dirnam\n  * Also, we ignore the name \".git\" (even if it is not a directory).\n  * That likely will not change.\n  */\n-static void read_directory(const char *path, const char *base, int baselen)\n+static int read_directory(const char *path, const char *base, int baselen)\n {\n-\tDIR *dir = opendir(path);\n+\tDIR *fdir = opendir(path);\n+\tint contents = 0;\n \n-\tif (dir) {\n+\tif (fdir) {\n \t\tint exclude_stk;\n \t\tstruct dirent *de;\n \t\tchar fullname[MAXPATHLEN + 1];\n@@ -270,7 +271,7 @@ static void read_directory(const char *p\n \n \t\texclude_stk = push_exclude_per_directory(base, baselen);\n \n-\t\twhile ((de = readdir(dir)) != NULL) {\n+\t\twhile ((de = readdir(fdir)) != NULL) {\n \t\t\tint len;\n \n \t\t\tif ((de->d_name[0] == '.') &&\n@@ -288,6 +289,7 @@ static void read_directory(const char *p\n \n \t\t\tswitch (DTYPE(de)) {\n \t\t\tstruct stat st;\n+\t\t\tint subdir, rewind_base;\n \t\t\tdefault:\n \t\t\t\tcontinue;\n \t\t\tcase DT_UNKNOWN:\n@@ -301,22 +303,31 @@ static void read_directory(const char *p\n \t\t\tcase DT_DIR:\n \t\t\t\tmemcpy(fullname + baselen + len, \"/\", 2);\n \t\t\t\tlen++;\n-\t\t\t\tif (show_other_directories &&\n-\t\t\t\t    !dir_exists(fullname, baselen + len))\n+\t\t\t\trewind_base = nr_dir;\n+\t\t\t\tsubdir = read_directory(fullname, fullname,\n+\t\t\t\t                        baselen + len);\n+\t\t\t\tif (show_other_directories && subdir &&\n+\t\t\t\t    !dir_exists(fullname, baselen + len)) {\n+\t\t\t\t\t// Rewind the read subdirectory\n+\t\t\t\t\twhile (nr_dir > rewind_base)\n+\t\t\t\t\t\tfree(dir[--nr_dir]);\n \t\t\t\t\tbreak;\n-\t\t\t\tread_directory(fullname, fullname,\n-\t\t\t\t\t       baselen + len);\n+\t\t\t\t}\n+\t\t\t\tcontents += subdir;\n \t\t\t\tcontinue;\n \t\t\tcase DT_REG:\n \t\t\tcase DT_LNK:\n \t\t\t\tbreak;\n \t\t\t}\n \t\t\tadd_name(fullname, baselen + len);\n+\t\t\tcontents++;\n \t\t}\n-\t\tclosedir(dir);\n+\t\tclosedir(fdir);\n \n \t\tpop_exclude_per_directory(exclude_stk);\n \t}\n+\n+\treturn contents;\n }\n \n static int cmp_name(const void *p1, const void *p2)\n\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nRight now I am having amnesia and deja-vu at the same time.  I think\nI have forgotten this before.\n"},{"id":"17992","messageId":"20060326145952.GM18185@pasky.or.cz","threadId":"3476","inReplyTo":"20060326142505.GL18185@pasky.or.cz","subject":"[PATCH] Optionally do not list empty directories in git-ls-files --others","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-03-26T14:59:52Z","receivedAt":"2006-03-26T14:59:52Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":" Hi,\n\nDear diary, on Sun, Mar 26, 2006 at 04:25:05PM CEST, I got a letter\nwhere Petr Baudis <pasky@suse.cz> said that...\n> Dear diary, on Mon, Feb 27, 2006 at 03:43:32PM CET, I got a letter\n> where Jim MacBaine <jmacbaine@gmail.com> said that...\n> > Many packages put empty directories under /etc, and although only a\n> > few of those directories are actually needed, the automatic removal of\n> > those packages will fail if I remove the empty directories manually.  \n> > Equally, the removal will fail, if I put a .placeholder file into\n> > those direrectories and cg-add it.  Is there a simple way out?\n> \n>   this is caused by git-ls-files behaviour - we now call it with\n> the --directory argument which is nice since it will show a non-empty\n> unknown directory as a single entry and won't list all its contents.\n> What is not so nice is the side-effect you are describing, and I tend\n> to agree that if the directory is empty, it should not be listed.\n\n  it turned out that cg-clean depends on the original behaviour (and it\nmakes sense there, we want to purge even empty directories). Therefore\nthis patch will preserve the old behaviour but add an option\n--no-empty-directory. When that gets propagated to Git releases, I will\nuse it in cg-status.\n\n---\n\nWithout the --directory flag, git-ls-files wouldn't ever list directories,\nproducing no output for empty directories, which is good since they cannot\nbe added and they bear no content, even untracked one (if Git ever starts\ntracking directories on their own, this should obviously change since the\ncontent notion will change).\n\nWith the --directory flag however, git-ls-files would list even empty\ndirectories. This may be good in some situations but sometimes you want to\nprevent that. This patch adds a --no-empty-directory option which makes\ngit-ls-files omit empty directories.\n\nSigned-off-by: Petr Baudis <pasky@suse.cz>\n---\n\n Documentation/git-ls-files.txt |    3 +++\n ls-files.c                     |   33 +++++++++++++++++++++++++--------\n 2 files changed, 28 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex e813f84..980c5c9 100644\n--- a/Documentation/git-ls-files.txt\n+++ b/Documentation/git-ls-files.txt\n@@ -52,6 +52,9 @@ OPTIONS\n \tIf a whole directory is classified as \"other\", show just its\n \tname (with a trailing slash) and not its whole contents.\n \n+--no-empty-directory::\n+\tDo not list empty directories. Has no effect without --directory.\n+\n -u|--unmerged::\n \tShow unmerged files in the output (forces --stage)\n \ndiff --git a/ls-files.c b/ls-files.c\nindex e42119c..83b0a3b 100644\n--- a/ls-files.c\n+++ b/ls-files.c\n@@ -20,6 +20,7 @@ static int show_unmerged = 0;\n static int show_modified = 0;\n static int show_killed = 0;\n static int show_other_directories = 0;\n+static int hide_empty_directories = 0;\n static int show_valid_bit = 0;\n static int line_terminator = '\\n';\n \n@@ -258,11 +259,12 @@ static int dir_exists(const char *dirnam\n  * Also, we ignore the name \".git\" (even if it is not a directory).\n  * That likely will not change.\n  */\n-static void read_directory(const char *path, const char *base, int baselen)\n+static int read_directory(const char *path, const char *base, int baselen)\n {\n-\tDIR *dir = opendir(path);\n+\tDIR *fdir = opendir(path);\n+\tint contents = 0;\n \n-\tif (dir) {\n+\tif (fdir) {\n \t\tint exclude_stk;\n \t\tstruct dirent *de;\n \t\tchar fullname[MAXPATHLEN + 1];\n@@ -270,7 +272,7 @@ static void read_directory(const char *p\n \n \t\texclude_stk = push_exclude_per_directory(base, baselen);\n \n-\t\twhile ((de = readdir(dir)) != NULL) {\n+\t\twhile ((de = readdir(fdir)) != NULL) {\n \t\t\tint len;\n \n \t\t\tif ((de->d_name[0] == '.') &&\n@@ -288,6 +290,7 @@ static void read_directory(const char *p\n \n \t\t\tswitch (DTYPE(de)) {\n \t\t\tstruct stat st;\n+\t\t\tint subdir, rewind_base;\n \t\t\tdefault:\n \t\t\t\tcontinue;\n \t\t\tcase DT_UNKNOWN:\n@@ -301,22 +304,32 @@ static void read_directory(const char *p\n \t\t\tcase DT_DIR:\n \t\t\t\tmemcpy(fullname + baselen + len, \"/\", 2);\n \t\t\t\tlen++;\n+\t\t\t\trewind_base = nr_dir;\n+\t\t\t\tsubdir = read_directory(fullname, fullname,\n+\t\t\t\t                        baselen + len);\n \t\t\t\tif (show_other_directories &&\n-\t\t\t\t    !dir_exists(fullname, baselen + len))\n+\t\t\t\t    (subdir || !hide_empty_directories) &&\n+\t\t\t\t    !dir_exists(fullname, baselen + len)) {\n+\t\t\t\t\t// Rewind the read subdirectory\n+\t\t\t\t\twhile (nr_dir > rewind_base)\n+\t\t\t\t\t\tfree(dir[--nr_dir]);\n \t\t\t\t\tbreak;\n-\t\t\t\tread_directory(fullname, fullname,\n-\t\t\t\t\t       baselen + len);\n+\t\t\t\t}\n+\t\t\t\tcontents += subdir;\n \t\t\t\tcontinue;\n \t\t\tcase DT_REG:\n \t\t\tcase DT_LNK:\n \t\t\t\tbreak;\n \t\t\t}\n \t\t\tadd_name(fullname, baselen + len);\n+\t\t\tcontents++;\n \t\t}\n-\t\tclosedir(dir);\n+\t\tclosedir(fdir);\n \n \t\tpop_exclude_per_directory(exclude_stk);\n \t}\n+\n+\treturn contents;\n }\n \n static int cmp_name(const void *p1, const void *p2)\n@@ -696,6 +709,10 @@ int main(int argc, const char **argv)\n \t\t\tshow_other_directories = 1;\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--no-empty-directory\")) {\n+\t\t\thide_empty_directories = 1;\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strcmp(arg, \"-u\") || !strcmp(arg, \"--unmerged\")) {\n \t\t\t/* There's no point in showing unmerged unless\n \t\t\t * you also show the stage information.\n\n\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nRight now I am having amnesia and deja-vu at the same time.  I think\nI have forgotten this before.\n"},{"id":"18010","messageId":"7vslp4q4cw.fsf@assigned-by-dhcp.cox.net","threadId":"3476","inReplyTo":"20060326145952.GM18185@pasky.or.cz","subject":"Re: [PATCH] Optionally do not list empty directories in git-ls-files --others","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-26T21:32:31Z","receivedAt":"2006-03-26T21:32:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n>   it turned out that cg-clean depends on the original behaviour...\n\nSupporting both sounds sensible.\n"},{"id":"18011","messageId":"20060326213733.GT18185@pasky.or.cz","threadId":"3476","inReplyTo":"3afbacad0602270643k9fdd255w8f3769ad77c54e65@mail.gmail.com","subject":"Re: cg-status and empty directories","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-03-26T21:37:33Z","receivedAt":"2006-03-26T21:37:33Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"  Hi,\n\nDear diary, on Mon, Feb 27, 2006 at 03:43:32PM CET, I got a letter\nwhere Jim MacBaine <jmacbaine@gmail.com> said that...\n> Many packages put empty directories under /etc, and although only a\n> few of those directories are actually needed, the automatic removal of\n> those packages will fail if I remove the empty directories manually.  \n> Equally, the removal will fail, if I put a .placeholder file into\n> those direrectories and cg-add it.  Is there a simple way out?\n\n  BTW, with Cogito-0.17.1 the simple way out should be cg-status -S\nwhich restores the original behaviour.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nRight now I am having amnesia and deja-vu at the same time.  I think\nI have forgotten this before.\n"}]}