{"thread":{"id":"38075","subject":"[PATCH 00/19] Add git-list-files","startedAt":"2014-11-30T08:55:48Z","lastAt":"2014-12-02T20:18:38Z","messageCount":28,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano","Eric Sunshine","Jeff King","Duy Nguyen","Michael J Gruber"],"isPatch":true,"patchVersion":1,"patchTotal":19},"messages":[{"id":"252719","messageId":"1417337767-4505-1-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":null,"subject":"[PATCH 00/19] Add git-list-files","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:48Z","receivedAt":"2014-11-30T08:55:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is something else that's been sitting in my tree for a while now.\nIt adds \"git list-files\", intended to be aliased as \"ls\" with your\nfavourite display options.\n\nAs you can guess it's a friendlier version (and pretty close to GNU\nls) of ls-files. On one hand, I think this is a nice addition. On the\nother hand, code bloat. Last version on the list is\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/244530/focus=245464\n\nNguyễn Thái Ngọc Duy (19):\n  ls_colors.c: add $LS_COLORS parsing code\n  ls_colors.c: parse color.ls.* from config file\n  ls_colors.c: add a function to color a file name\n  ls_colors.c: highlight submodules like directories\n  ls-files: buffer full item in strbuf before printing\n  ls-files: add --color to highlight file names\n  ls-files: add --column\n  ls-files: support --max-depth\n  Add git-list-files, a user friendly version of ls-files and more\n  list-files: -u does not imply showing stages\n  list-files: add -R/--recursive short for --max-depth=-1\n  list-files: add -1 short for --no-column\n  list-files: add -t back\n  list-files: sort output and remove duplicates\n  list-files: do not show duplicate cached entries\n  list-files: show directories as well as files\n  list-files: add -F/--classify\n  list-files -F: show submodules with the new indicator '&'\n  list-files: -M aka diff-cached\n\n .gitignore                             |   1 +\n Documentation/config.txt               |  22 ++\n Documentation/git-list-files.txt (new) |  99 +++++++\n Documentation/git-ls-files.txt         |  20 ++\n Makefile                               |   2 +\n builtin/ls-files.c                     | 415 ++++++++++++++++++++++++---\n color.h                                |  10 +\n command-list.txt                       |   1 +\n git.c                                  |   1 +\n ls_colors.c (new)                      | 496 +++++++++++++++++++++++++++++++++\n 10 files changed, 1034 insertions(+), 33 deletions(-)\n create mode 100644 Documentation/git-list-files.txt\n create mode 100644 ls_colors.c\n\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252720","messageId":"1417337767-4505-2-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 01/19] ls_colors.c: add $LS_COLORS parsing code","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:49Z","receivedAt":"2014-11-30T08:55:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Reusing color settings from $LS_COLORS could give a native look and\nfeel on file coloring.\n\nThis code is basically from coreutils.git [1], rewritten to fit Git.\n\nAs this is from GNU ls, the environment variable CLICOLOR is not\ntested. It is to be decided later whether we should ignore $LS_COLORS\nif $CLICOLOR is not set on Mac or FreeBSD.\n\n[1] commit 7326d1f1a67edf21947ae98194f98c38b6e9e527 file\n    src/ls.c. This is the last GPL-2 commit before coreutils turns to\n    GPL-3.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Makefile          |   1 +\n color.h           |   8 ++\n ls_colors.c (new) | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 407 insertions(+)\n create mode 100644 ls_colors.c\n\ndiff --git a/Makefile b/Makefile\nindex 827006b..459121d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -703,6 +703,7 @@ LIB_OBJS += list-objects.o\n LIB_OBJS += ll-merge.o\n LIB_OBJS += lockfile.o\n LIB_OBJS += log-tree.o\n+LIB_OBJS += ls_colors.o\n LIB_OBJS += mailmap.o\n LIB_OBJS += match-trees.o\n LIB_OBJS += merge.o\ndiff --git a/color.h b/color.h\nindex f5beab1..3eaa5bd 100644\n--- a/color.h\n+++ b/color.h\n@@ -45,6 +45,12 @@ struct strbuf;\n #define GIT_COLOR_BG_MAGENTA\t\"\\033[45m\"\n #define GIT_COLOR_BG_CYAN\t\"\\033[46m\"\n \n+#define GIT_COLOR_WHITE_ON_RED    \"\\033[37;41m\"\n+#define GIT_COLOR_WHITE_ON_BLUE   \"\\033[37;44m\"\n+#define GIT_COLOR_BLACK_ON_YELLOW \"\\033[30;43m\"\n+#define GIT_COLOR_BLUE_ON_GREEN   \"\\033[34;42m\"\n+#define GIT_COLOR_BLACK_ON_GREEN  \"\\033[30;42m\"\n+\n /* A special value meaning \"no color selected\" */\n #define GIT_COLOR_NIL \"NIL\"\n \n@@ -87,4 +93,6 @@ void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);\n \n int color_is_nil(const char *color);\n \n+void parse_ls_color(void);\n+\n #endif /* COLOR_H */\ndiff --git a/ls_colors.c b/ls_colors.c\nnew file mode 100644\nindex 0000000..eb944f4\n--- /dev/null\n+++ b/ls_colors.c\n@@ -0,0 +1,398 @@\n+#include \"cache.h\"\n+#include \"color.h\"\n+\n+enum color_ls {\n+\tLS_LC,\t\t\t/* left, unused */\n+\tLS_RC,\t\t\t/* right, unused */\n+\tLS_EC,\t\t\t/* end color, unused */\n+\tLS_RS,\t\t\t/* reset */\n+\tLS_NO,\t\t\t/* normal */\n+\tLS_FL,\t\t\t/* file, default */\n+\tLS_DI,\t\t\t/* directory */\n+\tLS_LN,\t\t\t/* symlink */\n+\n+\tLS_PI,\t\t\t/* pipe */\n+\tLS_SO,\t\t\t/* socket */\n+\tLS_BD,\t\t\t/* block device */\n+\tLS_CD,\t\t\t/* char device */\n+\tLS_MI,\t\t\t/* missing file */\n+\tLS_OR,\t\t\t/* orphaned symlink */\n+\tLS_EX,\t\t\t/* executable */\n+\tLS_DO,\t\t\t/* Solaris door */\n+\n+\tLS_SU,\t\t\t/* setuid */\n+\tLS_SG,\t\t\t/* setgid */\n+\tLS_ST,\t\t\t/* sticky */\n+\tLS_OW,\t\t\t/* other-writable */\n+\tLS_TW,\t\t\t/* ow with sticky */\n+\tLS_CA,\t\t\t/* cap */\n+\tLS_MH,\t\t\t/* multi hardlink */\n+\tLS_CL,\t\t\t/* clear end of line */\n+\n+\tMAX_LS\n+};\n+\n+static char ls_colors[MAX_LS][COLOR_MAXLEN] = {\n+\t\"\",\n+\t\"\",\n+\t\"\",\n+\tGIT_COLOR_RESET,\n+\tGIT_COLOR_NORMAL,\n+\tGIT_COLOR_NORMAL,\n+\tGIT_COLOR_BOLD_BLUE,\n+\tGIT_COLOR_BOLD_CYAN,\n+\n+\tGIT_COLOR_YELLOW,\n+\tGIT_COLOR_BOLD_MAGENTA,\n+\tGIT_COLOR_BOLD_YELLOW,\n+\tGIT_COLOR_BOLD_YELLOW,\n+\tGIT_COLOR_NORMAL,\n+\tGIT_COLOR_NORMAL,\n+\tGIT_COLOR_BOLD_GREEN,\n+\tGIT_COLOR_BOLD_MAGENTA,\n+\n+\tGIT_COLOR_WHITE_ON_RED,\n+\tGIT_COLOR_BLACK_ON_YELLOW,\n+\tGIT_COLOR_WHITE_ON_BLUE,\n+\tGIT_COLOR_BLUE_ON_GREEN,\n+\tGIT_COLOR_BLACK_ON_GREEN,\n+\t\"\",\n+\t\"\",\n+\t\"\"\n+};\n+\n+static const char *const indicator_name[] = {\n+\t\"lc\", \"rc\", \"ec\", \"rs\", \"no\", \"fi\", \"di\", \"ln\",\n+\t\"pi\", \"so\", \"bd\", \"cd\", \"mi\", \"or\", \"ex\", \"do\",\n+\t\"su\", \"sg\", \"st\", \"ow\", \"tw\", \"ca\", \"mh\", \"cl\",\n+\tNULL\n+};\n+\n+struct bin_str {\n+\tsize_t len;\t\t\t/* Number of bytes */\n+\tconst char *string;\t\t/* Pointer to the same */\n+};\n+\n+struct color_ext_type {\n+\tstruct bin_str ext;\t\t/* The extension we're looking for */\n+\tstruct bin_str seq;\t\t/* The sequence to output when we do */\n+\tstruct color_ext_type *next;\t/* Next in list */\n+};\n+\n+static struct color_ext_type *color_ext_list = NULL;\n+\n+/*\n+ * When true, in a color listing, color each symlink name according to the\n+ * type of file it points to.  Otherwise, color them according to the `ln'\n+ * directive in LS_COLORS.  Dangling (orphan) symlinks are treated specially,\n+ * regardless.  This is set when `ln=target' appears in LS_COLORS.\n+ */\n+static int color_symlink_as_referent;\n+\n+/*\n+ * Parse a string as part of the LS_COLORS variable; this may involve\n+ * decoding all kinds of escape characters.  If equals_end is set an\n+ * unescaped equal sign ends the string, otherwise only a : or \\0\n+ * does.  Set *OUTPUT_COUNT to the number of bytes output.  Return\n+ * true if successful.\n+ *\n+ * The resulting string is *not* null-terminated, but may contain\n+ * embedded nulls.\n+ *\n+ * Note that both dest and src are char **; on return they point to\n+ * the first free byte after the array and the character that ended\n+ * the input string, respectively.\n+ */\n+static int get_funky_string(char **dest, const char **src, int equals_end,\n+\t\t\t    size_t *output_count)\n+{\n+\tchar num;\t\t\t/* For numerical codes */\n+\tsize_t count;\t\t\t/* Something to count with */\n+\tenum {\n+\t\tST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX,\n+\t\tST_CARET, ST_END, ST_ERROR\n+\t} state;\n+\tconst char *p;\n+\tchar *q;\n+\n+\tp = *src;\t\t\t/* We don't want to double-indirect */\n+\tq = *dest;\t\t\t/* the whole darn time.  */\n+\n+\tcount = 0;\t\t\t/* No characters counted in yet.  */\n+\tnum = 0;\n+\n+\tstate = ST_GND;\t\t/* Start in ground state.  */\n+\twhile (state < ST_END) {\n+\t\tswitch (state) {\n+\t\tcase ST_GND:\t\t/* Ground state (no escapes) */\n+\t\t\tswitch (*p) {\n+\t\t\tcase ':':\n+\t\t\tcase '\\0':\n+\t\t\t\tstate = ST_END;\t/* End of string */\n+\t\t\t\tbreak;\n+\t\t\tcase '\\\\':\n+\t\t\t\tstate = ST_BACKSLASH; /* Backslash scape sequence */\n+\t\t\t\t++p;\n+\t\t\t\tbreak;\n+\t\t\tcase '^':\n+\t\t\t\tstate = ST_CARET; /* Caret escape */\n+\t\t\t\t++p;\n+\t\t\t\tbreak;\n+\t\t\tcase '=':\n+\t\t\t\tif (equals_end) {\n+\t\t\t\t\tstate = ST_END; /* End */\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\t/* else fall through */\n+\t\t\tdefault:\n+\t\t\t\t*(q++) = *(p++);\n+\t\t\t\t++count;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase ST_BACKSLASH:\t/* Backslash escaped character */\n+\t\t\tswitch (*p) {\n+\t\t\tcase '0':\n+\t\t\tcase '1':\n+\t\t\tcase '2':\n+\t\t\tcase '3':\n+\t\t\tcase '4':\n+\t\t\tcase '5':\n+\t\t\tcase '6':\n+\t\t\tcase '7':\n+\t\t\t\tstate = ST_OCTAL;\t/* Octal sequence */\n+\t\t\t\tnum = *p - '0';\n+\t\t\t\tbreak;\n+\t\t\tcase 'x':\n+\t\t\tcase 'X':\n+\t\t\t\tstate = ST_HEX;\t/* Hex sequence */\n+\t\t\t\tnum = 0;\n+\t\t\t\tbreak;\n+\t\t\tcase 'a':\t\t/* Bell */\n+\t\t\t\tnum = '\\a';\n+\t\t\t\tbreak;\n+\t\t\tcase 'b':\t\t/* Backspace */\n+\t\t\t\tnum = '\\b';\n+\t\t\t\tbreak;\n+\t\t\tcase 'e':\t\t/* Escape */\n+\t\t\t\tnum = 27;\n+\t\t\t\tbreak;\n+\t\t\tcase 'f':\t\t/* Form feed */\n+\t\t\t\tnum = '\\f';\n+\t\t\t\tbreak;\n+\t\t\tcase 'n':\t\t/* Newline */\n+\t\t\t\tnum = '\\n';\n+\t\t\t\tbreak;\n+\t\t\tcase 'r':\t\t/* Carriage return */\n+\t\t\t\tnum = '\\r';\n+\t\t\t\tbreak;\n+\t\t\tcase 't':\t\t/* Tab */\n+\t\t\t\tnum = '\\t';\n+\t\t\t\tbreak;\n+\t\t\tcase 'v':\t\t/* Vtab */\n+\t\t\t\tnum = '\\v';\n+\t\t\t\tbreak;\n+\t\t\tcase '?':\t\t/* Delete */\n+\t\t\t\tnum = 127;\n+\t\t\t\tbreak;\n+\t\t\tcase '_':\t\t/* Space */\n+\t\t\t\tnum = ' ';\n+\t\t\t\tbreak;\n+\t\t\tcase '\\0':\t\t/* End of string */\n+\t\t\t\tstate = ST_ERROR;\t/* Error! */\n+\t\t\t\tbreak;\n+\t\t\tdefault:\t\t/* Escaped character like \\ ^ : = */\n+\t\t\t\tnum = *p;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tif (state == ST_BACKSLASH) {\n+\t\t\t\t*(q++) = num;\n+\t\t\t\t++count;\n+\t\t\t\tstate = ST_GND;\n+\t\t\t}\n+\t\t\t++p;\n+\t\t\tbreak;\n+\n+\t\tcase ST_OCTAL:\t\t/* Octal sequence */\n+\t\t\tif (*p < '0' || *p > '7') {\n+\t\t\t\t*(q++) = num;\n+\t\t\t\t++count;\n+\t\t\t\tstate = ST_GND;\n+\t\t\t} else\n+\t\t\t\tnum = (num << 3) + (*(p++) - '0');\n+\t\t\tbreak;\n+\n+\t\tcase ST_HEX:\t\t/* Hex sequence */\n+\t\t\tswitch (*p) {\n+\t\t\tcase '0':\n+\t\t\tcase '1':\n+\t\t\tcase '2':\n+\t\t\tcase '3':\n+\t\t\tcase '4':\n+\t\t\tcase '5':\n+\t\t\tcase '6':\n+\t\t\tcase '7':\n+\t\t\tcase '8':\n+\t\t\tcase '9':\n+\t\t\t\tnum = (num << 4) + (*(p++) - '0');\n+\t\t\t\tbreak;\n+\t\t\tcase 'a':\n+\t\t\tcase 'b':\n+\t\t\tcase 'c':\n+\t\t\tcase 'd':\n+\t\t\tcase 'e':\n+\t\t\tcase 'f':\n+\t\t\t\tnum = (num << 4) + (*(p++) - 'a') + 10;\n+\t\t\t\tbreak;\n+\t\t\tcase 'A':\n+\t\t\tcase 'B':\n+\t\t\tcase 'C':\n+\t\t\tcase 'D':\n+\t\t\tcase 'E':\n+\t\t\tcase 'F':\n+\t\t\t\tnum = (num << 4) + (*(p++) - 'A') + 10;\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\t*(q++) = num;\n+\t\t\t\t++count;\n+\t\t\t\tstate = ST_GND;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase ST_CARET:\t\t/* Caret escape */\n+\t\t\tstate = ST_GND;\t/* Should be the next state... */\n+\t\t\tif (*p >= '@' && *p <= '~') {\n+\t\t\t\t*(q++) = *(p++) & 037;\n+\t\t\t\t++count;\n+\t\t\t} else if (*p == '?') {\n+\t\t\t\t*(q++) = 127;\n+\t\t\t\t++count;\n+\t\t\t} else\n+\t\t\t\tstate = ST_ERROR;\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tabort();\n+\t\t}\n+\t}\n+\n+\t*dest = q;\n+\t*src = p;\n+\t*output_count = count;\n+\n+\treturn state != ST_ERROR;\n+}\n+\n+void parse_ls_color(void)\n+{\n+\tconst char *p;\t\t\t/* Pointer to character being parsed */\n+\tchar *buf;\t\t\t/* color_buf buffer pointer */\n+\tint state;\t\t\t/* State of parser */\n+\tint ind_no;\t\t\t/* Indicator number */\n+\tchar label[3];\t\t\t/* Indicator label */\n+\tstruct color_ext_type *ext;\t/* Extension we are working on */\n+\tstatic char *color_buf;\n+\tchar *start;\n+\tsize_t len;\n+\n+\tif ((p = getenv(\"LS_COLORS\")) == NULL || *p == '\\0')\n+\t\treturn;\n+\n+\text = NULL;\n+\tstrcpy (label, \"??\");\n+\n+\t/*\n+\t * This is an overly conservative estimate, but any possible\n+\t * LS_COLORS string will *not* generate a color_buf longer\n+\t * than itself, so it is a safe way of allocating a buffer in\n+\t * advance.\n+\t */\n+\tbuf = color_buf = xstrdup(p);\n+\n+\tstate = 1;\n+\twhile (state > 0) {\n+\t\tswitch (state) {\n+\t\tcase 1:\t\t/* First label character */\n+\t\t\tswitch (*p) {\n+\t\t\tcase ':':\n+\t\t\t\t++p;\n+\t\t\t\tbreak;\n+\n+\t\t\tcase '*':\n+\t\t\t\t/*\n+\t\t\t\t * Allocate new extension block and add to head of\n+\t\t\t\t * linked list (this way a later definition will\n+\t\t\t\t * override an earlier one, which can be useful for\n+\t\t\t\t * having terminal-specific defs override global).\n+\t\t\t\t */\n+\n+\t\t\t\text = xmalloc(sizeof *ext);\n+\t\t\t\text->next = color_ext_list;\n+\t\t\t\tcolor_ext_list = ext;\n+\n+\t\t\t\t++p;\n+\t\t\t\text->ext.string = buf;\n+\n+\t\t\t\tstate = (get_funky_string(&buf, &p, 1, &ext->ext.len)\n+\t\t\t\t\t ? 4 : -1);\n+\t\t\t\tbreak;\n+\n+\t\t\tcase '\\0':\n+\t\t\t\tstate = 0;\t/* Done! */\n+\t\t\t\tbreak;\n+\n+\t\t\tdefault:\t/* Assume it is file type label */\n+\t\t\t\tlabel[0] = *(p++);\n+\t\t\t\tstate = 2;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase 2:\t\t/* Second label character */\n+\t\t\tif (*p) {\n+\t\t\t\tlabel[1] = *(p++);\n+\t\t\t\tstate = 3;\n+\t\t\t} else\n+\t\t\t\tstate = -1;\t/* Error */\n+\t\t\tbreak;\n+\n+\t\tcase 3:\t\t/* Equal sign after indicator label */\n+\t\t\tstate = -1;\t/* Assume failure...  */\n+\t\t\tif (*(p++) != '=')\n+\t\t\t\tbreak;\n+\t\t\tfor (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) {\n+\t\t\t\tif (!strcmp(label, indicator_name[ind_no])) {\n+\t\t\t\t\tstart = buf;\n+\t\t\t\t\tif (get_funky_string(&buf, &p, 0, &len))\n+\t\t\t\t\t\tstate = 1;\n+\t\t\t\t\telse\n+\t\t\t\t\t\tstate = -1;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif (state == -1)\n+\t\t\t\terror(_(\"unrecognized prefix: %s\"), label);\n+\t\t\telse if (ind_no == LS_LN && len == 6 &&\n+\t\t\t\t starts_with(start, \"target\"))\n+\t\t\t\tcolor_symlink_as_referent = 1;\n+\t\t\telse\n+\t\t\t\tsprintf(ls_colors[ind_no], \"\\033[%.*sm\",\n+\t\t\t\t       (int)len, start);\n+\t\t\tbreak;\n+\n+\t\tcase 4:\t\t/* Equal sign after *.ext */\n+\t\t\tif (*(p++) == '=') {\n+\t\t\t\text->seq.string = buf;\n+\t\t\t\tstate = (get_funky_string(&buf, &p, 0, &ext->seq.len)\n+\t\t\t\t\t ? 1 : -1);\n+\t\t\t} else\n+\t\t\t\tstate = -1;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (!strcmp(ls_colors[LS_LN], \"target\"))\n+\t\tcolor_symlink_as_referent = 1;\n+}\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252721","messageId":"1417337767-4505-3-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 02/19] ls_colors.c: parse color.ls.* from config file","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:50Z","receivedAt":"2014-11-30T08:55:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is the second (and preferred) source for color information. This\nwill override $LS_COLORS.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt | 11 +++++++++++\n ls_colors.c              | 26 ++++++++++++++++++++++++++\n 2 files changed, 37 insertions(+)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 9220725..2090866 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -940,6 +940,17 @@ color.status.<slot>::\n \tto red). The values of these variables may be specified as in\n \tcolor.branch.<slot>.\n \n+color.ls.<slot>::\n+\tUse customized color for file name colorization. If not set\n+\tand the environment variable LS_COLORS is set, color settings\n+\tfrom $LS_COLORS are used. `<slot>` can be `normal`, `file`,\n+\t`directory`, `symlink`, `fifo`, `socket`, `block`, `char`,\n+\t`missing`, `orphan`, `executable`, `door`, `setuid`, `setgid`,\n+\t`sticky`, `otherwritable`, `stickyotherwritable`, `cap`,\n+\t`multihardlink`. The values of these variables may be\n+\tspecified as in color.branch.<slot>.\n+\n+\n color.ui::\n \tThis variable determines the default value for variables such\n \tas `color.diff` and `color.grep` that control the use of color\ndiff --git a/ls_colors.c b/ls_colors.c\nindex eb944f4..3e35ffe 100644\n--- a/ls_colors.c\n+++ b/ls_colors.c\n@@ -68,6 +68,14 @@ static const char *const indicator_name[] = {\n \tNULL\n };\n \n+static const char* const config_name[] = {\n+\t\"\", \"\", \"\", \"\", \"normal\", \"file\", \"directory\", \"symlink\",\n+\t\"fifo\", \"socket\", \"block\", \"char\", \"missing\", \"orphan\", \"executable\",\n+\t\"door\", \"setuid\", \"setgid\", \"sticky\", \"otherwritable\",\n+\t\"stickyotherwritable\", \"cap\", \"multihardlink\", \"\",\n+\tNULL\n+};\n+\n struct bin_str {\n \tsize_t len;\t\t\t/* Number of bytes */\n \tconst char *string;\t\t/* Pointer to the same */\n@@ -285,6 +293,23 @@ static int get_funky_string(char **dest, const char **src, int equals_end,\n \treturn state != ST_ERROR;\n }\n \n+static int ls_colors_config(const char *var, const char *value, void *cb)\n+{\n+\tint slot;\n+\tif (!starts_with(var, \"color.ls.\"))\n+\t\treturn 0;\n+\tvar += 9;\n+\tfor (slot = 0; config_name[slot]; slot++)\n+\t\tif (!strcasecmp(var, config_name[slot]))\n+\t\t\tbreak;\n+\tif (!config_name[slot])\n+\t\treturn 0;\n+\tif (!value)\n+\t\treturn config_error_nonbool(var);\n+\tcolor_parse(value, ls_colors[slot]);\n+\treturn 0;\n+}\n+\n void parse_ls_color(void)\n {\n \tconst char *p;\t\t\t/* Pointer to character being parsed */\n@@ -395,4 +420,5 @@ void parse_ls_color(void)\n \n \tif (!strcmp(ls_colors[LS_LN], \"target\"))\n \t\tcolor_symlink_as_referent = 1;\n+\tgit_config(ls_colors_config, NULL);\n }\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252722","messageId":"1417337767-4505-4-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 03/19] ls_colors.c: add a function to color a file name","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:51Z","receivedAt":"2014-11-30T08:55:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The new function is based on print_color_indicator() from commit\n7326d1f1a67edf21947ae98194f98c38b6e9e527 in coreutils.git.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n color.h     |  2 ++\n ls_colors.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 68 insertions(+)\n\ndiff --git a/color.h b/color.h\nindex 3eaa5bd..b6904a3 100644\n--- a/color.h\n+++ b/color.h\n@@ -94,5 +94,7 @@ void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);\n int color_is_nil(const char *color);\n \n void parse_ls_color(void);\n+void color_filename(struct strbuf *sb, const char *name,\n+\t\t    const char *display_name, mode_t mode, int linkok);\n \n #endif /* COLOR_H */\ndiff --git a/ls_colors.c b/ls_colors.c\nindex 3e35ffe..a58da9e 100644\n--- a/ls_colors.c\n+++ b/ls_colors.c\n@@ -422,3 +422,69 @@ void parse_ls_color(void)\n \t\tcolor_symlink_as_referent = 1;\n \tgit_config(ls_colors_config, NULL);\n }\n+\n+void color_filename(struct strbuf *sb, const char *name,\n+\t\t    const char *display_name, mode_t mode, int linkok)\n+{\n+\tint type;\n+\tstruct color_ext_type *ext;\t/* Color extension */\n+\n+\tif (S_ISREG (mode)) {\n+\t\ttype = LS_FL;\n+\t\tif ((mode & S_ISUID) != 0)\n+\t\t\ttype = LS_SU;\n+\t\telse if ((mode & S_ISGID) != 0)\n+\t\t\ttype = LS_SG;\n+\t\telse if ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)\n+\t\t\ttype = LS_EX;\n+\t} else if (S_ISDIR (mode)) {\n+\t\tif ((mode & S_ISVTX) && (mode & S_IWOTH))\n+\t\t\ttype = LS_TW;\n+\t\telse if ((mode & S_IWOTH) != 0)\n+\t\t\ttype = LS_OW;\n+\t\telse if ((mode & S_ISVTX) != 0)\n+\t\t\ttype = LS_ST;\n+\t\telse\n+\t\t\ttype = LS_DI;\n+\t} else if (S_ISLNK (mode))\n+\t\ttype = (!linkok && *ls_colors[LS_OR]) ? LS_OR : LS_LN;\n+\telse if (S_ISFIFO (mode))\n+\t\ttype = LS_PI;\n+\telse if (S_ISSOCK (mode))\n+\t\ttype = LS_SO;\n+\telse if (S_ISBLK (mode))\n+\t\ttype = LS_BD;\n+\telse if (S_ISCHR (mode))\n+\t\ttype = LS_CD;\n+#ifdef S_ISDOOR\n+\telse if (S_ISDOOR (mode))\n+\t\ttype = LS_DO;\n+#endif\n+\telse\n+\t\t/* Classify a file of some other type as C_ORPHAN.  */\n+\t\ttype = LS_OR;\n+\n+\t/* Check the file's suffix only if still classified as C_FILE.  */\n+\text = NULL;\n+\tif (type == LS_FL) {\n+\t\t/* Test if NAME has a recognized suffix.  */\n+\t\tsize_t len = strlen(name);\n+\t\tconst char *p = name + len;\t\t/* Pointer to final \\0.  */\n+\t\tfor (ext = color_ext_list; ext != NULL; ext = ext->next) {\n+\t\t\tif (ext->ext.len <= len &&\n+\t\t\t    !strncmp(p - ext->ext.len, ext->ext.string, ext->ext.len))\n+\t\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (display_name)\n+\t\tname = display_name;\n+\tif (ext)\n+\t\tstrbuf_addf(sb, \"\\033[%.*sm%s%s\",\n+\t\t\t    (int)ext->seq.len, ext->seq.string,\n+\t\t\t    name, GIT_COLOR_RESET);\n+\telse if (*ls_colors[type])\n+\t\tstrbuf_addf(sb, \"%s%s%s\", ls_colors[type], name, GIT_COLOR_RESET);\n+\telse\n+\t\tstrbuf_addstr(sb, name);\n+}\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252723","messageId":"1417337767-4505-5-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 04/19] ls_colors.c: highlight submodules like directories","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:52Z","receivedAt":"2014-11-30T08:55:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/config.txt | 3 ++-\n ls_colors.c              | 8 +++++++-\n 2 files changed, 9 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2090866..2290c47 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -944,7 +944,8 @@ color.ls.<slot>::\n \tUse customized color for file name colorization. If not set\n \tand the environment variable LS_COLORS is set, color settings\n \tfrom $LS_COLORS are used. `<slot>` can be `normal`, `file`,\n-\t`directory`, `symlink`, `fifo`, `socket`, `block`, `char`,\n+\t`directory`, `submodule`,\n+\t`symlink`, `fifo`, `socket`, `block`, `char`,\n \t`missing`, `orphan`, `executable`, `door`, `setuid`, `setgid`,\n \t`sticky`, `otherwritable`, `stickyotherwritable`, `cap`,\n \t`multihardlink`. The values of these variables may be\ndiff --git a/ls_colors.c b/ls_colors.c\nindex a58da9e..e62e74b 100644\n--- a/ls_colors.c\n+++ b/ls_colors.c\n@@ -29,6 +29,8 @@ enum color_ls {\n \tLS_MH,\t\t\t/* multi hardlink */\n \tLS_CL,\t\t\t/* clear end of line */\n \n+\tLS_SUBMODULE,\n+\n \tMAX_LS\n };\n \n@@ -58,7 +60,8 @@ static char ls_colors[MAX_LS][COLOR_MAXLEN] = {\n \tGIT_COLOR_BLACK_ON_GREEN,\n \t\"\",\n \t\"\",\n-\t\"\"\n+\t\"\",\n+\tGIT_COLOR_BOLD_BLUE\n };\n \n static const char *const indicator_name[] = {\n@@ -73,6 +76,7 @@ static const char* const config_name[] = {\n \t\"fifo\", \"socket\", \"block\", \"char\", \"missing\", \"orphan\", \"executable\",\n \t\"door\", \"setuid\", \"setgid\", \"sticky\", \"otherwritable\",\n \t\"stickyotherwritable\", \"cap\", \"multihardlink\", \"\",\n+\t\"submodule\",\n \tNULL\n };\n \n@@ -448,6 +452,8 @@ void color_filename(struct strbuf *sb, const char *name,\n \t\t\ttype = LS_DI;\n \t} else if (S_ISLNK (mode))\n \t\ttype = (!linkok && *ls_colors[LS_OR]) ? LS_OR : LS_LN;\n+\telse if (S_ISGITLINK(mode))\n+\t\ttype = LS_SUBMODULE;\n \telse if (S_ISFIFO (mode))\n \t\ttype = LS_PI;\n \telse if (S_ISSOCK (mode))\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252724","messageId":"1417337767-4505-6-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 05/19] ls-files: buffer full item in strbuf before printing","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:53Z","receivedAt":"2014-11-30T08:55:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Buffering so that we can manipulate the strings (e.g. coloring)\nfurther before finally printing them.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-files.c | 48 +++++++++++++++++++++++++++++++++++-------------\n 1 file changed, 35 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 99cee20..f20c0fd 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -47,18 +47,30 @@ static const char *tag_modified = \"\";\n static const char *tag_skip_worktree = \"\";\n static const char *tag_resolve_undo = \"\";\n \n-static void write_name(const char *name)\n+static void write_name(struct strbuf *sb, const char *name)\n {\n \t/*\n \t * With \"--full-name\", prefix_len=0; this caller needs to pass\n \t * an empty string in that case (a NULL is good for \"\").\n \t */\n-\twrite_name_quoted_relative(name, prefix_len ? prefix : NULL,\n-\t\t\t\t   stdout, line_terminator);\n+\tconst char *real_prefix = prefix_len ? prefix : NULL;\n+\tif (!line_terminator) {\n+\t\tstruct strbuf sb2 = STRBUF_INIT;\n+\t\tstrbuf_addstr(sb, relative_path(name, real_prefix, &sb2));\n+\t\tstrbuf_release(&sb2);\n+\t} else\n+\t\tquote_path_relative(name, real_prefix, sb);\n+\tstrbuf_addch(sb, line_terminator);\n+}\n+\n+static void strbuf_fputs(struct strbuf *sb, FILE *fp)\n+{\n+\tfwrite(sb->buf, sb->len, 1, fp);\n }\n \n static void show_dir_entry(const char *tag, struct dir_entry *ent)\n {\n+\tstatic struct strbuf sb = STRBUF_INIT;\n \tint len = max_prefix_len;\n \n \tif (len >= ent->len)\n@@ -67,8 +79,10 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \tif (!dir_path_match(ent, &pathspec, len, ps_matched))\n \t\treturn;\n \n-\tfputs(tag, stdout);\n-\twrite_name(ent->name);\n+\tstrbuf_reset(&sb);\n+\tstrbuf_addstr(&sb, tag);\n+\twrite_name(&sb, ent->name);\n+\tstrbuf_fputs(&sb, stdout);\n }\n \n static void show_other_files(struct dir_struct *dir)\n@@ -134,6 +148,7 @@ static void show_killed_files(struct dir_struct *dir)\n \n static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n {\n+\tstatic struct strbuf sb = STRBUF_INIT;\n \tint len = max_prefix_len;\n \n \tif (len >= ce_namelen(ce))\n@@ -161,16 +176,18 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\ttag = alttag;\n \t}\n \n+\tstrbuf_reset(&sb);\n \tif (!show_stage) {\n-\t\tfputs(tag, stdout);\n+\t\tstrbuf_addstr(&sb, tag);\n \t} else {\n-\t\tprintf(\"%s%06o %s %d\\t\",\n-\t\t       tag,\n-\t\t       ce->ce_mode,\n-\t\t       find_unique_abbrev(ce->sha1,abbrev),\n-\t\t       ce_stage(ce));\n+\t\tstrbuf_addf(&sb, \"%s%06o %s %d\\t\",\n+\t\t\t    tag,\n+\t\t\t    ce->ce_mode,\n+\t\t\t    find_unique_abbrev(ce->sha1,abbrev),\n+\t\t\t    ce_stage(ce));\n \t}\n-\twrite_name(ce->name);\n+\twrite_name(&sb, ce->name);\n+\tstrbuf_fputs(&sb, stdout);\n \tif (debug_mode) {\n \t\tconst struct stat_data *sd = &ce->ce_stat_data;\n \n@@ -206,7 +223,12 @@ static void show_ru_info(void)\n \t\t\tprintf(\"%s%06o %s %d\\t\", tag_resolve_undo, ui->mode[i],\n \t\t\t       find_unique_abbrev(ui->sha1[i], abbrev),\n \t\t\t       i + 1);\n-\t\t\twrite_name(path);\n+\t\t\t/*\n+\t\t\t * With \"--full-name\", prefix_len=0; this caller needs to pass\n+\t\t\t * an empty string in that case (a NULL is good for \"\").\n+\t\t\t */\n+\t\t\twrite_name_quoted_relative(path, prefix_len ? prefix : NULL,\n+\t\t\t\t\t\t   stdout, line_terminator);\n \t\t}\n \t}\n }\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252725","messageId":"1417337767-4505-7-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 06/19] ls-files: add --color to highlight file names","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:54Z","receivedAt":"2014-11-30T08:55:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-ls-files.txt |  7 +++++++\n builtin/ls-files.c             | 38 +++++++++++++++++++++++++++++++++++---\n 2 files changed, 42 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex e26f01f..148f226 100644\n--- a/Documentation/git-ls-files.txt\n+++ b/Documentation/git-ls-files.txt\n@@ -147,6 +147,13 @@ a space) at the start of each line:\n \tpossible for manual inspection; the exact format may change at\n \tany time.\n \n+--color[=<when>]::\n+--no-color::\n+\tColor file names. The value must be `always`, `never`, or\n+\t`auto`. `--no-color` is equivalent to\n+\t`--color=never`. `--color` is equivalent to\n+\t`--color=auto`.\n+\n \\--::\n \tDo not interpret any more arguments as options.\n \ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex f20c0fd..4ddd49f 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -14,6 +14,7 @@\n #include \"resolve-undo.h\"\n #include \"string-list.h\"\n #include \"pathspec.h\"\n+#include \"color.h\"\n \n static int abbrev;\n static int show_deleted;\n@@ -27,6 +28,7 @@ static int show_killed;\n static int show_valid_bit;\n static int line_terminator = '\\n';\n static int debug_mode;\n+static int use_color;\n \n static const char *prefix;\n static int max_prefix_len;\n@@ -60,7 +62,6 @@ static void write_name(struct strbuf *sb, const char *name)\n \t\tstrbuf_release(&sb2);\n \t} else\n \t\tquote_path_relative(name, real_prefix, sb);\n-\tstrbuf_addch(sb, line_terminator);\n }\n \n static void strbuf_fputs(struct strbuf *sb, FILE *fp)\n@@ -68,6 +69,21 @@ static void strbuf_fputs(struct strbuf *sb, FILE *fp)\n \tfwrite(sb->buf, sb->len, 1, fp);\n }\n \n+static void write_dir_entry(struct strbuf *sb, const struct dir_entry *ent)\n+{\n+\tstruct strbuf quoted = STRBUF_INIT;\n+\tstruct stat st;\n+\tif (stat(ent->name, &st))\n+\t\tst.st_mode = 0;\n+\twrite_name(&quoted, ent->name);\n+\tif (want_color(use_color))\n+\t\tcolor_filename(sb, ent->name, quoted.buf, st.st_mode, 1);\n+\telse\n+\t\tstrbuf_addbuf(sb, &quoted);\n+\tstrbuf_addch(sb, line_terminator);\n+\tstrbuf_release(&quoted);\n+}\n+\n static void show_dir_entry(const char *tag, struct dir_entry *ent)\n {\n \tstatic struct strbuf sb = STRBUF_INIT;\n@@ -81,7 +97,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \n \tstrbuf_reset(&sb);\n \tstrbuf_addstr(&sb, tag);\n-\twrite_name(&sb, ent->name);\n+\twrite_dir_entry(&sb, ent);\n \tstrbuf_fputs(&sb, stdout);\n }\n \n@@ -146,6 +162,18 @@ static void show_killed_files(struct dir_struct *dir)\n \t}\n }\n \n+static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)\n+{\n+\tstruct strbuf quoted = STRBUF_INIT;\n+\twrite_name(&quoted, ce->name);\n+\tif (want_color(use_color))\n+\t\tcolor_filename(sb, ce->name, quoted.buf, ce->ce_mode, 1);\n+\telse\n+\t\tstrbuf_addbuf(sb, &quoted);\n+\tstrbuf_addch(sb, line_terminator);\n+\tstrbuf_release(&quoted);\n+}\n+\n static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n {\n \tstatic struct strbuf sb = STRBUF_INIT;\n@@ -186,7 +214,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t\t    find_unique_abbrev(ce->sha1,abbrev),\n \t\t\t    ce_stage(ce));\n \t}\n-\twrite_name(&sb, ce->name);\n+\twrite_ce_name(&sb, ce);\n \tstrbuf_fputs(&sb, stdout);\n \tif (debug_mode) {\n \t\tconst struct stat_data *sd = &ce->ce_stat_data;\n@@ -523,6 +551,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tN_(\"if any <file> is not in the index, treat this as an error\")),\n \t\tOPT_STRING(0, \"with-tree\", &with_tree, N_(\"tree-ish\"),\n \t\t\tN_(\"pretend that paths removed since <tree-ish> are still present\")),\n+\t\tOPT__COLOR(&use_color, N_(\"show color\")),\n \t\tOPT__ABBREV(&abbrev),\n \t\tOPT_BOOL(0, \"debug\", &debug_mode, N_(\"show debugging data\")),\n \t\tOPT_END()\n@@ -570,6 +599,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (require_work_tree && !is_inside_work_tree())\n \t\tsetup_work_tree();\n \n+\tif (want_color(use_color))\n+\t\tparse_ls_color();\n+\n \tparse_pathspec(&pathspec, 0,\n \t\t       PATHSPEC_PREFER_CWD |\n \t\t       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252726","messageId":"1417337767-4505-8-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 07/19] ls-files: add --column","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:55Z","receivedAt":"2014-11-30T08:55:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-ls-files.txt |  6 ++++++\n builtin/ls-files.c             | 28 ++++++++++++++++++++++++++++\n 2 files changed, 34 insertions(+)\n\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex 148f226..99328b9 100644\n--- a/Documentation/git-ls-files.txt\n+++ b/Documentation/git-ls-files.txt\n@@ -154,6 +154,12 @@ a space) at the start of each line:\n \t`--color=never`. `--color` is equivalent to\n \t`--color=auto`.\n \n+--column[=<options>]::\n+--no-column::\n+\tDisplay files in columns. See configuration variable column.ui\n+\tfor option syntax. `--column` and `--no-column` without options\n+\tare equivalent to 'always' and 'never' respectively.\n+\n \\--::\n \tDo not interpret any more arguments as options.\n \ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 4ddd49f..79e1944 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -15,6 +15,7 @@\n #include \"string-list.h\"\n #include \"pathspec.h\"\n #include \"color.h\"\n+#include \"column.h\"\n \n static int abbrev;\n static int show_deleted;\n@@ -29,6 +30,7 @@ static int show_valid_bit;\n static int line_terminator = '\\n';\n static int debug_mode;\n static int use_color;\n+static unsigned int colopts;\n \n static const char *prefix;\n static int max_prefix_len;\n@@ -39,6 +41,7 @@ static char *ps_matched;\n static const char *with_tree;\n static int exc_given;\n static int exclude_args;\n+static struct string_list output = STRING_LIST_INIT_NODUP;\n \n static const char *tag_cached = \"\";\n static const char *tag_unmerged = \"\";\n@@ -66,6 +69,10 @@ static void write_name(struct strbuf *sb, const char *name)\n \n static void strbuf_fputs(struct strbuf *sb, FILE *fp)\n {\n+\tif (column_active(colopts)) {\n+\t\tstring_list_append(&output, strbuf_detach(sb, NULL));\n+\t\treturn;\n+\t}\n \tfwrite(sb->buf, sb->len, 1, fp);\n }\n \n@@ -552,6 +559,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tOPT_STRING(0, \"with-tree\", &with_tree, N_(\"tree-ish\"),\n \t\t\tN_(\"pretend that paths removed since <tree-ish> are still present\")),\n \t\tOPT__COLOR(&use_color, N_(\"show color\")),\n+\t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"show files in columns\")),\n \t\tOPT__ABBREV(&abbrev),\n \t\tOPT_BOOL(0, \"debug\", &debug_mode, N_(\"show debugging data\")),\n \t\tOPT_END()\n@@ -596,6 +604,18 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (dir.exclude_per_dir)\n \t\texc_given = 1;\n \n+\tfinalize_colopts(&colopts, -1);\n+\tif (explicitly_enable_column(colopts)) {\n+\t\tif (!line_terminator)\n+\t\t\tdie(_(\"--column and -z are incompatible\"));\n+\t\tif (show_resolve_undo)\n+\t\t\tdie(_(\"--column and --resolve-undo are incompatible\"));\n+\t\tif (debug_mode)\n+\t\t\tdie(_(\"--column and --debug are incompatible\"));\n+\t}\n+\tif (column_active(colopts))\n+\t\tline_terminator = 0;\n+\n \tif (require_work_tree && !is_inside_work_tree())\n \t\tsetup_work_tree();\n \n@@ -638,6 +658,14 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (show_resolve_undo)\n \t\tshow_ru_info();\n \n+\tif (column_active(colopts)) {\n+\t\tstruct column_options copts;\n+\t\tmemset(&copts, 0, sizeof(copts));\n+\t\tcopts.padding = 2;\n+\t\tprint_columns(&output, colopts, &copts);\n+\t\tstring_list_clear(&output, 0);\n+\t}\n+\n \tif (ps_matched) {\n \t\tint bad;\n \t\tbad = report_path_error(ps_matched, &pathspec, prefix);\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252727","messageId":"1417337767-4505-9-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 08/19] ls-files: support --max-depth","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:56Z","receivedAt":"2014-11-30T08:55:56Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-ls-files.txt | 7 +++++++\n builtin/ls-files.c             | 7 +++++++\n 2 files changed, 14 insertions(+)\n\ndiff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt\nindex 99328b9..3d921eb 100644\n--- a/Documentation/git-ls-files.txt\n+++ b/Documentation/git-ls-files.txt\n@@ -160,6 +160,13 @@ a space) at the start of each line:\n \tfor option syntax. `--column` and `--no-column` without options\n \tare equivalent to 'always' and 'never' respectively.\n \n+--max-depth=<depth>::\n+\tFor each <pathspec> given on command line, descend at most <depth>\n+\tlevels of directories. A negative value means no limit (default).\n+\tThis option is ignored if <pathspec> contains active wildcards.\n+\tIn other words if \"a*\" matches a directory named \"a*\",\n+\t\"*\" is matched literally so --max-depth is still effective.\n+\n \\--::\n \tDo not interpret any more arguments as options.\n \ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 79e1944..40fe0f2 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -503,6 +503,7 @@ static int option_parse_exclude_standard(const struct option *opt,\n int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n {\n \tint require_work_tree = 0, show_tag = 0, i;\n+\tint max_depth = -1;\n \tconst char *max_prefix;\n \tstruct dir_struct dir;\n \tstruct exclude_list *el;\n@@ -560,6 +561,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tN_(\"pretend that paths removed since <tree-ish> are still present\")),\n \t\tOPT__COLOR(&use_color, N_(\"show color\")),\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"show files in columns\")),\n+\t\t{ OPTION_INTEGER, 0, \"max-depth\", &max_depth, N_(\"depth\"),\n+\t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n+\t\t\tNULL, 1 },\n \t\tOPT__ABBREV(&abbrev),\n \t\tOPT_BOOL(0, \"debug\", &debug_mode, N_(\"show debugging data\")),\n \t\tOPT_END()\n@@ -624,8 +628,11 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \n \tparse_pathspec(&pathspec, 0,\n \t\t       PATHSPEC_PREFER_CWD |\n+\t\t       (max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0) |\n \t\t       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,\n \t\t       prefix, argv);\n+\tpathspec.max_depth = max_depth;\n+\tpathspec.recursive = 1;\n \n \t/* Find common prefix for all pathspec's */\n \tmax_prefix = common_prefix(&pathspec);\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252728","messageId":"1417337767-4505-10-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:57Z","receivedAt":"2014-11-30T08:55:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is more user friendly version of ls-files:\n\n* it's automatically colored and columnized\n* it refreshes the index like all porcelain commands\n* it defaults to non-recursive behavior like ls\n* :(glob) is on by default so '*.c' means a.c but not a/b.c, use\n  '**/*.c' for that.\n* auto pager\n\nThe name 'ls' is not taken. It is left for the user to make an alias\nwith better default options.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n .gitignore                             |  1 +\n Documentation/config.txt               | 10 +++++\n Documentation/git-list-files.txt (new) | 80 ++++++++++++++++++++++++++++++++++\n Makefile                               |  1 +\n builtin/ls-files.c                     | 69 +++++++++++++++++++++++++++--\n command-list.txt                       |  1 +\n git.c                                  |  1 +\n 7 files changed, 159 insertions(+), 4 deletions(-)\n create mode 100644 Documentation/git-list-files.txt\n\ndiff --git a/.gitignore b/.gitignore\nindex a052419..9727ecc 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -76,6 +76,7 @@\n /git-init-db\n /git-interpret-trailers\n /git-instaweb\n+/git-list-files\n /git-log\n /git-ls-files\n /git-ls-remote\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2290c47..74da715 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -940,6 +940,12 @@ color.status.<slot>::\n \tto red). The values of these variables may be specified as in\n \tcolor.branch.<slot>.\n \n+color.list-files::\n+\tA boolean to enable/disable color in the output of\n+\tlinkgit:git-list-files[1]. May be set to `always`, `false` (or\n+\t`never`) or `auto` (or `true`), in which case colors are used\n+\tonly when the output is to a terminal. Defaults to false.\n+\n color.ls.<slot>::\n \tUse customized color for file name colorization. If not set\n \tand the environment variable LS_COLORS is set, color settings\n@@ -1012,6 +1018,10 @@ column.clean::\n \tSpecify the layout when list items in `git clean -i`, which always\n \tshows files and directories in columns. See `column.ui` for details.\n \n+column.list-files::\n+\tSpecify whether to output tag listing in `git list-files` in columns.\n+\tSee `column.ui` for details.\n+\n column.status::\n \tSpecify whether to output untracked files in `git status` in columns.\n \tSee `column.ui` for details.\ndiff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt\nnew file mode 100644\nindex 0000000..3039e1e\n--- /dev/null\n+++ b/Documentation/git-list-files.txt\n@@ -0,0 +1,80 @@\n+git-list-files(1)\n+===============\n+\n+NAME\n+----\n+git-list-files - List files\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git list-files [options] [<pathspec>...]\n+\n+DESCRIPTION\n+-----------\n+List files (by default in current working directory) that are in the\n+index. Depending on the chosen options, maybe only modified files in\n+working tree are shown, or untracked files...\n+\n+OPTIONS\n+-------\n+-c::\n+--cached::\n+\tShow cached files (default)\n+\n+-d::\n+--deleted::\n+\tShow cached files that are deleted on working directory\n+\n+-m::\n+--modified::\n+\tShow cached files that have modification on working directory\n+\n+-o::\n+--others::\n+\tShow untracked files (and only unignored ones unless -i is\n+\tspecified)\n+\n+-i::\n+--ignored::\n+\tShow only ignored files. When showing files in the index,\n+\tprint only those matched by an exclude pattern. When showing\n+\t\"other\" files, show only those matched by an exclude pattern.\n+\n+-u::\n+--unmerged::\n+\tShow unmerged files\n+\n+--color[=<when>]::\n+--no-color::\n+\tColor file names. The value must be `always`, `never`, or\n+\t`auto`. `--no-color` is equivalent to\n+\t`--color=never`. `--color` is equivalent to\n+\t`--color=auto`. See configuration variable `color.list-files`\n+\tfor the default settings.\n+\n+--column[=<options>]::\n+--no-column::\n+\tDisplay files in columns. See configuration variable column.ui\n+\tfor option syntax. `--column` and `--no-column` without options\n+\tare equivalent to 'always' and 'never' respectively.\n+\n+--max-depth=<depth>::\n+\tFor each <pathspec> given on command line, descend at most <depth>\n+\tlevels of directories. A negative value means no limit.\n+\tThis option is ignored if <pathspec> contains active wildcards.\n+\tIn other words if \"a*\" matches a directory named \"a*\",\n+\t\"*\" is matched literally so --max-depth is still effective.\n+\tThe default is `--max-depth=0`.\n+\n+<pathspec>::\n+\tFiles to show. :(glob) magic is enabled and recursion disabled\n+\tby default.\n+\n+SEE ALSO\n+--------\n+linkgit:git-ls-files[1]\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex 459121d..23a0751 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -587,6 +587,7 @@ BUILT_INS += git-cherry-pick$X\n BUILT_INS += git-format-patch$X\n BUILT_INS += git-fsck-objects$X\n BUILT_INS += git-init$X\n+BUILT_INS += git-list-files$X\n BUILT_INS += git-merge-subtree$X\n BUILT_INS += git-show$X\n BUILT_INS += git-stage$X\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 40fe0f2..f3873a8 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -31,6 +31,7 @@ static int line_terminator = '\\n';\n static int debug_mode;\n static int use_color;\n static unsigned int colopts;\n+static int porcelain;\n \n static const char *prefix;\n static int max_prefix_len;\n@@ -459,6 +460,11 @@ static const char * const ls_files_usage[] = {\n \tNULL\n };\n \n+static const char * const ls_usage[] = {\n+\tN_(\"git list-files [options] [<file>...]\"),\n+\tNULL\n+};\n+\n static int option_parse_z(const struct option *opt,\n \t\t\t  const char *arg, int unset)\n {\n@@ -500,6 +506,17 @@ static int option_parse_exclude_standard(const struct option *opt,\n \treturn 0;\n }\n \n+static int git_ls_config(const char *var, const char *value, void *cb)\n+{\n+\tif (starts_with(var, \"column.\"))\n+\t\treturn git_column_config(var, value, \"list-files\", &colopts);\n+\tif (!strcmp(var, \"color.list-files\")) {\n+\t\tuse_color = git_config_colorbool(var, value);\n+\t\treturn 0;\n+\t}\n+\treturn git_color_default_config(var, value, cb);\n+}\n+\n int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n {\n \tint require_work_tree = 0, show_tag = 0, i;\n@@ -568,21 +585,61 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tOPT_BOOL(0, \"debug\", &debug_mode, N_(\"show debugging data\")),\n \t\tOPT_END()\n \t};\n+\tstruct option builtin_ls_options[] = {\n+\t\tOPT_BOOL('c', \"cached\", &show_cached,\n+\t\t\tN_(\"show cached files (default)\")),\n+\t\tOPT_BOOL('d', \"deleted\", &show_deleted,\n+\t\t\tN_(\"show cached files that are deleted on working directory\")),\n+\t\tOPT_BOOL('m', \"modified\", &show_modified,\n+\t\t\tN_(\"show cached files that have modification on working directory\")),\n+\t\tOPT_BOOL('o', \"others\", &show_others,\n+\t\t\tN_(\"show untracked files\")),\n+\t\tOPT_BIT('i', \"ignored\", &dir.flags,\n+\t\t\tN_(\"show ignored files\"),\n+\t\t\tDIR_SHOW_IGNORED),\n+\t\tOPT_BOOL('u', \"unmerged\", &show_unmerged,\n+\t\t\tN_(\"show unmerged files\")),\n+\t\tOPT__COLOR(&use_color, N_(\"show color\")),\n+\t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"show files in columns\")),\n+\t\t{ OPTION_INTEGER, 0, \"max-depth\", &max_depth, N_(\"depth\"),\n+\t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n+\t\t\tNULL, 1 },\n+\t\tOPT__ABBREV(&abbrev),\n+\t\tOPT_END()\n+\t};\n+\tstruct option *options;\n+\tconst char * const *help_usage;\n \n+\tif (!strcmp(argv[0], \"list-files\")) {\n+\t\thelp_usage = ls_usage;\n+\t\toptions = builtin_ls_options;\n+\t\tporcelain = 1;\n+\t} else {\n+\t\thelp_usage = ls_files_usage;\n+\t\toptions = builtin_ls_files_options;\n+\t}\n \tif (argc == 2 && !strcmp(argv[1], \"-h\"))\n-\t\tusage_with_options(ls_files_usage, builtin_ls_files_options);\n+\t\tusage_with_options(help_usage, options);\n \n \tmemset(&dir, 0, sizeof(dir));\n \tprefix = cmd_prefix;\n \tif (prefix)\n \t\tprefix_len = strlen(prefix);\n-\tgit_config(git_default_config, NULL);\n+\n+\tif (porcelain) {\n+\t\tsetenv(GIT_GLOB_PATHSPECS_ENVIRONMENT, \"1\", 1);\n+\t\texc_given = 1;\n+\t\tsetup_standard_excludes(&dir);\n+\t\tuse_color = -1;\n+\t\tmax_depth = 0;\n+\t\tgit_config(git_ls_config, NULL);\n+\t} else\n+\t\tgit_config(git_default_config, NULL);\n \n \tif (read_cache() < 0)\n \t\tdie(\"index file corrupt\");\n \n-\targc = parse_options(argc, argv, prefix, builtin_ls_files_options,\n-\t\t\tls_files_usage, 0);\n+\targc = parse_options(argc, argv, prefix, options, help_usage, 0);\n \tel = add_exclude_list(&dir, EXC_CMDL, \"--exclude option\");\n \tfor (i = 0; i < exclude_list.nr; i++) {\n \t\tadd_exclude(exclude_list.items[i].string, \"\", 0, el, --exclude_args);\n@@ -661,6 +718,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tdie(\"ls-files --with-tree is incompatible with -s or -u\");\n \t\toverlay_tree_on_cache(with_tree, max_prefix);\n \t}\n+\tif (porcelain) {\n+\t\trefresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);\n+\t\tsetup_pager();\n+\t}\n \tshow_files(&dir);\n \tif (show_resolve_undo)\n \t\tshow_ru_info();\ndiff --git a/command-list.txt b/command-list.txt\nindex f1eae08..32101de 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -64,6 +64,7 @@ git-init                                mainporcelain common\n git-instaweb                            ancillaryinterrogators\n git-interpret-trailers                  purehelpers\n gitk                                    mainporcelain\n+git-list-files                          mainporcelain\n git-log                                 mainporcelain common\n git-ls-files                            plumbinginterrogators\n git-ls-remote                           plumbinginterrogators\ndiff --git a/git.c b/git.c\nindex 18fbf79..617c083 100644\n--- a/git.c\n+++ b/git.c\n@@ -418,6 +418,7 @@ static struct cmd_struct commands[] = {\n \t{ \"init\", cmd_init_db, NO_SETUP },\n \t{ \"init-db\", cmd_init_db, NO_SETUP },\n \t{ \"interpret-trailers\", cmd_interpret_trailers, RUN_SETUP },\n+\t{ \"list-files\", cmd_ls_files, RUN_SETUP },\n \t{ \"log\", cmd_log, RUN_SETUP },\n \t{ \"ls-files\", cmd_ls_files, RUN_SETUP },\n \t{ \"ls-remote\", cmd_ls_remote, RUN_SETUP_GENTLY },\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252729","messageId":"1417337767-4505-11-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 10/19] list-files: -u does not imply showing stages","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:58Z","receivedAt":"2014-11-30T08:55:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Showing full index entry information is something for ls-files\nonly. The users of \"git list-files\" may just want to know what entries\nare not unmerged.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-files.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex f3873a8..f2b62b5 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -656,7 +656,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t}\n \tif (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)\n \t\trequire_work_tree = 1;\n-\tif (show_unmerged)\n+\tif (show_unmerged && !porcelain)\n \t\t/*\n \t\t * There's no point in showing unmerged unless\n \t\t * you also show the stage information.\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252730","messageId":"1417337767-4505-12-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 11/19] list-files: add -R/--recursive short for --max-depth=-1","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:55:59Z","receivedAt":"2014-11-30T08:55:59Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-list-files.txt | 4 ++++\n builtin/ls-files.c               | 2 ++\n 2 files changed, 6 insertions(+)\n\ndiff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt\nindex 3039e1e..5dccbbc 100644\n--- a/Documentation/git-list-files.txt\n+++ b/Documentation/git-list-files.txt\n@@ -45,6 +45,10 @@ OPTIONS\n --unmerged::\n \tShow unmerged files\n \n+-R::\n+--recursive::\n+\tEquivalent of `--max-depth=-1` (infinite recursion).\n+\n --color[=<when>]::\n --no-color::\n \tColor file names. The value must be `always`, `never`, or\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex f2b62b5..d0d39bd 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -594,6 +594,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tN_(\"show cached files that have modification on working directory\")),\n \t\tOPT_BOOL('o', \"others\", &show_others,\n \t\t\tN_(\"show untracked files\")),\n+\t\tOPT_SET_INT('R', \"recursive\", &max_depth,\n+\t\t\t    N_(\"shortcut for --max-depth=-1\"), -1),\n \t\tOPT_BIT('i', \"ignored\", &dir.flags,\n \t\t\tN_(\"show ignored files\"),\n \t\t\tDIR_SHOW_IGNORED),\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252731","messageId":"1417337767-4505-13-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 12/19] list-files: add -1 short for --no-column","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:56:00Z","receivedAt":"2014-11-30T08:56:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-list-files.txt | 3 +++\n builtin/ls-files.c               | 2 ++\n 2 files changed, 5 insertions(+)\n\ndiff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt\nindex 5dccbbc..725a236 100644\n--- a/Documentation/git-list-files.txt\n+++ b/Documentation/git-list-files.txt\n@@ -49,6 +49,9 @@ OPTIONS\n --recursive::\n \tEquivalent of `--max-depth=-1` (infinite recursion).\n \n+-1::\n+\tEquivalent of --no-column.\n+\n --color[=<when>]::\n --no-color::\n \tColor file names. The value must be `always`, `never`, or\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex d0d39bd..be9a39c 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -603,6 +603,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tN_(\"show unmerged files\")),\n \t\tOPT__COLOR(&use_color, N_(\"show color\")),\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"show files in columns\")),\n+\t\tOPT_SET_INT('1', NULL, &colopts,\n+\t\t\t    N_(\"shortcut for --no-column\"), COL_PARSEOPT),\n \t\t{ OPTION_INTEGER, 0, \"max-depth\", &max_depth, N_(\"depth\"),\n \t\t\tN_(\"descend at most <depth> levels\"), PARSE_OPT_NONEG,\n \t\t\tNULL, 1 },\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252732","messageId":"1417337767-4505-14-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 13/19] list-files: add -t back","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:56:01Z","receivedAt":"2014-11-30T08:56:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Tag \"H\" (cached) is not shown though because it's usually the majority\nand becomes noise. Not showing it makes the other tags stand out. -t\nis on by default if more than one file category is selected.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-list-files.txt |  6 ++++++\n builtin/ls-files.c               | 27 +++++++++++++++++----------\n 2 files changed, 23 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt\nindex 725a236..0ef616b 100644\n--- a/Documentation/git-list-files.txt\n+++ b/Documentation/git-list-files.txt\n@@ -45,6 +45,12 @@ OPTIONS\n --unmerged::\n \tShow unmerged files\n \n+-t::\n+--[no-]tag::\n+\tShow a tag to indicate file type. Automatically turned on with\n+\tmultiple file selections. See linkgit::git-ls-files[1] option\n+\t`-t` for more information.\n+\n -R::\n --recursive::\n \tEquivalent of `--max-depth=-1` (infinite recursion).\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex be9a39c..c7aaade 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -596,6 +596,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tN_(\"show untracked files\")),\n \t\tOPT_SET_INT('R', \"recursive\", &max_depth,\n \t\t\t    N_(\"shortcut for --max-depth=-1\"), -1),\n+\t\tOPT_BOOL('t', \"tag\", &show_tag,\n+\t\t\tN_(\"identify the file status with tags\")),\n \t\tOPT_BIT('i', \"ignored\", &dir.flags,\n \t\t\tN_(\"show ignored files\"),\n \t\t\tDIR_SHOW_IGNORED),\n@@ -636,6 +638,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tsetup_standard_excludes(&dir);\n \t\tuse_color = -1;\n \t\tmax_depth = 0;\n+\t\tshow_tag = -1;\n \t\tgit_config(git_ls_config, NULL);\n \t} else\n \t\tgit_config(git_default_config, NULL);\n@@ -648,16 +651,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tfor (i = 0; i < exclude_list.nr; i++) {\n \t\tadd_exclude(exclude_list.items[i].string, \"\", 0, el, --exclude_args);\n \t}\n-\tif (show_tag || show_valid_bit) {\n-\t\ttag_cached = \"H \";\n-\t\ttag_unmerged = \"M \";\n-\t\ttag_removed = \"R \";\n-\t\ttag_modified = \"C \";\n-\t\ttag_other = \"? \";\n-\t\ttag_killed = \"K \";\n-\t\ttag_skip_worktree = \"S \";\n-\t\ttag_resolve_undo = \"U \";\n-\t}\n \tif (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)\n \t\trequire_work_tree = 1;\n \tif (show_unmerged && !porcelain)\n@@ -711,6 +704,20 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t      show_killed || show_modified || show_resolve_undo))\n \t\tshow_cached = 1;\n \n+\tif (show_tag == -1)\n+\t\tshow_tag = (show_cached + show_deleted + show_others +\n+\t\t\t    show_unmerged + show_killed + show_modified) > 1;\n+\tif (show_tag || show_valid_bit) {\n+\t\ttag_cached = porcelain ? \"  \" : \"H \";\n+\t\ttag_unmerged = \"M \";\n+\t\ttag_removed = \"R \";\n+\t\ttag_modified = \"C \";\n+\t\ttag_other = \"? \";\n+\t\ttag_killed = \"K \";\n+\t\ttag_skip_worktree = \"S \";\n+\t\ttag_resolve_undo = \"U \";\n+\t}\n+\n \tif (max_prefix)\n \t\tprune_cache(max_prefix);\n \tif (with_tree) {\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252733","messageId":"1417337767-4505-15-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 14/19] list-files: sort output and remove duplicates","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:56:02Z","receivedAt":"2014-11-30T08:56:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"When you mix different file types, with ls-files you may get separate\nlisting. For example, \"ls-files -cm\" will show file \"abc\" twice: one\nas part of cached list, one of modified list. With \"ls\" (and this\npatch) they will be in a single sorted list (easier for the eye).\n\nDuplicate entries are also removed. Note that display content is\ncompared, so if you have \"-t\" on, or you color file types differently,\nyou will get duplicate textual entries. This is good imo.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-files.c | 36 ++++++++++++++++++++++++------------\n 1 file changed, 24 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex c7aaade..42c530d 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -53,6 +53,13 @@ static const char *tag_modified = \"\";\n static const char *tag_skip_worktree = \"\";\n static const char *tag_resolve_undo = \"\";\n \n+static int compare_output(const void *a_, const void *b_)\n+{\n+\tconst struct string_list_item *a = a_;\n+\tconst struct string_list_item *b = b_;\n+\treturn strcmp(a->util, b->util);\n+}\n+\n static void write_name(struct strbuf *sb, const char *name)\n {\n \t/*\n@@ -68,10 +75,12 @@ static void write_name(struct strbuf *sb, const char *name)\n \t\tquote_path_relative(name, real_prefix, sb);\n }\n \n-static void strbuf_fputs(struct strbuf *sb, FILE *fp)\n+static void strbuf_fputs(struct strbuf *sb, const char *full_name, FILE *fp)\n {\n-\tif (column_active(colopts)) {\n-\t\tstring_list_append(&output, strbuf_detach(sb, NULL));\n+\tif (column_active(colopts) || porcelain) {\n+\t\tstruct string_list_item *it;\n+\t\tit = string_list_append(&output, strbuf_detach(sb, NULL));\n+\t\tit->util = (void*)full_name;\n \t\treturn;\n \t}\n \tfwrite(sb->buf, sb->len, 1, fp);\n@@ -106,7 +115,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)\n \tstrbuf_reset(&sb);\n \tstrbuf_addstr(&sb, tag);\n \twrite_dir_entry(&sb, ent);\n-\tstrbuf_fputs(&sb, stdout);\n+\tstrbuf_fputs(&sb, ent->name, stdout);\n }\n \n static void show_other_files(struct dir_struct *dir)\n@@ -223,7 +232,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)\n \t\t\t    ce_stage(ce));\n \t}\n \twrite_ce_name(&sb, ce);\n-\tstrbuf_fputs(&sb, stdout);\n+\tstrbuf_fputs(&sb, ce->name, stdout);\n \tif (debug_mode) {\n \t\tconst struct stat_data *sd = &ce->ce_stat_data;\n \n@@ -524,6 +533,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tconst char *max_prefix;\n \tstruct dir_struct dir;\n \tstruct exclude_list *el;\n+\tstruct column_options copts;\n \tstruct string_list exclude_list = STRING_LIST_INIT_NODUP;\n \tstruct option builtin_ls_files_options[] = {\n \t\t{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,\n@@ -671,7 +681,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tif (debug_mode)\n \t\t\tdie(_(\"--column and --debug are incompatible\"));\n \t}\n-\tif (column_active(colopts))\n+\tif (column_active(colopts) || porcelain)\n \t\tline_terminator = 0;\n \n \tif (require_work_tree && !is_inside_work_tree())\n@@ -737,13 +747,15 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tif (show_resolve_undo)\n \t\tshow_ru_info();\n \n-\tif (column_active(colopts)) {\n-\t\tstruct column_options copts;\n-\t\tmemset(&copts, 0, sizeof(copts));\n-\t\tcopts.padding = 2;\n-\t\tprint_columns(&output, colopts, &copts);\n-\t\tstring_list_clear(&output, 0);\n+\tmemset(&copts, 0, sizeof(copts));\n+\tcopts.padding = 2;\n+\tif (porcelain) {\n+\t\tqsort(output.items, output.nr, sizeof(*output.items),\n+\t\t      compare_output);\n+\t\tstring_list_remove_duplicates(&output, 0);\n \t}\n+\tprint_columns(&output, colopts, &copts);\n+\tstring_list_clear(&output, 0);\n \n \tif (ps_matched) {\n \t\tint bad;\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252734","messageId":"1417337767-4505-16-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 15/19] list-files: do not show duplicate cached entries","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:56:03Z","receivedAt":"2014-11-30T08:56:03Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"With the current show_files() \"list-files -tcm\" will show\n\n  foo.c\nM foo.c\n\nThe first item is redundant. If \"foo.c\" is modified, we know it's in\nthe cache. Introduce show_files_compact to do that because ls-files is\nplumbing and scripts may already depend on current display behavior.\n\nAnother difference in show_files_compact() is it does not show\nskip-worktree (aka outside sparse checkout) entries anymore, which\nmakes sense in porcelain context.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-files.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 51 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 42c530d..fc70265 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -333,6 +333,53 @@ static void show_files(struct dir_struct *dir)\n \t}\n }\n \n+static void show_files_compact(struct dir_struct *dir)\n+{\n+\tint i;\n+\n+\t/* For cached/deleted files we don't need to even do the readdir */\n+\tif (show_others || show_killed) {\n+\t\tif (!show_others)\n+\t\t\tdir->flags |= DIR_COLLECT_KILLED_ONLY;\n+\t\tfill_directory(dir, &pathspec);\n+\t\tif (show_others)\n+\t\t\tshow_other_files(dir);\n+\t\tif (show_killed)\n+\t\t\tshow_killed_files(dir);\n+\t}\n+\tif (!(show_cached || show_stage || show_deleted || show_modified))\n+\t\treturn;\n+\tfor (i = 0; i < active_nr; i++) {\n+\t\tconst struct cache_entry *ce = active_cache[i];\n+\t\tstruct stat st;\n+\t\tint err, shown = 0;\n+\t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n+\t\t    !ce_excluded(dir, ce))\n+\t\t\tcontinue;\n+\t\tif (show_unmerged && !ce_stage(ce))\n+\t\t\tcontinue;\n+\t\tif (ce->ce_flags & CE_UPDATE)\n+\t\t\tcontinue;\n+\t\tif (ce_skip_worktree(ce))\n+\t\t\tcontinue;\n+\t\terr = lstat(ce->name, &st);\n+\t\tif (show_deleted && err) {\n+\t\t\tshow_ce_entry(tag_removed, ce);\n+\t\t\tshown = 1;\n+\t\t}\n+\t\tif (show_modified && (err || ce_modified(ce, &st, 0))) {\n+\t\t\tshow_ce_entry(tag_modified, ce);\n+\t\t\tshown = 1;\n+\t\t}\n+\t\tif (ce_stage(ce)) {\n+\t\t\tshow_ce_entry(tag_unmerged, ce);\n+\t\t\tshown = 1;\n+\t\t}\n+\t\tif (!shown && show_cached)\n+\t\t\tshow_ce_entry(tag_cached, ce);\n+\t}\n+}\n+\n /*\n  * Prune the index to only contain stuff starting with \"prefix\"\n  */\n@@ -743,7 +790,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\trefresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);\n \t\tsetup_pager();\n \t}\n-\tshow_files(&dir);\n+\tif (porcelain)\n+\t\tshow_files_compact(&dir);\n+\telse\n+\t\tshow_files(&dir);\n \tif (show_resolve_undo)\n \t\tshow_ru_info();\n \n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252735","messageId":"1417337767-4505-17-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 16/19] list-files: show directories as well as files","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:56:04Z","receivedAt":"2014-11-30T08:56:04Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The index does not store directories explicitly (except submodules) so\nwe have to figure them out from file list. The function\nshow_directories() deliberately generates duplicate directories and\nexpects the previous patch to remove duplicates.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-files.c | 44 +++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 43 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex fc70265..41efdaa 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -27,6 +27,8 @@ static int show_resolve_undo;\n static int show_modified;\n static int show_killed;\n static int show_valid_bit;\n+static int show_tag;\n+static int show_dirs;\n static int line_terminator = '\\n';\n static int debug_mode;\n static int use_color;\n@@ -333,6 +335,43 @@ static void show_files(struct dir_struct *dir)\n \t}\n }\n \n+static void show_directories(const struct cache_entry *ce)\n+{\n+\tstatic const char *last_directory;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *p = ce->name + prefix_len;\n+\tconst char *sep;\n+\n+\tif (last_directory) {\n+\t\tint len = strlen(last_directory);\n+\t\tif (!strncmp(ce->name, last_directory, len) &&\n+\t\t    ce->name[len] == '/')\n+\t\t\tp += len + 1;\n+\t}\n+\n+\twhile (*p && (sep = strchr(p, '/'))) {\n+\t\tstruct strbuf sb2 = STRBUF_INIT;\n+\t\tstrbuf_reset(&sb);\n+\t\tstrbuf_add(&sb, ce->name, sep - ce->name);\n+\t\tp = sep + 1;\n+\t\tif (!match_pathspec(&pathspec, sb.buf, sb.len,\n+\t\t\t\t    prefix_len, NULL, 1))\n+\t\t\tcontinue;\n+\t\twrite_name(&sb2, sb.buf);\n+\t\tif (want_color(use_color)) {\n+\t\t\tstruct strbuf sb3 = STRBUF_INIT;\n+\t\t\tcolor_filename(&sb3, ce->name, sb2.buf, S_IFDIR, 1);\n+\t\t\tstrbuf_release(&sb2);\n+\t\t\tsb2 = sb3;\n+\t\t}\n+\t\tif (show_tag)\n+\t\t\tstrbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached));\n+\t\tlast_directory = strbuf_detach(&sb, NULL);\n+\t\tstrbuf_fputs(&sb2, last_directory, NULL);\n+\t\tstrbuf_release(&sb2);\n+\t}\n+}\n+\n static void show_files_compact(struct dir_struct *dir)\n {\n \tint i;\n@@ -353,6 +392,8 @@ static void show_files_compact(struct dir_struct *dir)\n \t\tconst struct cache_entry *ce = active_cache[i];\n \t\tstruct stat st;\n \t\tint err, shown = 0;\n+\t\tif (show_dirs)\n+\t\t\tshow_directories(ce);\n \t\tif ((dir->flags & DIR_SHOW_IGNORED) &&\n \t\t    !ce_excluded(dir, ce))\n \t\t\tcontinue;\n@@ -575,7 +616,7 @@ static int git_ls_config(const char *var, const char *value, void *cb)\n \n int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n {\n-\tint require_work_tree = 0, show_tag = 0, i;\n+\tint require_work_tree = 0, i;\n \tint max_depth = -1;\n \tconst char *max_prefix;\n \tstruct dir_struct dir;\n@@ -696,6 +737,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\tuse_color = -1;\n \t\tmax_depth = 0;\n \t\tshow_tag = -1;\n+\t\tshow_dirs = 1;\n \t\tgit_config(git_ls_config, NULL);\n \t} else\n \t\tgit_config(git_default_config, NULL);\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252736","messageId":"1417337767-4505-18-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 17/19] list-files: add -F/--classify","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:56:05Z","receivedAt":"2014-11-30T08:56:05Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This appends an indicator after the file name if it's executable, a\ndirectory and so on, like in GNU ls. In fact append_indicator() is a\nrewrite from get_type_indicator() in coreutils.git commit\n7326d1f1a67edf21947ae98194f98c38b6e9e527.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-list-files.txt |  6 ++++++\n builtin/ls-files.c               | 31 +++++++++++++++++++++++++++++++\n 2 files changed, 37 insertions(+)\n\ndiff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt\nindex 0ef616b..22084eb 100644\n--- a/Documentation/git-list-files.txt\n+++ b/Documentation/git-list-files.txt\n@@ -51,6 +51,12 @@ OPTIONS\n \tmultiple file selections. See linkgit::git-ls-files[1] option\n \t`-t` for more information.\n \n+-F::\n+--classify::\n+\tAppend indicator (one of `*/=>@|`, which is executable,\n+\tdirectory, socket, Solaris door, symlink, or fifo\n+\trespectively) to entries.\n+\n -R::\n --recursive::\n \tEquivalent of `--max-depth=-1` (infinite recursion).\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 41efdaa..28737cb 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -29,6 +29,7 @@ static int show_killed;\n static int show_valid_bit;\n static int show_tag;\n static int show_dirs;\n+static int show_indicator;\n static int line_terminator = '\\n';\n static int debug_mode;\n static int use_color;\n@@ -77,6 +78,28 @@ static void write_name(struct strbuf *sb, const char *name)\n \t\tquote_path_relative(name, real_prefix, sb);\n }\n \n+static void append_indicator(struct strbuf *sb, mode_t mode)\n+{\n+\tchar c = 0;\n+\tif (S_ISREG(mode)) {\n+\t\tif (mode & (S_IXUSR | S_IXGRP | S_IXOTH))\n+\t\t\tc = '*';\n+\t} else if (S_ISDIR(mode))\n+\t\tc = '/';\n+\telse if (S_ISLNK(mode))\n+\t\tc = '@';\n+\telse if (S_ISFIFO(mode))\n+\t\tc = '|';\n+\telse if (S_ISSOCK(mode))\n+\t\tc = '=';\n+#ifdef S_ISDOOR\n+\telse if (S_ISDOOR(mode))\n+\t\tc = '>';\n+#endif\n+\tif (c)\n+\t\tstrbuf_addch(sb, c);\n+}\n+\n static void strbuf_fputs(struct strbuf *sb, const char *full_name, FILE *fp)\n {\n \tif (column_active(colopts) || porcelain) {\n@@ -99,6 +122,8 @@ static void write_dir_entry(struct strbuf *sb, const struct dir_entry *ent)\n \t\tcolor_filename(sb, ent->name, quoted.buf, st.st_mode, 1);\n \telse\n \t\tstrbuf_addbuf(sb, &quoted);\n+\tif (show_indicator && st.st_mode)\n+\t\tappend_indicator(sb, st.st_mode);\n \tstrbuf_addch(sb, line_terminator);\n \tstrbuf_release(&quoted);\n }\n@@ -189,6 +214,8 @@ static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)\n \t\tcolor_filename(sb, ce->name, quoted.buf, ce->ce_mode, 1);\n \telse\n \t\tstrbuf_addbuf(sb, &quoted);\n+\tif (show_indicator)\n+\t\tappend_indicator(sb, ce->ce_mode);\n \tstrbuf_addch(sb, line_terminator);\n \tstrbuf_release(&quoted);\n }\n@@ -366,6 +393,8 @@ static void show_directories(const struct cache_entry *ce)\n \t\t}\n \t\tif (show_tag)\n \t\t\tstrbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached));\n+\t\tif (show_indicator)\n+\t\t\tappend_indicator(&sb2, S_IFDIR);\n \t\tlast_directory = strbuf_detach(&sb, NULL);\n \t\tstrbuf_fputs(&sb2, last_directory, NULL);\n \t\tstrbuf_release(&sb2);\n@@ -701,6 +730,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tDIR_SHOW_IGNORED),\n \t\tOPT_BOOL('u', \"unmerged\", &show_unmerged,\n \t\t\tN_(\"show unmerged files\")),\n+\t\tOPT_BOOL('F', \"classify\", &show_indicator,\n+\t\t\t N_(\"append indicator (one of */=>@|) to entries\")),\n \t\tOPT__COLOR(&use_color, N_(\"show color\")),\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"show files in columns\")),\n \t\tOPT_SET_INT('1', NULL, &colopts,\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252737","messageId":"1417337767-4505-19-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 18/19] list-files -F: show submodules with the new indicator '&'","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:56:06Z","receivedAt":"2014-11-30T08:56:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/git-list-files.txt | 4 ++--\n builtin/ls-files.c               | 2 ++\n 2 files changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt\nindex 22084eb..c57129b 100644\n--- a/Documentation/git-list-files.txt\n+++ b/Documentation/git-list-files.txt\n@@ -53,8 +53,8 @@ OPTIONS\n \n -F::\n --classify::\n-\tAppend indicator (one of `*/=>@|`, which is executable,\n-\tdirectory, socket, Solaris door, symlink, or fifo\n+\tAppend indicator (one of `*/=>@|&`, which is executable,\n+\tdirectory, socket, Solaris door, symlink, fifo, or submodule\n \trespectively) to entries.\n \n -R::\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 28737cb..5b5a068 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -92,6 +92,8 @@ static void append_indicator(struct strbuf *sb, mode_t mode)\n \t\tc = '|';\n \telse if (S_ISSOCK(mode))\n \t\tc = '=';\n+\telse if (S_ISGITLINK(mode))\n+\t\tc = '&';\n #ifdef S_ISDOOR\n \telse if (S_ISDOOR(mode))\n \t\tc = '>';\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252738","messageId":"1417337767-4505-20-git-send-email-pclouds@gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 19/19] list-files: -M aka diff-cached","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-11-30T08:56:07Z","receivedAt":"2014-11-30T08:56:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/ls-files.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++---\n 1 file changed, 54 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex 5b5a068..08ae206 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -16,6 +16,9 @@\n #include \"pathspec.h\"\n #include \"color.h\"\n #include \"column.h\"\n+#include \"diff.h\"\n+#include \"diffcore.h\"\n+#include \"revision.h\"\n \n static int abbrev;\n static int show_deleted;\n@@ -25,6 +28,7 @@ static int show_stage;\n static int show_unmerged;\n static int show_resolve_undo;\n static int show_modified;\n+static int show_diff_cached;\n static int show_killed;\n static int show_valid_bit;\n static int show_tag;\n@@ -53,6 +57,7 @@ static const char *tag_removed = \"\";\n static const char *tag_other = \"\";\n static const char *tag_killed = \"\";\n static const char *tag_modified = \"\";\n+static const char *tag_diff_cached = \"\";\n static const char *tag_skip_worktree = \"\";\n static const char *tag_resolve_undo = \"\";\n \n@@ -343,7 +348,7 @@ static void show_files(struct dir_struct *dir)\n \t\t\t\t(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);\n \t\t}\n \t}\n-\tif (show_deleted || show_modified) {\n+\tif (show_deleted || show_modified || show_diff_cached) {\n \t\tfor (i = 0; i < active_nr; i++) {\n \t\t\tconst struct cache_entry *ce = active_cache[i];\n \t\t\tstruct stat st;\n@@ -358,7 +363,15 @@ static void show_files(struct dir_struct *dir)\n \t\t\terr = lstat(ce->name, &st);\n \t\t\tif (show_deleted && err)\n \t\t\t\tshow_ce_entry(tag_removed, ce);\n-\t\t\tif (show_modified && ce_modified(ce, &st, 0))\n+\t\t\tif (show_diff_cached && (ce->ce_flags & CE_MATCHED)) {\n+\t\t\t\tshow_ce_entry(tag_diff_cached, ce);\n+\t\t\t\t/*\n+\t\t\t\t * if we don't clear, it'll confuse write_ce_name()\n+\t\t\t\t * when show_ce_entry(tag_modified, ce) is called\n+\t\t\t\t */\n+\t\t\t\tactive_cache[i]->ce_flags &= ~CE_MATCHED;\n+\t\t\t}\n+\t\t\tif (show_modified && (err || ce_modified(ce, &st, 0)))\n \t\t\t\tshow_ce_entry(tag_modified, ce);\n \t\t}\n \t}\n@@ -452,6 +465,38 @@ static void show_files_compact(struct dir_struct *dir)\n \t}\n }\n \n+static void mark_diff_cached(struct diff_queue_struct *q,\n+\t\t\t     struct diff_options *options,\n+\t\t\t     void *data)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < q->nr; i++) {\n+\t\tstruct diff_filepair *p = q->queue[i];\n+\t\tint pos = cache_name_pos(p->two->path, strlen(p->two->path));\n+\t\tif (pos < 0)\n+\t\t\tcontinue;\n+\t\tactive_cache[pos]->ce_flags |= CE_MATCHED;\n+\t}\n+}\n+\n+static void diff_cached(struct pathspec *pathspec)\n+{\n+\tstruct rev_info rev;\n+\tconst char *argv[] = { \"ls-files\", \"HEAD\", NULL };\n+\n+\tinit_revisions(&rev, NULL);\n+\tsetup_revisions(2, argv, &rev, NULL);\n+\n+\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n+\trev.diffopt.format_callback = mark_diff_cached;\n+\trev.diffopt.detect_rename = 1;\n+\trev.diffopt.rename_limit = 200;\n+\trev.diffopt.break_opt = 0;\n+\tcopy_pathspec(&rev.prune_data, pathspec);\n+\trun_diff_index(&rev, 1);\n+}\n+\n /*\n  * Prune the index to only contain stuff starting with \"prefix\"\n  */\n@@ -721,6 +766,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\t\tN_(\"show cached files that are deleted on working directory\")),\n \t\tOPT_BOOL('m', \"modified\", &show_modified,\n \t\t\tN_(\"show cached files that have modification on working directory\")),\n+\t\tOPT_BOOL('M', \"modified\", &show_diff_cached,\n+\t\t\tN_(\"show modified files in the cache\")),\n \t\tOPT_BOOL('o', \"others\", &show_others,\n \t\t\tN_(\"show untracked files\")),\n \t\tOPT_SET_INT('R', \"recursive\", &max_depth,\n@@ -833,11 +880,12 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \n \t/* With no flags, we default to showing the cached files */\n \tif (!(show_stage || show_deleted || show_others || show_unmerged ||\n-\t      show_killed || show_modified || show_resolve_undo))\n+\t      show_killed || show_modified || show_resolve_undo || show_diff_cached))\n \t\tshow_cached = 1;\n \n \tif (show_tag == -1)\n \t\tshow_tag = (show_cached + show_deleted + show_others +\n+\t\t\t    show_diff_cached +\n \t\t\t    show_unmerged + show_killed + show_modified) > 1;\n \tif (show_tag || show_valid_bit) {\n \t\ttag_cached = porcelain ? \"  \" : \"H \";\n@@ -845,6 +893,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\ttag_removed = \"R \";\n \t\ttag_modified = \"C \";\n \t\ttag_other = \"? \";\n+\t\ttag_diff_cached = \"X \";\n \t\ttag_killed = \"K \";\n \t\ttag_skip_worktree = \"S \";\n \t\ttag_resolve_undo = \"U \";\n@@ -865,6 +914,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \t\trefresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);\n \t\tsetup_pager();\n \t}\n+\tif (show_diff_cached)\n+\t\tdiff_cached(&pathspec);\n \tif (porcelain)\n \t\tshow_files_compact(&dir);\n \telse\n-- \n2.2.0.60.gb7b3c64\n"},{"id":"252805","messageId":"xmqqbnnnp291.fsf@gitster.dls.corp.google.com","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 00/19] Add git-list-files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-12-01T20:02:34Z","receivedAt":"2014-12-01T20:02:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Does this contain a lot of borrowed code or something?  The style\nviolation in the patches are unusually high, even compared with your\nother series.\n\nI've tried to fix it up and will push out the result on 'pu' if\nthings work OK, but this does not even have tests, so it is unlikely\nthat it would break anything but itself ;-)\n"},{"id":"252821","messageId":"CAPig+cQCFkGUqLjvGPLON8D3577ADyBJ2hmQ9girbO5Q1Tn6Eg@mail.gmail.com","threadId":"38075","inReplyTo":"1417337767-4505-10-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2014-12-02T02:50:54Z","receivedAt":"2014-12-02T02:50:54Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sunday, November 30, 2014, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>\n> This is more user friendly version of ls-files:\n>\n> * it's automatically colored and columnized\n> * it refreshes the index like all porcelain commands\n> * it defaults to non-recursive behavior like ls\n> * :(glob) is on by default so '*.c' means a.c but not a/b.c, use\n>   '**/*.c' for that.\n> * auto pager\n>\n> The name 'ls' is not taken. It is left for the user to make an alias\n> with better default options.\n\nI understand that your original version was named git-ls and that you\nrenamed it to git-list-files in order to leave 'ls' available so users\ncan create an 'ls' alias specifying their own default options. Would\nit make sense, however, to restore the name to git-ls and allow users\nto set default options via a config variable instead? Doing so would\nmake the short-and-sweet git-ls command work for all users\nout-of-the-box, which might be well appreciated by Unix users.\n\nMore below.\n\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt\n> new file mode 100644\n> index 0000000..3039e1e\n> --- /dev/null\n> +++ b/Documentation/git-list-files.txt\n> @@ -0,0 +1,80 @@\n> +git-list-files(1)\n> +===============\n> +\n> +NAME\n> +----\n> +git-list-files - List files\n> +\n> +SYNOPSIS\n> +--------\n> +[verse]\n> +'git list-files [options] [<pathspec>...]\n> +\n> +DESCRIPTION\n> +-----------\n> +List files (by default in current working directory) that are in the\n> +index. Depending on the chosen options, maybe only modified files in\n> +working tree are shown, or untracked files...\n> +\n> +OPTIONS\n> +-------\n> +-c::\n> +--cached::\n> +       Show cached files (default)\n\nI realize that this mirrors what is in git-ls-files.txt, but:\n\ns/$/./\n\n> +-d::\n> +--deleted::\n> +       Show cached files that are deleted on working directory\n\ns/$/./\n\n> +-m::\n> +--modified::\n> +       Show cached files that have modification on working directory\n\ns/$/./\n\n> +-o::\n> +--others::\n> +       Show untracked files (and only unignored ones unless -i is\n\ns/-i/`-i`/\n\n> +       specified)\n\ns/$/./\n\n> +-i::\n> +--ignored::\n> +       Show only ignored files. When showing files in the index,\n> +       print only those matched by an exclude pattern. When showing\n> +       \"other\" files, show only those matched by an exclude pattern.\n> +\n> +-u::\n> +--unmerged::\n> +       Show unmerged files\n\ns/$/./\n\n> +--color[=<when>]::\n> +--no-color::\n> +       Color file names. The value must be `always`, `never`, or\n> +       `auto`. `--no-color` is equivalent to\n> +       `--color=never`. `--color` is equivalent to\n> +       `--color=auto`. See configuration variable `color.list-files`\n> +       for the default settings.\n> +\n> +--column[=<options>]::\n> +--no-column::\n> +       Display files in columns. See configuration variable column.ui\n\ns/column.ui/`column.ui`/\n\n> +       for option syntax. `--column` and `--no-column` without options\n> +       are equivalent to 'always' and 'never' respectively.\n> +\n> +--max-depth=<depth>::\n> +       For each <pathspec> given on command line, descend at most <depth>\n> +       levels of directories. A negative value means no limit.\n> +       This option is ignored if <pathspec> contains active wildcards.\n> +       In other words if \"a*\" matches a directory named \"a*\",\n> +       \"*\" is matched literally so --max-depth is still effective.\n> +       The default is `--max-depth=0`.\n> +\n> +<pathspec>::\n> +       Files to show. :(glob) magic is enabled and recursion disabled\n> +       by default.\n> +\n> +SEE ALSO\n> +--------\n> +linkgit:git-ls-files[1]\n> +\n> +GIT\n> +---\n> +Part of the linkgit:git[1] suite\n"},{"id":"252834","messageId":"20141202054226.GA1948@peff.net","threadId":"38075","inReplyTo":"1417337767-4505-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 00/19] Add git-list-files","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-12-02T05:42:26Z","receivedAt":"2014-12-02T05:42:26Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Nov 30, 2014 at 03:55:48PM +0700, Nguyễn Thái Ngọc Duy wrote:\n\n> This is something else that's been sitting in my tree for a while now.\n> It adds \"git list-files\", intended to be aliased as \"ls\" with your\n> favourite display options.\n\nWhen I read the subject, I thought \"why isn't this called git-ls?\". Then\nwhen I read this paragraph, I thought \"if the point is for everybody to\nmake their own ls alias, why do we need list-files at all, instead of\njust adding options to ls-files\"?\n\nI'll let you decide which (if any) you'd like to answer. :)\n\nMy guesses:\n\n  1. If it were \"git-ls\", it would stomp on existing aliases people have\n     constructed.\n\n  2. If it is a wrapper around ls-files, then the options may be\n     constrained; ls-files already squats on useful options like \"-d\"\n     (which, if we are matching traditional ls, is more like our \"-t\").\n\nI somewhat feel like (1) can be mitigated by the fact that your command\nis what people were probably trying to approximate with their aliases,\nand that as porcelain it should be very configurable (so they should be\nable to accomplish the same things as their aliases). But I dunno. I do\nnot have an \"ls\" alias, so I am biased. :)\n\nAs a side note, I wonder if it would be sensible to whitelist some\ncommands as porcelain, and allow aliases to override them (either\nentirely, or just to add-in some options).\n\n-Peff\n"},{"id":"252849","messageId":"CACsJy8Do1PancG847KYnF-SZ=qq-=ubCG--QohYxm=+kUcMNNg@mail.gmail.com","threadId":"38075","inReplyTo":"xmqqbnnnp291.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 00/19] Add git-list-files","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2014-12-02T11:33:13Z","receivedAt":"2014-12-02T11:33:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Dec 2, 2014 at 3:02 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Does this contain a lot of borrowed code or something?  The style\n> violation in the patches are unusually high, even compared with your\n> other series.\n\nThe first one is from coreutils, but I reformatted (and trimmed) to\nfit Git. I recall you had a script to spot style violation, right?\nWhere can I find the script? Else I'll reread CodingGuidlines again\nand go through the patch.\n\n\n> I've tried to fix it up and will push out the result on 'pu' if\n> things work OK, but this does not even have tests, so it is unlikely\n> that it would break anything but itself ;-)\n\nHeh.. ;) Next version will come with tests. Thanks for the reminder.\n-- \nDuy\n"},{"id":"252850","messageId":"CACsJy8DBkGVhaJnCTs9_E+g6FYYr4V-6S=XB5wrGBFPjHnEu1A@mail.gmail.com","threadId":"38075","inReplyTo":"20141202054226.GA1948@peff.net","subject":"Re: [PATCH 00/19] Add git-list-files","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2014-12-02T11:45:52Z","receivedAt":"2014-12-02T11:45:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Dec 2, 2014 at 12:42 PM, Jeff King <peff@peff.net> wrote:\n> On Sun, Nov 30, 2014 at 03:55:48PM +0700, Nguyễn Thái Ngọc Duy wrote:\n>\n>> This is something else that's been sitting in my tree for a while now.\n>> It adds \"git list-files\", intended to be aliased as \"ls\" with your\n>> favourite display options.\n>\n> When I read the subject, I thought \"why isn't this called git-ls?\". Then\n> when I read this paragraph, I thought \"if the point is for everybody to\n> make their own ls alias, why do we need list-files at all, instead of\n> just adding options to ls-files\"?\n>\n> I'll let you decide which (if any) you'd like to answer. :)\n>\n> My guesses:\n>\n>   1. If it were \"git-ls\", it would stomp on existing aliases people have\n>      constructed.\n\nYes, Matthew Moy (I think) at least had this git-ls alias and he did\ncomplain. Also we could not agree on what should be the good defaults\nfor git-ls if it's built in.\n\n>   2. If it is a wrapper around ls-files, then the options may be\n>      constrained; ls-files already squats on useful options like \"-d\"\n>      (which, if we are matching traditional ls, is more like our \"-t\").\n\nAlso right. I want to keep option names close to GNU ls.\n\n> As a side note, I wonder if it would be sensible to whitelist some\n> commands as porcelain, and allow aliases to override them (either\n> entirely, or just to add-in some options).\n\nAgreed. Maybe not all porcelain (some like git-branch almost functions\nlike plumbing).\n\nWe also need away to stop alias (e.g. in scripts). In scripts I can\nspecify full path to a command to make sure I won't hit an alias. I\nguess we can't do the same here. The closet to \"full path\" is git-cmd\nform, as opposed to \"git cmd\" form) but I think we don't want to bring\nback git-cmd. Maybe just a \"git --no-alias cmd\" and GIT_NO_ALIAS..\n\nAnd if  people now can override standard commands, I think it makes\nsense to ship a default alias set (with lower priority than\nuser-defined aliases). After all people need to check twice if the\ncommand they type really means what they think it is..\n-- \nDuy\n"},{"id":"252853","messageId":"CACsJy8BhDvVkG_NCqkoLCiERM1+nOfWT2p09JPvvU1_XGchhuw@mail.gmail.com","threadId":"38075","inReplyTo":"CAPig+cQCFkGUqLjvGPLON8D3577ADyBJ2hmQ9girbO5Q1Tn6Eg@mail.gmail.com","subject":"Re: [PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2014-12-02T12:06:48Z","receivedAt":"2014-12-02T12:06:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Dec 2, 2014 at 9:50 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sunday, November 30, 2014, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n>>\n>> This is more user friendly version of ls-files:\n>>\n>> * it's automatically colored and columnized\n>> * it refreshes the index like all porcelain commands\n>> * it defaults to non-recursive behavior like ls\n>> * :(glob) is on by default so '*.c' means a.c but not a/b.c, use\n>>   '**/*.c' for that.\n>> * auto pager\n>>\n>> The name 'ls' is not taken. It is left for the user to make an alias\n>> with better default options.\n>\n> I understand that your original version was named git-ls and that you\n> renamed it to git-list-files in order to leave 'ls' available so users\n> can create an 'ls' alias specifying their own default options. Would\n> it make sense, however, to restore the name to git-ls and allow users\n> to set default options via a config variable instead? Doing so would\n> make the short-and-sweet git-ls command work for all users\n> out-of-the-box, which might be well appreciated by Unix users.\n\nOr I just make git-ls the first alias shipped by default.. I don't\nreally like using config var to define default options. Sounds like a\nworkaround to our alias. Jeff raised it elsewhere in this thread:\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/260423/focus=260538\n-- \nDuy\n"},{"id":"252861","messageId":"547DB325.6030500@drmicha.warpmail.net","threadId":"38075","inReplyTo":"20141202054226.GA1948@peff.net","subject":"Re: [PATCH 00/19] Add git-list-files","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2014-12-02T12:40:05Z","receivedAt":"2014-12-02T12:40:05Z","isPatch":true,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Jeff King schrieb am 02.12.2014 um 06:42:\n> On Sun, Nov 30, 2014 at 03:55:48PM +0700, Nguyễn Thái Ngọc Duy wrote:\n> \n>> This is something else that's been sitting in my tree for a while now.\n>> It adds \"git list-files\", intended to be aliased as \"ls\" with your\n>> favourite display options.\n> \n> When I read the subject, I thought \"why isn't this called git-ls?\". Then\n> when I read this paragraph, I thought \"if the point is for everybody to\n> make their own ls alias, why do we need list-files at all, instead of\n> just adding options to ls-files\"?\n> \n> I'll let you decide which (if any) you'd like to answer. :)\n> \n> My guesses:\n> \n>   1. If it were \"git-ls\", it would stomp on existing aliases people have\n>      constructed.\n> \n>   2. If it is a wrapper around ls-files, then the options may be\n>      constrained; ls-files already squats on useful options like \"-d\"\n>      (which, if we are matching traditional ls, is more like our \"-t\").\n> \n> I somewhat feel like (1) can be mitigated by the fact that your command\n> is what people were probably trying to approximate with their aliases,\n> and that as porcelain it should be very configurable (so they should be\n> able to accomplish the same things as their aliases). But I dunno. I do\n> not have an \"ls\" alias, so I am biased. :)\n> \n> As a side note, I wonder if it would be sensible to whitelist some\n> commands as porcelain, and allow aliases to override them (either\n> entirely, or just to add-in some options).\n> \n> -Peff\n> \n\nI'd like to second all that (\"+1\", \"like\").\n\nUser friendly listing of files in the git repo is dearly needed, and\nfollowing names and default behaviour of mv/cp/ls is a way to follow the\nprinciple of least surprise.\n\nWhile \"ls\" might be an alias for many, I'm sure \"stage\" was for quite a\nfew people, too. We should be able to take any new name for new command,\nregardless of aliases people may be using.\n\nAllowing to alias at least porcelain commands, at least to the extent of\nadding default options, is something we've talked about before and which\nwould have prevented us from the increasing bloat by the default\nchanging config knobs. \"git -c ...\" somehow took us down the other road.\n\nI'm still dreaming of a git future where either \"git foo --bar=baz\" is\nequivalent to \"git -c foo.bar=baz foo\" (i.e. unify the naming), or we\nare simply able to alias \"foo\" to \"foo --bar=baz\" if that is what we\nlike as default (i.e. get rid of many of the special config knobs).\n\nRight now, we have two \"sets of options\" with often differing names.\n\nAlso, we could ship a few commonly used aliases (such as co=checkout,\nci=commit, st=status) which could be overriden easily.\n\nMichael\n"},{"id":"252888","messageId":"20141202201837.GC23461@peff.net","threadId":"38075","inReplyTo":"CACsJy8DBkGVhaJnCTs9_E+g6FYYr4V-6S=XB5wrGBFPjHnEu1A@mail.gmail.com","subject":"Re: [PATCH 00/19] Add git-list-files","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-12-02T20:18:38Z","receivedAt":"2014-12-02T20:18:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Dec 02, 2014 at 06:45:52PM +0700, Duy Nguyen wrote:\n\n> > As a side note, I wonder if it would be sensible to whitelist some\n> > commands as porcelain, and allow aliases to override them (either\n> > entirely, or just to add-in some options).\n> \n> Agreed. Maybe not all porcelain (some like git-branch almost functions\n> like plumbing).\n\nYeah, many things straddle the plumbing/porcelain line (e.g., \"commit\"\nis porcelain, but it's basically the only sane way for scripts to make a\ncommit, so many use it). So I'd pick just a few things that should be\nsafe to override.\n\n> We also need away to stop alias (e.g. in scripts).\n\nDo we? I think the point of allowing this only for porcelain is that you\ndo not have to care about scripts. That is, a script running \"git ls\"\nwould get whatever the user's preferences are for \"ls\" output. A script\nparsing the output of \"ls\" deserves whatever crap it gets.\n\n> In scripts I can specify full path to a command to make sure I won't\n> hit an alias. I guess we can't do the same here. The closet to \"full\n> path\" is git-cmd form, as opposed to \"git cmd\" form) but I think we\n> don't want to bring back git-cmd. Maybe just a \"git --no-alias cmd\"\n> and GIT_NO_ALIAS..\n\nYeah, I think \"--no-alias\"/GIT_NO_ALIAS would work. But the problem is\none of compatibility. Scripts are not written to specify no-alias, so\nyou cannot just turn on the override-commands-with-aliases feature\nimmediately (and likewise, scripts have little incentive to bother\nannotating their calls if it the override feature is not enabled).\n\n-Peff\n"}]}