{"thread":{"id":"367","subject":"[PATCH] add a diff-files command (revised and cleaned up)","startedAt":"2005-04-28T02:43:58Z","lastAt":"2005-04-28T21:04:47Z","messageCount":4,"participants":["Nicolas Pitre","Linus Torvalds","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"1981","messageId":"Pine.LNX.4.62.0504272239420.14033@localhost.localdomain","threadId":"367","inReplyTo":null,"subject":"[PATCH] add a diff-files command (revised and cleaned up)","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2005-04-28T02:43:58Z","receivedAt":"2005-04-28T02:43:58Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"\n[ sorry for the resent\n  still experiencing glitches with cogito\n  please ignore previous patch ]\n\nIn the same spirit as diff-tree and diff-cache, here is a diff-files \ncommand that processes differences between the index cache and the \nworking directory content.  It produces lists of files that are either \nchanged, deleted and/or unknown with regards to the current cache, \ncontent. The -p option can also be used to generate a patch describing \nthe differences in patch form.\n\nIt also has the ability to accept exclude patterns for files and the \nability to read those exclude patterns from a file.\n\nTypical usage looks like:\n\n    diff-files --others --exclude=\\*.o arch/arm/ include/asm-arm/\n\nwhich lists all files the git cache doesn't know about in arch/arm/ and \ninclude/asm-arm/ but ignoring any object files.  Or:\n\n    diff-files --all -p --exclude-from=dontdiff.list\n\nwhich produces a patch of all changes currently in the work tree while \nexcluding all files matching any of the patterns listed in \ndontdiff.list (useful when one doesn't want to run 'make distclean').\n\n(revised after comments from Junio C Hamano)\nSigned-off-by: Nicolas Pitre <nico@cam.org>\n\n--- k/Makefile\n+++ l/Makefile\n@@ -18,7 +18,7 @@ PROG=   update-cache show-diff init-db w\n \tcat-file fsck-cache checkout-cache diff-tree rev-tree show-files \\\n \tcheck-files ls-tree merge-base merge-cache unpack-file git-export \\\n \tdiff-cache convert-cache http-pull rpush rpull rev-list git-mktag \\\n-\tdiff-tree-helper\n+\tdiff-tree-helper diff-files\n \n all: $(PROG)\n \n--- k/diff-files.c\n+++ l/diff-files.c\n@@ -0,0 +1,347 @@\n+/*\n+ * GIT - The information manager from hell\n+ *\n+ * Copyright (C) Linus Torvalds, 2005\n+ */\n+\n+#include <dirent.h>\n+#include <fnmatch.h>\n+#include \"cache.h\"\n+#include \"diff.h\"\n+\n+static const char *diff_files_usage =\n+\t\"diff-files [--all] [--changed] [--deleted] [--others] [-p | -z] \"\n+\t\"[--exclude=<pattern>] [--exclude-from=<file>] [paths...]\";\n+\n+/* What paths are we interested in? */\n+static int nr_paths = 0;\n+static char **paths = NULL;\n+static int *pathlens = NULL;\n+\n+static int nr_excludes;\n+static const char **excludes;\n+static int excludes_alloc;\n+\n+static void add_exclude(const char *string)\n+{\n+\tif (nr_excludes == excludes_alloc) {\n+\t\texcludes_alloc = alloc_nr(excludes_alloc);\n+\t\texcludes = realloc(excludes, excludes_alloc*sizeof(char *));\n+\t}\n+\texcludes[nr_excludes++] = string;\n+}\n+\n+static void add_excludes_from_file(const char *fname)\n+{\n+\tint fd, i;\n+\tlong size;\n+\tchar *buf, *entry;\n+\n+\tfd = open(fname, O_RDONLY);\n+\tif (fd < 0)\n+\t\tgoto err;\n+\tsize = lseek(fd, 0, SEEK_END);\n+\tif (size < 0)\n+\t\tgoto err;\n+\tlseek(fd, 0, SEEK_SET);\n+\tif (size == 0) {\n+\t\tclose(fd);\n+\t\treturn;\n+\t}\n+\tbuf = malloc(size);\n+\tif (!buf) {\n+\t\terrno = ENOMEM;\n+\t\tgoto err;\n+\t}\n+\tif (read(fd, buf, size) != size)\n+\t\tgoto err;\n+\tclose(fd);\n+\n+\tentry = buf;\n+\tfor (i = 0; i < size; i++) {\n+\t\tif (buf[i] == '\\n') {\n+\t\t\tif (entry != buf + i) {\n+\t\t\t\tbuf[i] = 0;\n+\t\t\t\tadd_exclude(entry);\n+\t\t\t}\n+\t\t\tentry = buf + i + 1;\n+\t\t}\n+\t}\n+\treturn;\n+\n+err:\tperror(fname);\n+\texit(1);\n+}\n+\n+/*\n+ * See if name matches our specified paths and is not excluded.\n+ * return value:\n+ *\t-1 if no match\n+ *\t0 if partial match (name is a directory component)\n+ *\t1 = exact match\n+ *\t2 = name is under a specified directory path with no excludes\n+ */\n+static int path_match(const char *name, int namelen)\n+{\n+\tint i, ret;\n+\n+\t/* fast case: no path list and no exclude list */\n+\tif (!nr_paths && !nr_excludes)\n+\t\treturn 2;\n+\n+\tret = (nr_paths) ? -1 : 1;\n+\tfor (i = 0; i < nr_paths; i++) {\n+\t\tint pathlen = pathlens[i];\n+\t\tif (pathlen == namelen &&\n+\t\t    strncmp(paths[i], name, pathlen) == 0) {\n+\t\t\tret = 1;\n+\t\t\tbreak;\n+\t\t} else if (pathlen > namelen && \n+\t\t\t   strncmp(paths[i], name, namelen) == 0 &&\n+\t\t\t   paths[i][namelen] == '/') {\n+\t\t\tret = 0;\n+\t\t\tbreak;\n+\t\t} else if (pathlen < namelen &&\n+\t\t\t   strncmp(paths[i], name, pathlen) == 0 &&\n+\t\t\t   name[pathlen] == '/') {\n+\t\t\tret = (nr_excludes) ? 1 : 2;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (ret >= 0 && nr_excludes) {\n+\t\tconst char *basename = strrchr(name, '/');\n+\t\tbasename = (basename) ? basename+1 : name;\n+\t\tfor (i = 0; i < nr_excludes; i++) {\n+\t\t\tif (fnmatch(excludes[i], basename, 0) == 0) {\n+\t\t\t\tret = -1;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static const char **others;\n+static int nr_others;\n+static int others_alloc;\n+\n+static void add_name(const char *pathname, int len)\n+{\n+\tchar *name;\n+\n+\tif (cache_name_pos(pathname, len) >= 0)\n+\t\treturn;\n+\n+\tif (nr_others == others_alloc) {\n+\t\tothers_alloc = alloc_nr(others_alloc);\n+\t\tothers = realloc(others, others_alloc*sizeof(char *));\n+\t}\n+\tname = malloc(len + 1);\n+\tmemcpy(name, pathname, len + 1);\n+\tothers[nr_others++] = name;\n+}\n+\n+/*\n+ * Read a directory tree. We currently ignore anything but\n+ * directories and regular files. That's because git doesn't\n+ * handle them at all yet. Maybe that will change some day.\n+ *\n+ * Also, we currently ignore all names starting with a dot.\n+ * That likely will not change.\n+ */\n+static void read_directory(const char *path, const char *base, int baselen, int match)\n+{\n+\tDIR *dir = opendir(path);\n+\n+\tif (dir) {\n+\t\tstruct dirent *de;\n+\t\tchar fullname[MAXPATHLEN + 1];\n+\t\tmemcpy(fullname, base, baselen);\n+\n+\t\twhile ((de = readdir(dir)) != NULL) {\n+\t\t\tint len;\n+\n+\t\t\tif (de->d_name[0] == '.')\n+\t\t\t\tcontinue;\n+\t\t\tlen = strlen(de->d_name);\n+\t\t\tmemcpy(fullname + baselen, de->d_name, len+1);\n+\t\t\tif (match < 2)\n+\t\t\t\tmatch = path_match(fullname, baselen+len);\n+\t\t\tif (match < 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\tswitch (de->d_type) {\n+\t\t\tstruct stat st;\n+\t\t\tdefault:\n+\t\t\t\tcontinue;\n+\t\t\tcase DT_UNKNOWN:\n+\t\t\t\tif (lstat(fullname, &st))\n+\t\t\t\t\tcontinue;\n+\t\t\t\tif (S_ISREG(st.st_mode))\n+\t\t\t\t\tbreak;\n+\t\t\t\tif (!S_ISDIR(st.st_mode))\n+\t\t\t\t\tcontinue;\n+\t\t\t\t/* fallthrough */\n+\t\t\tcase DT_DIR:\n+\t\t\t\tmemcpy(fullname + baselen + len, \"/\", 2);\n+\t\t\t\tread_directory(fullname, fullname,\n+\t\t\t\t\t       baselen + len + 1, match);\n+\t\t\t\tcontinue;\n+\t\t\tcase DT_REG:\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (match > 0)\n+\t\t\t\tadd_name(fullname, baselen + len);\n+\t\t}\n+\t\tclosedir(dir);\n+\t}\n+}\n+\n+static int cmp_name(const void *p1, const void *p2)\n+{\n+\tconst char *n1 = *(const char **)p1;\n+\tconst char *n2 = *(const char **)p2;\n+\tint l1 = strlen(n1), l2 = strlen(n2);\n+\n+\treturn cache_name_compare(n1, l1, n2, l2);\n+}\n+\n+static int show_changed = 0;\n+static int show_deleted = 0;\n+static int show_others = 0;\n+static int generate_patch = 0;\n+static int line_terminator = '\\n';\n+\n+static const char null_sha1[20];\n+static const char null_sha1_hex[] = \"0000000000000000000000000000000000000000\";\n+\n+static void show_file(int prefix, unsigned int mode,\n+\t\t      const char *sha1, const char *name)\n+{\n+\tif (generate_patch)\n+\t\tdiff_addremove(prefix, mode, sha1, name, NULL);\n+\telse\n+\t\tprintf(\"%c%o\\t%s\\t%s\\t%s%c\", prefix, mode, \"blob\",\n+\t\t       sha1_to_hex(sha1), name, line_terminator);\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tint i, entries;\n+\n+\tfor (i = 1; i < argc; i++) {\n+\t\tchar *arg = argv[i];\n+\n+\t\tif (*arg != '-') {\n+\t\t\tbreak;\n+\t\t} else if (!strcmp(arg, \"-z\")) {\n+\t\t\tline_terminator = 0;\n+\t\t} else if (!strcmp(arg, \"-a\") || !strcmp(arg, \"--all\")) {\n+\t\t\tshow_changed = show_deleted = show_others = 1;\n+\t\t} else if (!strcmp(arg, \"-c\") || !strcmp(arg, \"--changed\")) {\n+\t\t\tshow_changed = 1;\n+\t\t} else if (!strcmp(arg, \"-d\") || !strcmp(arg, \"--deleted\")) {\n+\t\t\tshow_deleted = 1;\n+\t\t} else if (!strcmp(arg, \"-o\") || !strcmp(arg, \"--others\")) {\n+\t\t\tshow_others = 1;\n+\t\t} else if (!strcmp(arg, \"-p\")) {\n+\t\t\tgenerate_patch = 1;\n+\t\t} else if (!strcmp(arg, \"-x\") && i+1 < argc) {\n+\t\t\tadd_exclude(argv[++i]);\n+\t\t} else if (!strncmp(arg, \"--exclude=\", 10)) {\n+\t\t\tadd_exclude(arg+10);\n+\t\t} else if (!strcmp(arg, \"-X\") && i+1 < argc) {\n+\t\t\tadd_excludes_from_file(argv[++i]);\n+\t\t} else if (!strncmp(arg, \"--exclude-from=\", 15)) {\n+\t\t\tadd_excludes_from_file(arg+15);\n+\t\t} else if (!strcmp(arg, \"--\")) {\n+\t\t\ti++;\n+\t\t\tbreak;\n+\t\t} else\n+\t\t\tusage(diff_files_usage);\n+\t}\n+\n+\t/* default to -c if none of -c, -d nor -o have been specified */\n+\tif (!show_changed && !show_deleted && !show_others)\n+\t\tshow_changed = 1;\n+\n+\tif (i < argc) {\n+\t\tpaths = &argv[i];\n+\t\tnr_paths = argc - i;\n+\t\tpathlens = malloc(nr_paths * sizeof(int));\n+\t\tfor (i=0; i<nr_paths; i++) {\n+\t\t\tpathlens[i] = strlen(paths[i]);\n+\t\t\tif (paths[i][pathlens[i] - 1] == '/')\n+\t\t\t\tpathlens[i]--;\n+\t\t}\n+\t}\n+\n+\tentries = read_cache();\n+\tif (entries < 0) {\n+\t\tperror(\"read_cache\");\n+\t\texit(1);\n+\t}\n+\n+\tif (show_others) {\n+\t\tread_directory(\".\", \"\", 0, 0);\n+\t\tqsort(others, nr_others, sizeof(char *), cmp_name);\n+\t\tfor (i = 0; i < nr_others; i++) {\n+\t\t\tstruct stat st;\n+\t\t\tunsigned int mode;\n+\t\t\tif (stat(others[i], &st) < 0) {\n+\t\t\t\tperror(others[i]);\n+\t\t\t} else {\n+\t\t\t\tmode = S_IFREG | ce_permissions(st.st_mode);\n+\t\t\t\tshow_file('+', mode, null_sha1, others[i]);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < entries; i++) {\n+\t\tstruct stat st;\n+\t\tunsigned int ce_mode, mode;\n+\t\tstruct cache_entry *ce = active_cache[i];\n+\n+\t\tif (path_match(ce->name, ce_namelen(ce)) < 1)\n+\t\t\tcontinue;\n+\n+\t\tif (show_changed && ce_stage(ce)) {\n+\t\t\tif (generate_patch)\n+\t\t\t\tdiff_unmerge(ce->name);\n+\t\t\telse\n+\t\t\t\tprintf(\"U %s%c\", ce->name, line_terminator);\n+\t\t\tdo {\n+\t\t\t\ti++;\n+\t\t\t} while (i < entries &&\n+\t\t\t\t !strcmp(ce->name, active_cache[i]->name));\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tce_mode = ntohl(ce->ce_mode);\n+\t\tif (stat(ce->name, &st) < 0) {\n+\t\t\tif (errno != ENOENT) {\n+\t\t\t\tperror(ce->name);\n+\t\t\t} else if (show_deleted) {\n+\t\t\t\tshow_file('-', ce_mode, ce->sha1, ce->name);\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!show_changed || !cache_match_stat(ce, &st))\n+\t\t\tcontinue;\n+\n+\t\tmode = S_IFREG | ce_permissions(st.st_mode);\n+\t\tif (generate_patch)\n+\t\t\tdiff_change(ce_mode, mode, ce->sha1,\n+\t\t\t\t    null_sha1, ce->name, NULL);\n+\t\telse\n+\t\t\tprintf(\"*%o->%o\\t%s\\t%s->%s\\t%s%c\",\n+\t\t\t       ce_mode, mode, \"blob\",\n+\t\t\t       sha1_to_hex(ce->sha1), null_sha1_hex,\n+\t\t\t       ce->name, line_terminator);\n+\t}\n+\n+\treturn 0;\n+}\n"},{"id":"2052","messageId":"Pine.LNX.4.58.0504280950340.18901@ppc970.osdl.org","threadId":"367","inReplyTo":"Pine.LNX.4.62.0504272239420.14033@localhost.localdomain","subject":"Re: [PATCH] add a diff-files command (revised and cleaned up)","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-28T17:08:07Z","receivedAt":"2005-04-28T17:08:07Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 27 Apr 2005, Nicolas Pitre wrote:\n>\n> In the same spirit as diff-tree and diff-cache, here is a diff-files \n> command that processes differences between the index cache and the \n> working directory content.\n\nI really think the current \"show-diff\" does that very well, and what \nyou're doing is really different.\n\nI think this thing is really a replacement for \"show-files\", which is a \npiece of crap (hey, I wrote it, but I don't have to be proud of it), and \nwhich really was meant to be more of what your diff-files is.\n\nThe thing is, I really don't want the \"core\" diff-xxx programs to worry \nabout exclude patters, and current directory contents. They do one thing, \nand one thing only: compare the files they were explicitly told to \ncompare. \n\nHOWEVER, there clearly is a separate problem, which is what \"show-files\"  \ncurrently does very badly (and not at all in some cases), which is the \n\"ok, what about the _other_ files?\"\n\nAnd once you start talking about files that are _not_ mentioned in the\nindex, now you really do have something totally different, and now it does\nneed to be able to have exclude patterns to know to avoid object files and\nother crud that we know we're not interested in).\n\nBut for the crud we don't know about, we're not really interested in the\ndiff against something we _do_ know about. So I think that the whole\n\"--others\" and \"--all\" thing is wrong (yeah, yeah, it was me that started\nit with show-files), and that this thing should always _only_ look at\nfiles that aren't mentioned in the index file (ie \"others\" is always\nenabled, and \"all\" is pointless).\n\nBecause those are special files: they are files we don't know what to do\nwith (conversely, files that _are_ mentioned in the index but don't \nactually seem to show up are interesting for the exact same reason).\n\nThat set of files is interesting for several reasons:\n\n - maybe we're about to check something in. We want to know whether maybe \n   we've forgotten to \"add\" a file or \"remove\" a file.\n\n - is it a file we've lost track of, and if so, does it look anything like \n   some _other_ file in the index. This happens if you do a \"mv\", and \n   don't tell the SCM about it: git doesn't care (it looks like a remove \n   and add), but it would be good to have a tool that warns about it and \n   then it would be nice if it could actually say \"files xxx and yyy seem \n   to have gone away, but I see new files aaa and bbb, and it looks like \n   bbb might be similar to yyy, and aaa looks a lot like the old xxx\"\n\nThis was all stuff that \"show-files\" was kind of supposed to work up to, \nbut I just couldn't find it in myself to be interested enough.\n\n\t\tLinus\n"},{"id":"2059","messageId":"Pine.LNX.4.62.0504281327520.14033@localhost.localdomain","threadId":"367","inReplyTo":"Pine.LNX.4.58.0504280950340.18901@ppc970.osdl.org","subject":"Re: [PATCH] add a diff-files command (revised and cleaned up)","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2005-04-28T17:35:23Z","receivedAt":"2005-04-28T17:35:23Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"On Thu, 28 Apr 2005, Linus Torvalds wrote:\n\n> HOWEVER, there clearly is a separate problem, which is what \"show-files\"  \n> currently does very badly (and not at all in some cases), which is the \n> \"ok, what about the _other_ files?\"\n\nRight.  And that's the problem I'm trying to solve.\n\nWhat about this patch then?\n\n=====\n\nGive show-files the ability to process exclusion pattern.\n\nThis can be used with the famous dontdiff file as follows to find out \nabout uncommitted files just like dontdiff is used with the diff \ncommand:\n\n    show-files --others --exclude-from=dontdiff\n\nand the exclude list can be reversed with the --ignore switch.\n\nSigned-off-by: Nicolas Pitre <nico@cam.org>\n\n--- a/show-files.c\n+++ b/show-files.c\n@@ -6,6 +6,7 @@\n  * Copyright (C) Linus Torvalds, 2005\n  */\n #include <dirent.h>\n+#include <fnmatch.h>\n \n #include \"cache.h\"\n \n@@ -17,6 +18,70 @@ static int show_stage = 0;\n static int show_unmerged = 0;\n static int line_terminator = '\\n';\n \n+static int nr_excludes;\n+static const char **excludes;\n+static int excludes_alloc;\n+\n+static void add_exclude(const char *string)\n+{\n+\tif (nr_excludes == excludes_alloc) {\n+\t\texcludes_alloc = alloc_nr(excludes_alloc);\n+\t\texcludes = realloc(excludes, excludes_alloc*sizeof(char *));\n+\t}\n+\texcludes[nr_excludes++] = string;\n+}\n+\n+static void add_excludes_from_file(const char *fname)\n+{\n+\tint fd, i;\n+\tlong size;\n+\tchar *buf, *entry;\n+\n+\tfd = open(fname, O_RDONLY);\n+\tif (fd < 0)\n+\t\tgoto err;\n+\tsize = lseek(fd, 0, SEEK_END);\n+\tif (size < 0)\n+\t\tgoto err;\n+\tlseek(fd, 0, SEEK_SET);\n+\tif (size == 0) {\n+\t\tclose(fd);\n+\t\treturn;\n+\t}\n+\tbuf = xmalloc(size);\n+\tif (read(fd, buf, size) != size)\n+\t\tgoto err;\n+\tclose(fd);\n+\n+\tentry = buf;\n+\tfor (i = 0; i < size; i++) {\n+\t\tif (buf[i] == '\\n') {\n+\t\t\tif (entry != buf + i) {\n+\t\t\t\tbuf[i] = 0;\n+\t\t\t\tadd_exclude(entry);\n+\t\t\t}\n+\t\t\tentry = buf + i + 1;\n+\t\t}\n+\t}\n+\treturn;\n+\n+err:\tperror(fname);\n+\texit(1);\n+}\n+\n+static int excluded(const char *pathname)\n+{\n+\tint i;\n+\tif (nr_excludes) {\n+\t\tconst char *basename = strrchr(pathname, '/');\n+\t\tbasename = (basename) ? basename+1 : pathname;\n+\t\tfor (i = 0; i < nr_excludes; i++)\n+\t\t\tif (fnmatch(excludes[i], basename, 0) == 0)\n+\t\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n static const char **dir;\n static int nr_dir;\n static int dir_alloc;\n@@ -59,6 +124,8 @@ static void read_directory(const char *p\n \n \t\t\tif (de->d_name[0] == '.')\n \t\t\t\tcontinue;\n+\t\t\tif (excluded(de->d_name) != show_ignored)\n+\t\t\t\tcontinue;\n \t\t\tlen = strlen(de->d_name);\n \t\t\tmemcpy(fullname + baselen, de->d_name, len+1);\n \n@@ -101,17 +168,17 @@ static void show_files(void)\n \tint i;\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n-\tif (show_others | show_ignored) {\n+\tif (show_others) {\n \t\tread_directory(\".\", \"\", 0);\n \t\tqsort(dir, nr_dir, sizeof(char *), cmp_name);\n-\t}\n-\tif (show_others) {\n \t\tfor (i = 0; i < nr_dir; i++)\n \t\t\tprintf(\"%s%c\", dir[i], line_terminator);\n \t}\n \tif (show_cached | show_stage) {\n \t\tfor (i = 0; i < active_nr; i++) {\n \t\t\tstruct cache_entry *ce = active_cache[i];\n+\t\t\tif (excluded(ce->name) != show_ignored)\n+\t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n \t\t\tif (!show_stage)\n@@ -130,14 +197,13 @@ static void show_files(void)\n \t\tfor (i = 0; i < active_nr; i++) {\n \t\t\tstruct cache_entry *ce = active_cache[i];\n \t\t\tstruct stat st;\n+\t\t\tif (excluded(ce->name) != show_ignored)\n+\t\t\t\tcontinue;\n \t\t\tif (!stat(ce->name, &st))\n \t\t\t\tcontinue;\n \t\t\tprintf(\"%s%c\", ce->name, line_terminator);\n \t\t}\n \t}\n-\tif (show_ignored) {\n-\t\t/* We don't have any \"ignore\" list yet */\n-\t}\n }\n \n int main(int argc, char **argv)\n@@ -179,11 +245,34 @@ int main(int argc, char **argv)\n \t\t\tcontinue;\n \t\t}\n \n-\t\tusage(\"show-files [-z] (--[cached|deleted|others|ignored|stage])*\");\n+\t\tif (!strcmp(arg, \"-x\") && i+1 < argc) {\n+\t\t\tadd_exclude(argv[++i]);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strncmp(arg, \"--exclude=\", 10)) {\n+\t\t\tadd_exclude(arg+10);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-X\") && i+1 < argc) {\n+\t\t\tadd_excludes_from_file(argv[++i]);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strncmp(arg, \"--exclude-from=\", 15)) {\n+\t\t\tadd_excludes_from_file(arg+15);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tusage(\"show-files [-z] (--[cached|deleted|others|stage])* \"\n+\t\t      \"[ --ignored [--exclude=<pattern>] [--exclude-from=<file>) ]\");\n+\t}\n+\n+\tif (show_ignored && !nr_excludes) {\n+\t\tfprintf(stderr, \"%s: --ignored needs some exclude pattern\\n\", argv[0]);\n+\t\texit(1);\n \t}\n \n \t/* With no flags, we default to showing the cached files */\n-\tif (!(show_stage | show_deleted | show_others | show_ignored | show_unmerged))\n+\tif (!(show_stage | show_deleted | show_others | show_unmerged))\n \t\tshow_cached = 1;\n \n \tread_cache();\n"},{"id":"2079","messageId":"7vis267guo.fsf@assigned-by-dhcp.cox.net","threadId":"367","inReplyTo":"Pine.LNX.4.62.0504281327520.14033@localhost.localdomain","subject":"Re: [PATCH] add a diff-files command (revised and cleaned up)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-28T21:04:47Z","receivedAt":"2005-04-28T21:04:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"NP\" == Nicolas Pitre <nico@cam.org> writes:\n\nNP> What about this patch then?\nNP> =====\nNP> Give show-files the ability to process exclusion pattern.\n\nI just tried this, and I like it.  Thanks!\n\n"}]}