git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v2 00/25] list-files redesign
@ 2015-04-06 13:52 Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 01/25] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
                   ` (25 more replies)
  0 siblings, 26 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

The UI part is the same (or nearly the same) with the last round. The
internal data structure is reorignized to avoid abusing string_list.
Tests and documentation are added back.

Nguyễn Thái Ngọc Duy (25):
  ls_colors.c: add $LS_COLORS parsing code
  ls_colors.c: parse color.ls.* from config file
  ls_colors.c: add a function to color a file name
  ls_colors.c: highlight submodules like directories
  list-files: command skeleton
  list-files: show paths relative to cwd
  list-files: add tag to each entry, filter duplicate tags
  list-files: add --[no-]column, -C and -1
  list-files: add --max-depth, -R and default to --max-depth=0
  list-files: show directories as well as files
  list-files: add --color
  list-files: add -F/--classify
  list-files: new indicator '&' for submodules when -F is used
  list-files: add --cached and --others
  list-files: add --ignored
  list-files: add --unmerged
  list-files: add file modification options -[admADM]
  list-files: delete redundant cached entries
  list-files: make alias 'ls' default to 'list-files'
  list-files: preload index
  list-files: reduce match_pathspec calls in matched()
  list-files: only do diff that is actually useful
  pathspec: move getenv() code out of prefix_pathspec()
  list-files: make :(glob) pathspec default
  list-files: documentation

 .gitignore                             |   1 +
 Documentation/config.txt               |  12 +
 Documentation/git-list-files.txt (new) | 115 +++++++
 Makefile                               |   2 +
 builtin.h                              |   1 +
 builtin/list-files.c (new)             | 581 +++++++++++++++++++++++++++++++++
 color.h                                |  10 +
 config.c                               |   8 +
 git.c                                  |   1 +
 ls_colors.c (new)                      | 498 ++++++++++++++++++++++++++++
 pathspec.c                             |  59 ++--
 pathspec.h                             |   1 +
 t/t7013-list-files.sh (new +x)         | 335 +++++++++++++++++++
 wt-status.c                            |  16 +-
 wt-status.h                            |   3 +
 15 files changed, 1612 insertions(+), 31 deletions(-)
 create mode 100644 Documentation/git-list-files.txt
 create mode 100644 builtin/list-files.c
 create mode 100644 ls_colors.c
 create mode 100755 t/t7013-list-files.sh

-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 01/25] ls_colors.c: add $LS_COLORS parsing code
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 02/25] ls_colors.c: parse color.ls.* from config file Nguyễn Thái Ngọc Duy
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy, Junio C Hamano

Reusing color settings from $LS_COLORS could give a native look and
feel on file coloring.

This code is basically from coreutils.git [1], rewritten to fit Git.

As this is from GNU ls, the environment variable CLICOLOR is not
tested. It is to be decided later whether we should ignore $LS_COLORS
if $CLICOLOR is not set on Mac or FreeBSD.

[1] commit 7326d1f1a67edf21947ae98194f98c38b6e9e527 file
    src/ls.c. This is the last GPL-2 commit before coreutils turns to
    GPL-3.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Makefile          |   1 +
 color.h           |   8 ++
 ls_colors.c (new) | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 407 insertions(+)
 create mode 100644 ls_colors.c

diff --git a/Makefile b/Makefile
index 827006b..459121d 100644
--- a/Makefile
+++ b/Makefile
@@ -703,6 +703,7 @@ LIB_OBJS += list-objects.o
 LIB_OBJS += ll-merge.o
 LIB_OBJS += lockfile.o
 LIB_OBJS += log-tree.o
+LIB_OBJS += ls_colors.o
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
 LIB_OBJS += merge.o
diff --git a/color.h b/color.h
index f5beab1..3eaa5bd 100644
--- a/color.h
+++ b/color.h
@@ -45,6 +45,12 @@ struct strbuf;
 #define GIT_COLOR_BG_MAGENTA	"\033[45m"
 #define GIT_COLOR_BG_CYAN	"\033[46m"
 
+#define GIT_COLOR_WHITE_ON_RED    "\033[37;41m"
+#define GIT_COLOR_WHITE_ON_BLUE   "\033[37;44m"
+#define GIT_COLOR_BLACK_ON_YELLOW "\033[30;43m"
+#define GIT_COLOR_BLUE_ON_GREEN   "\033[34;42m"
+#define GIT_COLOR_BLACK_ON_GREEN  "\033[30;42m"
+
 /* A special value meaning "no color selected" */
 #define GIT_COLOR_NIL "NIL"
 
@@ -87,4 +93,6 @@ void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);
 
 int color_is_nil(const char *color);
 
+void parse_ls_color(void);
+
 #endif /* COLOR_H */
diff --git a/ls_colors.c b/ls_colors.c
new file mode 100644
index 0000000..e743315
--- /dev/null
+++ b/ls_colors.c
@@ -0,0 +1,398 @@
+#include "cache.h"
+#include "color.h"
+
+enum color_ls {
+	LS_LC,			/* left, unused */
+	LS_RC,			/* right, unused */
+	LS_EC,			/* end color, unused */
+	LS_RS,			/* reset */
+	LS_NO,			/* normal */
+	LS_FL,			/* file, default */
+	LS_DI,			/* directory */
+	LS_LN,			/* symlink */
+
+	LS_PI,			/* pipe */
+	LS_SO,			/* socket */
+	LS_BD,			/* block device */
+	LS_CD,			/* char device */
+	LS_MI,			/* missing file */
+	LS_OR,			/* orphaned symlink */
+	LS_EX,			/* executable */
+	LS_DO,			/* Solaris door */
+
+	LS_SU,			/* setuid */
+	LS_SG,			/* setgid */
+	LS_ST,			/* sticky */
+	LS_OW,			/* other-writable */
+	LS_TW,			/* ow with sticky */
+	LS_CA,			/* cap */
+	LS_MH,			/* multi hardlink */
+	LS_CL,			/* clear end of line */
+
+	MAX_LS
+};
+
+static char ls_colors[MAX_LS][COLOR_MAXLEN] = {
+	"",
+	"",
+	"",
+	GIT_COLOR_RESET,
+	GIT_COLOR_NORMAL,
+	GIT_COLOR_NORMAL,
+	GIT_COLOR_BOLD_BLUE,
+	GIT_COLOR_BOLD_CYAN,
+
+	GIT_COLOR_YELLOW,
+	GIT_COLOR_BOLD_MAGENTA,
+	GIT_COLOR_BOLD_YELLOW,
+	GIT_COLOR_BOLD_YELLOW,
+	GIT_COLOR_NORMAL,
+	GIT_COLOR_NORMAL,
+	GIT_COLOR_BOLD_GREEN,
+	GIT_COLOR_BOLD_MAGENTA,
+
+	GIT_COLOR_WHITE_ON_RED,
+	GIT_COLOR_BLACK_ON_YELLOW,
+	GIT_COLOR_WHITE_ON_BLUE,
+	GIT_COLOR_BLUE_ON_GREEN,
+	GIT_COLOR_BLACK_ON_GREEN,
+	"",
+	"",
+	""
+};
+
+static const char *const indicator_name[] = {
+	"lc", "rc", "ec", "rs", "no", "fi", "di", "ln",
+	"pi", "so", "bd", "cd", "mi", "or", "ex", "do",
+	"su", "sg", "st", "ow", "tw", "ca", "mh", "cl",
+	NULL
+};
+
+struct bin_str {
+	size_t len;			/* Number of bytes */
+	const char *string;		/* Pointer to the same */
+};
+
+struct color_ext_type {
+	struct bin_str ext;		/* The extension we're looking for */
+	struct bin_str seq;		/* The sequence to output when we do */
+	struct color_ext_type *next;	/* Next in list */
+};
+
+static struct color_ext_type *color_ext_list;
+
+/*
+ * When true, in a color listing, color each symlink name according to the
+ * type of file it points to.  Otherwise, color them according to the `ln'
+ * directive in LS_COLORS.  Dangling (orphan) symlinks are treated specially,
+ * regardless.  This is set when `ln=target' appears in LS_COLORS.
+ */
+static int color_symlink_as_referent;
+
+/*
+ * Parse a string as part of the LS_COLORS variable; this may involve
+ * decoding all kinds of escape characters.  If equals_end is set an
+ * unescaped equal sign ends the string, otherwise only a : or \0
+ * does.  Set *OUTPUT_COUNT to the number of bytes output.  Return
+ * true if successful.
+ *
+ * The resulting string is *not* null-terminated, but may contain
+ * embedded nulls.
+ *
+ * Note that both dest and src are char **; on return they point to
+ * the first free byte after the array and the character that ended
+ * the input string, respectively.
+ */
+static int get_funky_string(char **dest, const char **src, int equals_end,
+			    size_t *output_count)
+{
+	char num;			/* For numerical codes */
+	size_t count;			/* Something to count with */
+	enum {
+		ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX,
+		ST_CARET, ST_END, ST_ERROR
+	} state;
+	const char *p;
+	char *q;
+
+	p = *src;			/* We don't want to double-indirect */
+	q = *dest;			/* the whole darn time.  */
+
+	count = 0;			/* No characters counted in yet.  */
+	num = 0;
+
+	state = ST_GND;		/* Start in ground state.  */
+	while (state < ST_END) {
+		switch (state) {
+		case ST_GND:		/* Ground state (no escapes) */
+			switch (*p) {
+			case ':':
+			case '\0':
+				state = ST_END;	/* End of string */
+				break;
+			case '\\':
+				state = ST_BACKSLASH; /* Backslash scape sequence */
+				++p;
+				break;
+			case '^':
+				state = ST_CARET; /* Caret escape */
+				++p;
+				break;
+			case '=':
+				if (equals_end) {
+					state = ST_END; /* End */
+					break;
+				}
+				/* else fall through */
+			default:
+				*(q++) = *(p++);
+				++count;
+				break;
+			}
+			break;
+
+		case ST_BACKSLASH:	/* Backslash escaped character */
+			switch (*p) {
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+				state = ST_OCTAL;	/* Octal sequence */
+				num = *p - '0';
+				break;
+			case 'x':
+			case 'X':
+				state = ST_HEX;	/* Hex sequence */
+				num = 0;
+				break;
+			case 'a':		/* Bell */
+				num = '\a';
+				break;
+			case 'b':		/* Backspace */
+				num = '\b';
+				break;
+			case 'e':		/* Escape */
+				num = 27;
+				break;
+			case 'f':		/* Form feed */
+				num = '\f';
+				break;
+			case 'n':		/* Newline */
+				num = '\n';
+				break;
+			case 'r':		/* Carriage return */
+				num = '\r';
+				break;
+			case 't':		/* Tab */
+				num = '\t';
+				break;
+			case 'v':		/* Vtab */
+				num = '\v';
+				break;
+			case '?':		/* Delete */
+				num = 127;
+				break;
+			case '_':		/* Space */
+				num = ' ';
+				break;
+			case '\0':		/* End of string */
+				state = ST_ERROR;	/* Error! */
+				break;
+			default:		/* Escaped character like \ ^ : = */
+				num = *p;
+				break;
+			}
+			if (state == ST_BACKSLASH) {
+				*(q++) = num;
+				++count;
+				state = ST_GND;
+			}
+			++p;
+			break;
+
+		case ST_OCTAL:		/* Octal sequence */
+			if (*p < '0' || *p > '7') {
+				*(q++) = num;
+				++count;
+				state = ST_GND;
+			} else
+				num = (num << 3) + (*(p++) - '0');
+			break;
+
+		case ST_HEX:		/* Hex sequence */
+			switch (*p) {
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				num = (num << 4) + (*(p++) - '0');
+				break;
+			case 'a':
+			case 'b':
+			case 'c':
+			case 'd':
+			case 'e':
+			case 'f':
+				num = (num << 4) + (*(p++) - 'a') + 10;
+				break;
+			case 'A':
+			case 'B':
+			case 'C':
+			case 'D':
+			case 'E':
+			case 'F':
+				num = (num << 4) + (*(p++) - 'A') + 10;
+				break;
+			default:
+				*(q++) = num;
+				++count;
+				state = ST_GND;
+				break;
+			}
+			break;
+
+		case ST_CARET:		/* Caret escape */
+			state = ST_GND;	/* Should be the next state... */
+			if (*p >= '@' && *p <= '~') {
+				*(q++) = *(p++) & 037;
+				++count;
+			} else if (*p == '?') {
+				*(q++) = 127;
+				++count;
+			} else
+				state = ST_ERROR;
+			break;
+
+		default:
+			abort();
+		}
+	}
+
+	*dest = q;
+	*src = p;
+	*output_count = count;
+
+	return state != ST_ERROR;
+}
+
+void parse_ls_color(void)
+{
+	const char *p;			/* Pointer to character being parsed */
+	char *buf;			/* color_buf buffer pointer */
+	int state;			/* State of parser */
+	int ind_no;			/* Indicator number */
+	char label[3];			/* Indicator label */
+	struct color_ext_type *ext;	/* Extension we are working on */
+	static char *color_buf;
+	char *start;
+	size_t len;
+
+	if ((p = getenv("LS_COLORS")) == NULL || *p == '\0')
+		return;
+
+	ext = NULL;
+	strcpy(label, "??");
+
+	/*
+	 * This is an overly conservative estimate, but any possible
+	 * LS_COLORS string will *not* generate a color_buf longer
+	 * than itself, so it is a safe way of allocating a buffer in
+	 * advance.
+	 */
+	buf = color_buf = xstrdup(p);
+
+	state = 1;
+	while (state > 0) {
+		switch (state) {
+		case 1:		/* First label character */
+			switch (*p) {
+			case ':':
+				++p;
+				break;
+
+			case '*':
+				/*
+				 * Allocate new extension block and add to head of
+				 * linked list (this way a later definition will
+				 * override an earlier one, which can be useful for
+				 * having terminal-specific defs override global).
+				 */
+
+				ext = xmalloc(sizeof(*ext));
+				ext->next = color_ext_list;
+				color_ext_list = ext;
+
+				++p;
+				ext->ext.string = buf;
+
+				state = (get_funky_string(&buf, &p, 1, &ext->ext.len)
+					 ? 4 : -1);
+				break;
+
+			case '\0':
+				state = 0;	/* Done! */
+				break;
+
+			default:	/* Assume it is file type label */
+				label[0] = *(p++);
+				state = 2;
+				break;
+			}
+			break;
+
+		case 2:		/* Second label character */
+			if (*p) {
+				label[1] = *(p++);
+				state = 3;
+			} else
+				state = -1;	/* Error */
+			break;
+
+		case 3:		/* Equal sign after indicator label */
+			state = -1;	/* Assume failure...  */
+			if (*(p++) != '=')
+				break;
+			for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) {
+				if (!strcmp(label, indicator_name[ind_no])) {
+					start = buf;
+					if (get_funky_string(&buf, &p, 0, &len))
+						state = 1;
+					else
+						state = -1;
+					break;
+				}
+			}
+			if (state == -1)
+				error(_("unrecognized prefix: %s"), label);
+			else if (ind_no == LS_LN && len == 6 &&
+				 starts_with(start, "target"))
+				color_symlink_as_referent = 1;
+			else
+				sprintf(ls_colors[ind_no], "\033[%.*sm",
+				       (int)len, start);
+			break;
+
+		case 4:		/* Equal sign after *.ext */
+			if (*(p++) == '=') {
+				ext->seq.string = buf;
+				state = (get_funky_string(&buf, &p, 0, &ext->seq.len)
+					 ? 1 : -1);
+			} else
+				state = -1;
+			break;
+		}
+	}
+
+	if (!strcmp(ls_colors[LS_LN], "target"))
+		color_symlink_as_referent = 1;
+}
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 02/25] ls_colors.c: parse color.ls.* from config file
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 01/25] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 03/25] ls_colors.c: add a function to color a file name Nguyễn Thái Ngọc Duy
                   ` (23 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy, Junio C Hamano

This is the second (and preferred) source for color information. This
will override $LS_COLORS.

Helped-by: Michael Blume <blume.mike@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/config.txt | 11 +++++++++++
 ls_colors.c              | 30 +++++++++++++++++++++++++++++-
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 9220725..2090866 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -940,6 +940,17 @@ color.status.<slot>::
 	to red). The values of these variables may be specified as in
 	color.branch.<slot>.
 
+color.ls.<slot>::
+	Use customized color for file name colorization. If not set
+	and the environment variable LS_COLORS is set, color settings
+	from $LS_COLORS are used. `<slot>` can be `normal`, `file`,
+	`directory`, `symlink`, `fifo`, `socket`, `block`, `char`,
+	`missing`, `orphan`, `executable`, `door`, `setuid`, `setgid`,
+	`sticky`, `otherwritable`, `stickyotherwritable`, `cap`,
+	`multihardlink`. The values of these variables may be
+	specified as in color.branch.<slot>.
+
+
 color.ui::
 	This variable determines the default value for variables such
 	as `color.diff` and `color.grep` that control the use of color
diff --git a/ls_colors.c b/ls_colors.c
index e743315..2dc2d39 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -68,6 +68,14 @@ static const char *const indicator_name[] = {
 	NULL
 };
 
+static const char * const config_name[] = {
+	"", "", "", "", "normal", "file", "directory", "symlink",
+	"fifo", "socket", "block", "char", "missing", "orphan", "executable",
+	"door", "setuid", "setgid", "sticky", "otherwritable",
+	"stickyotherwritable", "cap", "multihardlink", "",
+	NULL
+};
+
 struct bin_str {
 	size_t len;			/* Number of bytes */
 	const char *string;		/* Pointer to the same */
@@ -285,6 +293,23 @@ static int get_funky_string(char **dest, const char **src, int equals_end,
 	return state != ST_ERROR;
 }
 
+static int ls_colors_config(const char *var, const char *value, void *cb)
+{
+	int slot;
+	if (!starts_with(var, "color.ls."))
+		return 0;
+	var += 9;
+	for (slot = 0; config_name[slot]; slot++)
+		if (!strcasecmp(var, config_name[slot]))
+			break;
+	if (!config_name[slot])
+		return 0;
+	if (!value)
+		return config_error_nonbool(var);
+	color_parse(value, ls_colors[slot]);
+	return 0;
+}
+
 void parse_ls_color(void)
 {
 	const char *p;			/* Pointer to character being parsed */
@@ -297,8 +322,10 @@ void parse_ls_color(void)
 	char *start;
 	size_t len;
 
-	if ((p = getenv("LS_COLORS")) == NULL || *p == '\0')
+	if ((p = getenv("LS_COLORS")) == NULL || *p == '\0') {
+		git_config(ls_colors_config, NULL);
 		return;
+	}
 
 	ext = NULL;
 	strcpy(label, "??");
@@ -395,4 +422,5 @@ void parse_ls_color(void)
 
 	if (!strcmp(ls_colors[LS_LN], "target"))
 		color_symlink_as_referent = 1;
+	git_config(ls_colors_config, NULL);
 }
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 03/25] ls_colors.c: add a function to color a file name
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 01/25] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 02/25] ls_colors.c: parse color.ls.* from config file Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 04/25] ls_colors.c: highlight submodules like directories Nguyễn Thái Ngọc Duy
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy, Junio C Hamano

The new function is based on print_color_indicator() from commit
7326d1f1a67edf21947ae98194f98c38b6e9e527 in coreutils.git.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 color.h     |  2 ++
 ls_colors.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/color.h b/color.h
index 3eaa5bd..b6904a3 100644
--- a/color.h
+++ b/color.h
@@ -94,5 +94,7 @@ void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);
 int color_is_nil(const char *color);
 
 void parse_ls_color(void);
+void color_filename(struct strbuf *sb, const char *name,
+		    const char *display_name, mode_t mode, int linkok);
 
 #endif /* COLOR_H */
diff --git a/ls_colors.c b/ls_colors.c
index 2dc2d39..f84ef0f 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -424,3 +424,69 @@ void parse_ls_color(void)
 		color_symlink_as_referent = 1;
 	git_config(ls_colors_config, NULL);
 }
+
+void color_filename(struct strbuf *sb, const char *name,
+		    const char *display_name, mode_t mode, int linkok)
+{
+	int type;
+	struct color_ext_type *ext;	/* Color extension */
+
+	if (S_ISREG(mode)) {
+		type = LS_FL;
+		if ((mode & S_ISUID) != 0)
+			type = LS_SU;
+		else if ((mode & S_ISGID) != 0)
+			type = LS_SG;
+		else if ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
+			type = LS_EX;
+	} else if (S_ISDIR(mode)) {
+		if ((mode & S_ISVTX) && (mode & S_IWOTH))
+			type = LS_TW;
+		else if ((mode & S_IWOTH) != 0)
+			type = LS_OW;
+		else if ((mode & S_ISVTX) != 0)
+			type = LS_ST;
+		else
+			type = LS_DI;
+	} else if (S_ISLNK(mode))
+		type = (!linkok && *ls_colors[LS_OR]) ? LS_OR : LS_LN;
+	else if (S_ISFIFO(mode))
+		type = LS_PI;
+	else if (S_ISSOCK(mode))
+		type = LS_SO;
+	else if (S_ISBLK(mode))
+		type = LS_BD;
+	else if (S_ISCHR(mode))
+		type = LS_CD;
+#ifdef S_ISDOOR
+	else if (S_ISDOOR(mode))
+		type = LS_DO;
+#endif
+	else
+		/* Classify a file of some other type as C_ORPHAN.  */
+		type = LS_OR;
+
+	/* Check the file's suffix only if still classified as C_FILE.  */
+	ext = NULL;
+	if (type == LS_FL) {
+		/* Test if NAME has a recognized suffix.  */
+		size_t len = strlen(name);
+		const char *p = name + len;		/* Pointer to final \0.  */
+		for (ext = color_ext_list; ext != NULL; ext = ext->next) {
+			if (ext->ext.len <= len &&
+			    !strncmp(p - ext->ext.len, ext->ext.string, ext->ext.len))
+				break;
+		}
+	}
+
+	if (display_name)
+		name = display_name;
+	if (ext)
+		strbuf_addf(sb, "\033[%.*sm%s%s",
+			    (int)ext->seq.len, ext->seq.string,
+			    name, GIT_COLOR_RESET);
+	else if (*ls_colors[type])
+		strbuf_addf(sb, "%s%s%s", ls_colors[type], name, GIT_COLOR_RESET);
+	else
+		strbuf_addstr(sb, name);
+}
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 04/25] ls_colors.c: highlight submodules like directories
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (2 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 03/25] ls_colors.c: add a function to color a file name Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 05/25] list-files: command skeleton Nguyễn Thái Ngọc Duy
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy, Junio C Hamano

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 Documentation/config.txt | 3 ++-
 ls_colors.c              | 8 +++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 2090866..2290c47 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -944,7 +944,8 @@ color.ls.<slot>::
 	Use customized color for file name colorization. If not set
 	and the environment variable LS_COLORS is set, color settings
 	from $LS_COLORS are used. `<slot>` can be `normal`, `file`,
-	`directory`, `symlink`, `fifo`, `socket`, `block`, `char`,
+	`directory`, `submodule`,
+	`symlink`, `fifo`, `socket`, `block`, `char`,
 	`missing`, `orphan`, `executable`, `door`, `setuid`, `setgid`,
 	`sticky`, `otherwritable`, `stickyotherwritable`, `cap`,
 	`multihardlink`. The values of these variables may be
diff --git a/ls_colors.c b/ls_colors.c
index f84ef0f..011a8b9 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -29,6 +29,8 @@ enum color_ls {
 	LS_MH,			/* multi hardlink */
 	LS_CL,			/* clear end of line */
 
+	LS_SUBMODULE,
+
 	MAX_LS
 };
 
@@ -58,7 +60,8 @@ static char ls_colors[MAX_LS][COLOR_MAXLEN] = {
 	GIT_COLOR_BLACK_ON_GREEN,
 	"",
 	"",
-	""
+	"",
+	GIT_COLOR_BOLD_BLUE
 };
 
 static const char *const indicator_name[] = {
@@ -73,6 +76,7 @@ static const char * const config_name[] = {
 	"fifo", "socket", "block", "char", "missing", "orphan", "executable",
 	"door", "setuid", "setgid", "sticky", "otherwritable",
 	"stickyotherwritable", "cap", "multihardlink", "",
+	"submodule",
 	NULL
 };
 
@@ -450,6 +454,8 @@ void color_filename(struct strbuf *sb, const char *name,
 			type = LS_DI;
 	} else if (S_ISLNK(mode))
 		type = (!linkok && *ls_colors[LS_OR]) ? LS_OR : LS_LN;
+	else if (S_ISGITLINK(mode))
+		type = LS_SUBMODULE;
 	else if (S_ISFIFO(mode))
 		type = LS_PI;
 	else if (S_ISSOCK(mode))
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 05/25] list-files: command skeleton
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (3 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 04/25] ls_colors.c: highlight submodules like directories Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 06/25] list-files: show paths relative to cwd Nguyễn Thái Ngọc Duy
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

list-files is supposed to be the user friendly version of ls-files, or
an alternative to git-status. Nothing fancy in this patch yet.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 .gitignore                     |   1 +
 Makefile                       |   1 +
 builtin.h                      |   1 +
 builtin/list-files.c (new)     | 107 +++++++++++++++++++++++++++++++++++++++++
 git.c                          |   1 +
 t/t7013-list-files.sh (new +x) |  35 ++++++++++++++
 6 files changed, 146 insertions(+)
 create mode 100644 builtin/list-files.c
 create mode 100755 t/t7013-list-files.sh

diff --git a/.gitignore b/.gitignore
index a052419..0534225 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,7 @@
 /git-interpret-trailers
 /git-instaweb
 /git-log
+/git-list-files
 /git-ls-files
 /git-ls-remote
 /git-ls-tree
diff --git a/Makefile b/Makefile
index 459121d..17f52b2 100644
--- a/Makefile
+++ b/Makefile
@@ -832,6 +832,7 @@ BUILTIN_OBJS += builtin/index-pack.o
 BUILTIN_OBJS += builtin/init-db.o
 BUILTIN_OBJS += builtin/interpret-trailers.o
 BUILTIN_OBJS += builtin/log.o
+BUILTIN_OBJS += builtin/list-files.o
 BUILTIN_OBJS += builtin/ls-files.o
 BUILTIN_OBJS += builtin/ls-remote.o
 BUILTIN_OBJS += builtin/ls-tree.o
diff --git a/builtin.h b/builtin.h
index b87df70..afc29e7 100644
--- a/builtin.h
+++ b/builtin.h
@@ -76,6 +76,7 @@ extern int cmd_init_db(int argc, const char **argv, const char *prefix);
 extern int cmd_interpret_trailers(int argc, const char **argv, const char *prefix);
 extern int cmd_log(int argc, const char **argv, const char *prefix);
 extern int cmd_log_reflog(int argc, const char **argv, const char *prefix);
+extern int cmd_list_files(int argc, const char **argv, const char *prefix);
 extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
 extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_ls_remote(int argc, const char **argv, const char *prefix);
diff --git a/builtin/list-files.c b/builtin/list-files.c
new file mode 100644
index 0000000..8b74d79
--- /dev/null
+++ b/builtin/list-files.c
@@ -0,0 +1,107 @@
+#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+#include "pathspec.h"
+#include "dir.h"
+
+enum item_type {
+	FROM_INDEX
+};
+
+struct item {
+	enum item_type type;
+	const char *path;
+	const struct cache_entry *ce;
+};
+
+struct item_list {
+	struct item *items;
+	int nr, alloc;
+};
+
+static struct pathspec pathspec;
+static const char *prefix;
+static int prefix_length;
+
+static const char * const ls_usage[] = {
+	N_("git list-files [options] [<pathspec>...]"),
+	NULL
+};
+
+struct option ls_options[] = {
+	OPT_END()
+};
+
+static void populate_cached_entries(struct item_list *result,
+				    const struct index_state *istate)
+{
+	int i;
+
+	for (i = 0; i < istate->cache_nr; i++) {
+		const struct cache_entry *ce = istate->cache[i];
+		struct item *item;
+
+		if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
+				    0, NULL,
+				    S_ISDIR(ce->ce_mode) ||
+				    S_ISGITLINK(ce->ce_mode)))
+			continue;
+
+		ALLOC_GROW(result->items, result->nr + 1, result->alloc);
+		item = result->items + result->nr++;
+		item->type = FROM_INDEX;
+		item->path = ce->name;
+		item->ce = ce;
+	}
+}
+
+static void display(const struct item_list *result)
+{
+	int i;
+
+	for (i = 0; i < result->nr; i++) {
+		const struct item *item = result->items + i;
+
+		printf("%s\n", item->path);
+	}
+}
+
+static int ls_config(const char *var, const char *value, void *cb)
+{
+	return git_default_config(var, value, cb);
+}
+
+int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
+{
+	struct item_list result;
+
+	if (argc == 2 && !strcmp(argv[1], "-h"))
+		usage_with_options(ls_usage, ls_options);
+
+	prefix = cmd_prefix;
+	if (prefix)
+		prefix_length = strlen(prefix);
+
+	if (read_cache() < 0)
+		die(_("index file corrupt"));
+
+	git_config(ls_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, ls_options, ls_usage, 0);
+
+	parse_pathspec(&pathspec, 0,
+		       PATHSPEC_PREFER_CWD |
+		       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
+		       cmd_prefix, argv);
+	pathspec.max_depth = 0;
+	pathspec.recursive = 1;
+
+	refresh_index(&the_index, REFRESH_QUIET | REFRESH_UNMERGED,
+		      &pathspec, NULL, NULL);
+
+	memset(&result, 0, sizeof(result));
+	populate_cached_entries(&result, &the_index);
+	display(&result);
+	/* free-ing result seems unnecessary */
+	return 0;
+}
diff --git a/git.c b/git.c
index 18fbf79..ae7fe77 100644
--- a/git.c
+++ b/git.c
@@ -418,6 +418,7 @@ static struct cmd_struct commands[] = {
 	{ "init", cmd_init_db, NO_SETUP },
 	{ "init-db", cmd_init_db, NO_SETUP },
 	{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP },
+	{ "list-files", cmd_list_files, RUN_SETUP | USE_PAGER | NEED_WORK_TREE },
 	{ "log", cmd_log, RUN_SETUP },
 	{ "ls-files", cmd_ls_files, RUN_SETUP },
 	{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
new file mode 100755
index 0000000..f43776e
--- /dev/null
+++ b/t/t7013-list-files.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+test_description='list-files'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	mkdir sa sa/sb sc &&
+	touch a b c sa/a sa/sb/b sc/c &&
+	git add .
+'
+
+test_expect_success 'list-files from index' '
+	git list-files >actual &&
+	cat >expect <<-\EOF &&
+	a
+	b
+	c
+	sa/a
+	sa/sb/b
+	sc/c
+	EOF
+	test_cmp expect actual
+'
+
+test_expect_success 'list-files selectively from index' '
+	git list-files "*a" >actual &&
+	cat >expect <<-\EOF &&
+	a
+	sa/a
+	EOF
+	test_cmp expect actual
+'
+
+test_done
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 06/25] list-files: show paths relative to cwd
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (4 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 05/25] list-files: command skeleton Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 07/25] list-files: add tag to each entry, filter duplicate tags Nguyễn Thái Ngọc Duy
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  |  9 ++++++++-
 t/t7013-list-files.sh | 24 ++++++++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 8b74d79..51ff19d 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -3,6 +3,7 @@
 #include "parse-options.h"
 #include "pathspec.h"
 #include "dir.h"
+#include "quote.h"
 
 enum item_type {
 	FROM_INDEX
@@ -57,13 +58,19 @@ static void populate_cached_entries(struct item_list *result,
 
 static void display(const struct item_list *result)
 {
+	struct strbuf quoted = STRBUF_INIT;
 	int i;
 
+	if (!prefix_length)
+		prefix = NULL;
+
 	for (i = 0; i < result->nr; i++) {
 		const struct item *item = result->items + i;
 
-		printf("%s\n", item->path);
+		quote_path_relative(item->path, prefix, &quoted);
+		printf("%s\n", quoted.buf);
 	}
+	strbuf_release(&quoted);
 }
 
 static int ls_config(const char *var, const char *value, void *cb)
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index f43776e..a5e555d 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -32,4 +32,28 @@ test_expect_success 'list-files selectively from index' '
 	test_cmp expect actual
 '
 
+test_expect_success 'list-files from subdir ' '
+	(
+	cd sa &&
+	git list-files >actual &&
+	cat >expect <<-\EOF &&
+	a
+	sb/b
+	EOF
+	test_cmp expect actual
+	)
+'
+
+test_expect_success 'list-files from subdir (2)' '
+	(
+	cd sa &&
+	git list-files ../a sb >actual &&
+	cat >expect <<-\EOF &&
+	../a
+	sb/b
+	EOF
+	test_cmp expect actual
+	)
+'
+
 test_done
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 07/25] list-files: add tag to each entry, filter duplicate tags
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (5 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 06/25] list-files: show paths relative to cwd Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 21:32   ` Eric Sunshine
  2015-04-06 13:52 ` [PATCH 08/25] list-files: add --[no-]column, -C and -1 Nguyễn Thái Ngọc Duy
                   ` (18 subsequent siblings)
  25 siblings, 1 reply; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

All entries have a two-letter tag. If all entries have the same tags,
tags are not displayed.

The outcome before and after this patch is the same. But it will be
useful in future when there are more than one type of entry.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 51ff19d..ec9ca17 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -12,17 +12,20 @@ enum item_type {
 struct item {
 	enum item_type type;
 	const char *path;
+	char tag[2];
 	const struct cache_entry *ce;
 };
 
 struct item_list {
 	struct item *items;
 	int nr, alloc;
+	int tag_pos, tag_len;
 };
 
 static struct pathspec pathspec;
 static const char *prefix;
 static int prefix_length;
+static int show_tag = -1;
 
 static const char * const ls_usage[] = {
 	N_("git list-files [options] [<pathspec>...]"),
@@ -30,6 +33,7 @@ static const char * const ls_usage[] = {
 };
 
 struct option ls_options[] = {
+	OPT_BOOL(0, "tag", &show_tag, N_("show tags")),
 	OPT_END()
 };
 
@@ -52,10 +56,61 @@ static void populate_cached_entries(struct item_list *result,
 		item = result->items + result->nr++;
 		item->type = FROM_INDEX;
 		item->path = ce->name;
+		item->tag[0] = ' ';
+		item->tag[1] = ' ';
 		item->ce = ce;
 	}
 }
 
+static void cleanup_tags(struct item_list *result)
+{
+	int i, same_1 = 1, same_2 = 1;
+
+	if (!show_tag) {
+		result->tag_pos = 0;
+		result->tag_len = 0;
+		return;
+	}
+	if (show_tag > 0) {
+		result->tag_pos = 0;
+		result->tag_len = 2;
+		return;
+	}
+
+	for (i = 1; i < result->nr && (same_1 || same_2); i++) {
+		const char *s0 = result->items[i - 1].tag;
+		const char *s1 = result->items[i].tag;
+
+		same_1 = same_1 && s0[0] == s1[0];
+		same_2 = same_2 && s0[1] == s1[1];
+	}
+
+	if (same_1 && same_2) {
+		result->tag_pos = 0;
+		result->tag_len = 0;
+	} else if (same_1) {
+		result->tag_pos = 1;
+		result->tag_len = 1;
+	} else if (same_2) {
+		result->tag_pos = 0;
+		result->tag_len = 1;
+	} else {
+		result->tag_pos = 0;
+		result->tag_len = 2;
+	}
+}
+
+/* this is similar to quote_path_relative() except it does not clear sb */
+static void quote_item(struct strbuf *out, const struct item *item)
+{
+	static struct strbuf sb = STRBUF_INIT;
+	const char *rel;
+
+	strbuf_reset(&sb);
+	rel = relative_path(item->path, prefix, &sb);
+	quote_c_style(rel, out, NULL, 0);
+}
+
 static void display(const struct item_list *result)
 {
 	struct strbuf quoted = STRBUF_INIT;
@@ -67,7 +122,13 @@ static void display(const struct item_list *result)
 	for (i = 0; i < result->nr; i++) {
 		const struct item *item = result->items + i;
 
-		quote_path_relative(item->path, prefix, &quoted);
+		strbuf_reset(&quoted);
+		if (result->tag_len) {
+			strbuf_add(&quoted, item->tag + result->tag_pos,
+				   result->tag_len);
+			strbuf_addch(&quoted, ' ');
+		}
+		quote_item(&quoted, item);
 		printf("%s\n", quoted.buf);
 	}
 	strbuf_release(&quoted);
@@ -108,6 +169,7 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 
 	memset(&result, 0, sizeof(result));
 	populate_cached_entries(&result, &the_index);
+	cleanup_tags(&result);
 	display(&result);
 	/* free-ing result seems unnecessary */
 	return 0;
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 08/25] list-files: add --[no-]column, -C and -1
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (6 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 07/25] list-files: add tag to each entry, filter duplicate tags Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 09/25] list-files: add --max-depth, -R and default to --max-depth=0 Nguyễn Thái Ngọc Duy
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 22 +++++++++++++++++++++-
 t/t7013-list-files.sh | 27 +++++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index ec9ca17..8913770 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -4,6 +4,7 @@
 #include "pathspec.h"
 #include "dir.h"
 #include "quote.h"
+#include "column.h"
 
 enum item_type {
 	FROM_INDEX
@@ -26,6 +27,7 @@ static struct pathspec pathspec;
 static const char *prefix;
 static int prefix_length;
 static int show_tag = -1;
+static unsigned int colopts;
 
 static const char * const ls_usage[] = {
 	N_("git list-files [options] [<pathspec>...]"),
@@ -34,6 +36,9 @@ static const char * const ls_usage[] = {
 
 struct option ls_options[] = {
 	OPT_BOOL(0, "tag", &show_tag, N_("show tags")),
+	OPT_COLUMN('C', "column", &colopts, N_("show files in columns")),
+	OPT_SET_INT('1', NULL, &colopts,
+		    N_("shortcut for --no-column"), COL_PARSEOPT),
 	OPT_END()
 };
 
@@ -114,6 +119,7 @@ static void quote_item(struct strbuf *out, const struct item *item)
 static void display(const struct item_list *result)
 {
 	struct strbuf quoted = STRBUF_INIT;
+	struct string_list s = STRING_LIST_INIT_DUP;
 	int i;
 
 	if (!prefix_length)
@@ -129,13 +135,26 @@ static void display(const struct item_list *result)
 			strbuf_addch(&quoted, ' ');
 		}
 		quote_item(&quoted, item);
-		printf("%s\n", quoted.buf);
+		if (column_active(colopts))
+			string_list_append(&s, quoted.buf);
+		else
+			printf("%s\n", quoted.buf);
+	}
+
+	if (column_active(colopts)) {
+		struct column_options copts;
+		memset(&copts, 0, sizeof(copts));
+		copts.padding = 2;
+		print_columns(&s, colopts, &copts);
+		string_list_clear(&s, 0);
 	}
 	strbuf_release(&quoted);
 }
 
 static int ls_config(const char *var, const char *value, void *cb)
 {
+	if (starts_with(var, "column."))
+		return git_column_config(var, value, "listfiles", &colopts);
 	return git_default_config(var, value, cb);
 }
 
@@ -163,6 +182,7 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 		       cmd_prefix, argv);
 	pathspec.max_depth = 0;
 	pathspec.recursive = 1;
+	finalize_colopts(&colopts, -1);
 
 	refresh_index(&the_index, REFRESH_QUIET | REFRESH_UNMERGED,
 		      &pathspec, NULL, NULL);
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index a5e555d..b43245c 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -23,6 +23,33 @@ test_expect_success 'list-files from index' '
 	test_cmp expect actual
 '
 
+test_expect_success 'column output' '
+	COLUMNS=20 git list-files --column=always >actual &&
+	cat >expected <<-\EOF &&
+	a        sa/a
+	b        sa/sb/b
+	c        sc/c
+	EOF
+	test_cmp expected actual &&
+	COLUMNS=20 git -c column.listfiles=always list-files >actual &&
+	cat >expected <<-\EOF &&
+	a        sa/a
+	b        sa/sb/b
+	c        sc/c
+	EOF
+	test_cmp expected actual &&
+	COLUMNS=20 git -c column.listfiles=always list-files -1 >actual &&
+	cat >expected <<-\EOF &&
+	a
+	b
+	c
+	sa/a
+	sa/sb/b
+	sc/c
+	EOF
+	test_cmp expected actual
+'
+
 test_expect_success 'list-files selectively from index' '
 	git list-files "*a" >actual &&
 	cat >expect <<-\EOF &&
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 09/25] list-files: add --max-depth, -R and default to --max-depth=0
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (7 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 08/25] list-files: add --[no-]column, -C and -1 Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 10/25] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  |  9 ++++++++-
 t/t7013-list-files.sh | 40 ++++++++++++++++++++++++++++++++--------
 2 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 8913770..4599cf0 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -28,6 +28,7 @@ static const char *prefix;
 static int prefix_length;
 static int show_tag = -1;
 static unsigned int colopts;
+static int max_depth;
 
 static const char * const ls_usage[] = {
 	N_("git list-files [options] [<pathspec>...]"),
@@ -39,6 +40,11 @@ struct option ls_options[] = {
 	OPT_COLUMN('C', "column", &colopts, N_("show files in columns")),
 	OPT_SET_INT('1', NULL, &colopts,
 		    N_("shortcut for --no-column"), COL_PARSEOPT),
+	{ OPTION_INTEGER, 0, "max-depth", &max_depth, N_("depth"),
+	  N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
+	  NULL, 1 },
+	OPT_SET_INT('R', "recursive", &max_depth,
+		    N_("shortcut for --max-depth=-1"), -1),
 	OPT_END()
 };
 
@@ -178,9 +184,10 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 
 	parse_pathspec(&pathspec, 0,
 		       PATHSPEC_PREFER_CWD |
+		       (max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0) |
 		       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
 		       cmd_prefix, argv);
-	pathspec.max_depth = 0;
+	pathspec.max_depth = max_depth;
 	pathspec.recursive = 1;
 	finalize_colopts(&colopts, -1);
 
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index b43245c..89930c7 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -10,8 +10,8 @@ test_expect_success 'setup' '
 	git add .
 '
 
-test_expect_success 'list-files from index' '
-	git list-files >actual &&
+test_expect_success 'list-files -R from index' '
+	git list-files -R >actual &&
 	cat >expect <<-\EOF &&
 	a
 	b
@@ -23,22 +23,34 @@ test_expect_success 'list-files from index' '
 	test_cmp expect actual
 '
 
+test_expect_success 'list-files from index' '
+	git list-files --max-depth=0 >actual &&
+	cat >expect <<-\EOF &&
+	a
+	b
+	c
+	EOF
+	test_cmp expect actual &&
+	git list-files >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'column output' '
-	COLUMNS=20 git list-files --column=always >actual &&
+	COLUMNS=20 git list-files -R --column=always >actual &&
 	cat >expected <<-\EOF &&
 	a        sa/a
 	b        sa/sb/b
 	c        sc/c
 	EOF
 	test_cmp expected actual &&
-	COLUMNS=20 git -c column.listfiles=always list-files >actual &&
+	COLUMNS=20 git -c column.listfiles=always list-files -R >actual &&
 	cat >expected <<-\EOF &&
 	a        sa/a
 	b        sa/sb/b
 	c        sc/c
 	EOF
 	test_cmp expected actual &&
-	COLUMNS=20 git -c column.listfiles=always list-files -1 >actual &&
+	COLUMNS=20 git -c column.listfiles=always list-files -1R >actual &&
 	cat >expected <<-\EOF &&
 	a
 	b
@@ -51,7 +63,7 @@ test_expect_success 'column output' '
 '
 
 test_expect_success 'list-files selectively from index' '
-	git list-files "*a" >actual &&
+	git list-files -R "*a" >actual &&
 	cat >expect <<-\EOF &&
 	a
 	sa/a
@@ -59,10 +71,22 @@ test_expect_success 'list-files selectively from index' '
 	test_cmp expect actual
 '
 
+test_expect_success '--max-depth' '
+	git list-files --max-depth=1 >actual &&
+	cat >expected <<-\EOF &&
+	a
+	b
+	c
+	sa/a
+	sc/c
+	EOF
+	test_cmp expected actual
+'
+
 test_expect_success 'list-files from subdir ' '
 	(
 	cd sa &&
-	git list-files >actual &&
+	git list-files -R >actual &&
 	cat >expect <<-\EOF &&
 	a
 	sb/b
@@ -74,7 +98,7 @@ test_expect_success 'list-files from subdir ' '
 test_expect_success 'list-files from subdir (2)' '
 	(
 	cd sa &&
-	git list-files ../a sb >actual &&
+	git list-files -R ../a sb >actual &&
 	cat >expect <<-\EOF &&
 	../a
 	sb/b
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 10/25] list-files: show directories as well as files
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (8 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 09/25] list-files: add --max-depth, -R and default to --max-depth=0 Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 11/25] list-files: add --color Nguyễn Thái Ngọc Duy
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

The index does not store directories explicitly (except submodules) so
we have to figure them out from file list when output lis depth-limited.

The function add_directory() can generate duplicate entries, which is
cleaned up before displaying.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 94 +++++++++++++++++++++++++++++++++++++++++++++++----
 t/t7013-list-files.sh |  3 ++
 2 files changed, 91 insertions(+), 6 deletions(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 4599cf0..a60ab98 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -7,7 +7,8 @@
 #include "column.h"
 
 enum item_type {
-	FROM_INDEX
+	FROM_INDEX,
+	IS_DIR
 };
 
 struct item {
@@ -24,11 +25,13 @@ struct item_list {
 };
 
 static struct pathspec pathspec;
+static struct pathspec recursive_pathspec;
 static const char *prefix;
 static int prefix_length;
 static int show_tag = -1;
 static unsigned int colopts;
 static int max_depth;
+static int show_dirs;
 
 static const char * const ls_usage[] = {
 	N_("git list-files [options] [<pathspec>...]"),
@@ -48,6 +51,81 @@ struct option ls_options[] = {
 	OPT_END()
 };
 
+static int compare_item(const void *a_, const void *b_)
+{
+	const struct item *a = a_;
+	const struct item *b = b_;
+	return strcmp(a->path, b->path);
+}
+
+static void free_item(struct item *item)
+{
+	switch (item->type) {
+	case IS_DIR:
+		free((char*)item->path);
+		break;
+	default:
+		break;
+	}
+}
+
+static void remove_duplicates(struct item_list *list)
+{
+	int src, dst;
+
+	if (list->nr <= 1)
+		return;
+	qsort(list->items, list->nr, sizeof(*list->items), compare_item);
+	for (src = dst = 1; src < list->nr; src++) {
+		if (!compare_item(list->items + dst - 1, list->items + src))
+			free_item(list->items + src);
+		else
+			list->items[dst++] = list->items[src];
+	}
+	list->nr = dst;
+}
+
+static int add_directory(struct item_list *result,
+			 const char *name)
+{
+	struct strbuf sb = STRBUF_INIT;
+	struct item *item;
+	const char *p;
+
+	strbuf_addstr(&sb, name);
+	while (sb.len && (p = strrchr(sb.buf, '/')) != NULL) {
+		strbuf_setlen(&sb, p - sb.buf);
+		if (!match_pathspec(&pathspec, sb.buf, sb.len, 0, NULL, 1))
+			continue;
+
+		ALLOC_GROW(result->items, result->nr + 1, result->alloc);
+		item = result->items + result->nr++;
+		item->type = IS_DIR;
+		item->path = strbuf_detach(&sb, NULL);
+		item->tag[0] = ' ';
+		item->tag[1] = ' ';
+		return 1;
+	}
+	strbuf_release(&sb);
+	return 0;
+}
+
+static int matched(struct item_list *result, const char *name, int mode)
+{
+	int len = strlen(name);
+
+	if (!match_pathspec(&recursive_pathspec, name, len, 0, NULL,
+			    S_ISDIR(mode) || S_ISGITLINK(mode)))
+		return 0;
+
+	if (show_dirs && strchr(name, '/') &&
+	    !match_pathspec(&pathspec, name, len, 0, NULL, 1) &&
+	    add_directory(result, name))
+		return 0;
+
+	return 1;
+}
+
 static void populate_cached_entries(struct item_list *result,
 				    const struct index_state *istate)
 {
@@ -57,10 +135,7 @@ static void populate_cached_entries(struct item_list *result,
 		const struct cache_entry *ce = istate->cache[i];
 		struct item *item;
 
-		if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
-				    0, NULL,
-				    S_ISDIR(ce->ce_mode) ||
-				    S_ISGITLINK(ce->ce_mode)))
+		if (!matched(result, ce->name, ce->ce_mode))
 			continue;
 
 		ALLOC_GROW(result->items, result->nr + 1, result->alloc);
@@ -71,6 +146,10 @@ static void populate_cached_entries(struct item_list *result,
 		item->tag[1] = ' ';
 		item->ce = ce;
 	}
+
+	if (!show_dirs)
+		return;
+	remove_duplicates(result);
 }
 
 static void cleanup_tags(struct item_list *result)
@@ -189,10 +268,13 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 		       cmd_prefix, argv);
 	pathspec.max_depth = max_depth;
 	pathspec.recursive = 1;
+	show_dirs = max_depth >= 0;
+	copy_pathspec(&recursive_pathspec, &pathspec);
+	recursive_pathspec.max_depth = -1;
 	finalize_colopts(&colopts, -1);
 
 	refresh_index(&the_index, REFRESH_QUIET | REFRESH_UNMERGED,
-		      &pathspec, NULL, NULL);
+		      &recursive_pathspec, NULL, NULL);
 
 	memset(&result, 0, sizeof(result));
 	populate_cached_entries(&result, &the_index);
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index 89930c7..a4916d8 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -29,6 +29,8 @@ test_expect_success 'list-files from index' '
 	a
 	b
 	c
+	sa
+	sc
 	EOF
 	test_cmp expect actual &&
 	git list-files >actual &&
@@ -78,6 +80,7 @@ test_expect_success '--max-depth' '
 	b
 	c
 	sa/a
+	sa/sb
 	sc/c
 	EOF
 	test_cmp expected actual
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 11/25] list-files: add --color
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (9 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 10/25] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 21:33   ` Eric Sunshine
  2015-04-06 13:52 ` [PATCH 12/25] list-files: add -F/--classify Nguyễn Thái Ngọc Duy
                   ` (14 subsequent siblings)
  25 siblings, 1 reply; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 30 +++++++++++++++++++++++++++++-
 t/t7013-list-files.sh | 44 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index a60ab98..02a088d 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -5,6 +5,7 @@
 #include "dir.h"
 #include "quote.h"
 #include "column.h"
+#include "color.h"
 
 enum item_type {
 	FROM_INDEX,
@@ -32,6 +33,7 @@ static int show_tag = -1;
 static unsigned int colopts;
 static int max_depth;
 static int show_dirs;
+static int use_color = -1;
 
 static const char * const ls_usage[] = {
 	N_("git list-files [options] [<pathspec>...]"),
@@ -48,6 +50,7 @@ struct option ls_options[] = {
 	  NULL, 1 },
 	OPT_SET_INT('R', "recursive", &max_depth,
 		    N_("shortcut for --max-depth=-1"), -1),
+	OPT__COLOR(&use_color, N_("show color")),
 	OPT_END()
 };
 
@@ -69,6 +72,17 @@ static void free_item(struct item *item)
 	}
 }
 
+static mode_t get_mode(const struct item *item)
+{
+	switch (item->type) {
+	case IS_DIR:
+		return S_IFDIR;
+	case FROM_INDEX:
+		return item->ce->ce_mode;
+	}
+	return S_IFREG;
+}
+
 static void remove_duplicates(struct item_list *list)
 {
 	int src, dst;
@@ -220,6 +234,13 @@ static void display(const struct item_list *result)
 			strbuf_addch(&quoted, ' ');
 		}
 		quote_item(&quoted, item);
+		if (want_color(use_color)) {
+			struct strbuf sb = STRBUF_INIT;
+			strbuf_swap(&sb, &quoted);
+			color_filename(&quoted, item->path, sb.buf,
+				       get_mode(item), 1);
+			strbuf_release(&sb);
+		}
 		if (column_active(colopts))
 			string_list_append(&s, quoted.buf);
 		else
@@ -240,7 +261,11 @@ static int ls_config(const char *var, const char *value, void *cb)
 {
 	if (starts_with(var, "column."))
 		return git_column_config(var, value, "listfiles", &colopts);
-	return git_default_config(var, value, cb);
+	if (!strcmp(var, "color.listfiles")) {
+		use_color = git_config_colorbool(var, value);
+		return 0;
+	}
+	return git_color_default_config(var, value, cb);
 }
 
 int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
@@ -261,6 +286,9 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 
 	argc = parse_options(argc, argv, prefix, ls_options, ls_usage, 0);
 
+	if (want_color(use_color))
+		parse_ls_color();
+
 	parse_pathspec(&pathspec, 0,
 		       PATHSPEC_PREFER_CWD |
 		       (max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0) |
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index a4916d8..cdbc34a 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -110,4 +110,48 @@ test_expect_success 'list-files from subdir (2)' '
 	)
 '
 
+test_expect_success 'setup 2' '
+	git init 2 &&
+	(
+	cd 2 &&
+	mkdir dir &&
+	touch file dir/file &&
+	git init gitlink &&
+	( cd gitlink && test_commit foo ) &&
+	git add file dir/file gitlink &&
+	git commit -qm1
+	)
+'
+
+test_expect_success 'LS_COLORS env variable' '
+	(
+	cd 2 &&
+	LS_COLORS="rs=0:fi=31:di=32" &&
+	export LS_COLORS &&
+	git list-files --color=always | test_decode_color | \
+		grep -v gitlink >actual &&
+	cat >expected <<-\EOF &&
+	<GREEN>dir<RESET>
+	<RED>file<RESET>
+	EOF
+	test_cmp expected actual
+	)
+'
+
+test_expect_success 'color.ls.*' '
+	(
+	cd 2 &&
+	test_config color.ls.file red &&
+	test_config color.ls.directory green &&
+	test_config color.ls.submodule yellow &&
+	git list-files --color=always | test_decode_color >actual &&
+	cat >expected <<-\EOF &&
+	<GREEN>dir<RESET>
+	<RED>file<RESET>
+	<YELLOW>gitlink<RESET>
+	EOF
+	test_cmp expected actual
+	)
+'
+
 test_done
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 12/25] list-files: add -F/--classify
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (10 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 11/25] list-files: add --color Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 13/25] list-files: new indicator '&' for submodules when -F is used Nguyễn Thái Ngọc Duy
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

This appends an indicator after the file name if it's executable, a
directory and so on, like in GNU ls. In fact append_indicator() is a
rewrite from get_type_indicator() in coreutils.git commit
7326d1f1a67edf21947ae98194f98c38b6e9e527.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 27 +++++++++++++++++++++++++++
 t/t7013-list-files.sh | 13 +++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 02a088d..31f1f25 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -34,6 +34,7 @@ static unsigned int colopts;
 static int max_depth;
 static int show_dirs;
 static int use_color = -1;
+static int show_indicator;
 
 static const char * const ls_usage[] = {
 	N_("git list-files [options] [<pathspec>...]"),
@@ -51,6 +52,8 @@ struct option ls_options[] = {
 	OPT_SET_INT('R', "recursive", &max_depth,
 		    N_("shortcut for --max-depth=-1"), -1),
 	OPT__COLOR(&use_color, N_("show color")),
+	OPT_BOOL('F', "classify", &show_indicator,
+		 N_("append indicator (one of */=>@|) to entries")),
 	OPT_END()
 };
 
@@ -204,6 +207,28 @@ static void cleanup_tags(struct item_list *result)
 	}
 }
 
+static void append_indicator(struct strbuf *sb, mode_t mode)
+{
+	char c = 0;
+	if (S_ISREG(mode)) {
+		if (mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+			c = '*';
+	} else if (S_ISDIR(mode))
+		c = '/';
+	else if (S_ISLNK(mode))
+		c = '@';
+	else if (S_ISFIFO(mode))
+		c = '|';
+	else if (S_ISSOCK(mode))
+		c = '=';
+#ifdef S_ISDOOR
+	else if (S_ISDOOR(mode))
+		c = '>';
+#endif
+	if (c)
+		strbuf_addch(sb, c);
+}
+
 /* this is similar to quote_path_relative() except it does not clear sb */
 static void quote_item(struct strbuf *out, const struct item *item)
 {
@@ -241,6 +266,8 @@ static void display(const struct item_list *result)
 				       get_mode(item), 1);
 			strbuf_release(&sb);
 		}
+		if (show_indicator)
+			append_indicator(&quoted, get_mode(item));
 		if (column_active(colopts))
 			string_list_append(&s, quoted.buf);
 		else
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index cdbc34a..16d000e 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -154,4 +154,17 @@ test_expect_success 'color.ls.*' '
 	)
 '
 
+test_expect_success '--classify' '
+	(
+	cd 2 &&
+	git list-files -F >actual &&
+	cat >expected <<-\EOF &&
+	dir/
+	file
+	gitlink
+	EOF
+	test_cmp expected actual
+	)
+'
+
 test_done
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 13/25] list-files: new indicator '&' for submodules when -F is used
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (11 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 12/25] list-files: add -F/--classify Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 14/25] list-files: add --cached and --others Nguyễn Thái Ngọc Duy
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 2 ++
 t/t7013-list-files.sh | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 31f1f25..7c18848 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -221,6 +221,8 @@ static void append_indicator(struct strbuf *sb, mode_t mode)
 		c = '|';
 	else if (S_ISSOCK(mode))
 		c = '=';
+	else if (S_ISGITLINK(mode))
+		c = '&';
 #ifdef S_ISDOOR
 	else if (S_ISDOOR(mode))
 		c = '>';
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index 16d000e..37dd403 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -161,7 +161,7 @@ test_expect_success '--classify' '
 	cat >expected <<-\EOF &&
 	dir/
 	file
-	gitlink
+	gitlink&
 	EOF
 	test_cmp expected actual
 	)
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 14/25] list-files: add --cached and --others
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (12 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 13/25] list-files: new indicator '&' for submodules when -F is used Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 15/25] list-files: add --ignored Nguyễn Thái Ngọc Duy
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

If no filter options are specified, --cached is the default.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 t/t7013-list-files.sh | 38 ++++++++++++++++++++++++-
 2 files changed, 115 insertions(+), 2 deletions(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 7c18848..3cbd30d 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -6,9 +6,11 @@
 #include "quote.h"
 #include "column.h"
 #include "color.h"
+#include "wt-status.h"
 
 enum item_type {
 	FROM_INDEX,
+	FROM_WORKTREE,
 	IS_DIR
 };
 
@@ -17,6 +19,7 @@ struct item {
 	const char *path;
 	char tag[2];
 	const struct cache_entry *ce;
+	struct stat st;
 };
 
 struct item_list {
@@ -35,6 +38,7 @@ static int max_depth;
 static int show_dirs;
 static int use_color = -1;
 static int show_indicator;
+static int show_cached, show_untracked;
 
 static const char * const ls_usage[] = {
 	N_("git list-files [options] [<pathspec>...]"),
@@ -42,6 +46,13 @@ static const char * const ls_usage[] = {
 };
 
 struct option ls_options[] = {
+	OPT_GROUP(N_("Filter options")),
+	OPT_BOOL('c', "cached", &show_cached,
+		 N_("show cached files (default)")),
+	OPT_BOOL('o', "others", &show_untracked,
+		 N_("show untracked files")),
+
+	OPT_GROUP(N_("Other")),
 	OPT_BOOL(0, "tag", &show_tag, N_("show tags")),
 	OPT_COLUMN('C', "column", &colopts, N_("show files in columns")),
 	OPT_SET_INT('1', NULL, &colopts,
@@ -82,6 +93,8 @@ static mode_t get_mode(const struct item *item)
 		return S_IFDIR;
 	case FROM_INDEX:
 		return item->ce->ce_mode;
+	case FROM_WORKTREE:
+		return item->st.st_mode;
 	}
 	return S_IFREG;
 }
@@ -148,6 +161,9 @@ static void populate_cached_entries(struct item_list *result,
 {
 	int i;
 
+	if (!show_cached)
+		return;
+
 	for (i = 0; i < istate->cache_nr; i++) {
 		const struct cache_entry *ce = istate->cache[i];
 		struct item *item;
@@ -169,6 +185,63 @@ static void populate_cached_entries(struct item_list *result,
 	remove_duplicates(result);
 }
 
+static void add_wt_item(struct item_list *result,
+			enum item_type type,
+			const char *path,
+			const char *tag,
+			const struct stat *st)
+{
+	struct item *item;
+
+	ALLOC_GROW(result->items, result->nr + 1, result->alloc);
+	item = result->items + result->nr++;
+	item->type = type;
+	item->path = path;
+	memcpy(item->tag, tag, sizeof(item->tag));
+	memcpy(&item->st, &st, sizeof(st));
+}
+
+static void populate_untracked(struct item_list *result,
+			       const struct string_list *untracked)
+{
+	int i;
+
+	for (i = 0; i < untracked->nr; i++) {
+		const char *name = untracked->items[i].string;
+		struct stat st;
+
+		if (lstat(name, &st))
+			/* color_filename() treats this as an orphan file */
+			st.st_mode = 0;
+
+		if (!matched(result, name, st.st_mode))
+			continue;
+
+		add_wt_item(result, FROM_WORKTREE, name, "??", &st);
+	}
+}
+
+static void wt_status_populate(struct item_list *result,
+			       struct index_state *istate)
+{
+	struct wt_status ws;
+
+	if (!show_untracked)
+		return;
+
+	wt_status_prepare(&ws);
+	copy_pathspec(&ws.pathspec, &recursive_pathspec);
+	ws.relative_paths = 0;
+	ws.use_color = 0;
+	ws.fp = NULL;
+	wt_status_collect(&ws);
+
+	if (show_untracked)
+		populate_untracked(result, &ws.untracked);
+
+	remove_duplicates(result);
+}
+
 static void cleanup_tags(struct item_list *result)
 {
 	int i, same_1 = 1, same_2 = 1;
@@ -178,7 +251,7 @@ static void cleanup_tags(struct item_list *result)
 		result->tag_len = 0;
 		return;
 	}
-	if (show_tag > 0) {
+	if (show_tag > 0 || show_cached + show_untracked > 1) {
 		result->tag_pos = 0;
 		result->tag_len = 2;
 		return;
@@ -315,6 +388,9 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 
 	argc = parse_options(argc, argv, prefix, ls_options, ls_usage, 0);
 
+	if (!show_cached && !show_untracked)
+		show_cached = 1;
+
 	if (want_color(use_color))
 		parse_ls_color();
 
@@ -335,6 +411,7 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 
 	memset(&result, 0, sizeof(result));
 	populate_cached_entries(&result, &the_index);
+	wt_status_populate(&result, &the_index);
 	cleanup_tags(&result);
 	display(&result);
 	/* free-ing result seems unnecessary */
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index 37dd403..53dc745 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -7,7 +7,41 @@ test_description='list-files'
 test_expect_success 'setup' '
 	mkdir sa sa/sb sc &&
 	touch a b c sa/a sa/sb/b sc/c &&
-	git add .
+	git add a sa/a &&
+	git commit -m initial &&
+	git add . &&
+	echo foo >.git/info/exclude &&
+	touch foo bar sa/foo sa/bar
+'
+
+test_expect_success 'list-files --others' '
+	git list-files --others >actual &&
+	cat >expect <<-\EOF &&
+	?? actual
+	?? bar
+	   sa
+	EOF
+	test_cmp expect actual &&
+	git list-files --others --cached >actual &&
+	cat >expect <<-\EOF &&
+	   a
+	?? actual
+	   b
+	?? bar
+	   c
+	?? expect
+	   sa
+	   sc
+	EOF
+	test_cmp expect actual &&
+	git list-files --others -R >actual &&
+	cat >expect <<-\EOF &&
+	actual
+	bar
+	expect
+	sa/bar
+	EOF
+	test_cmp expect actual
 '
 
 test_expect_success 'list-files -R from index' '
@@ -34,6 +68,8 @@ test_expect_success 'list-files from index' '
 	EOF
 	test_cmp expect actual &&
 	git list-files >actual &&
+	test_cmp expect actual &&
+	git list-files --cached >actual &&
 	test_cmp expect actual
 '
 
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 15/25] list-files: add --ignored
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (13 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 14/25] list-files: add --cached and --others Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 21:34   ` Eric Sunshine
  2015-04-06 13:52 ` [PATCH 16/25] list-files: add --unmerged Nguyễn Thái Ngọc Duy
                   ` (10 subsequent siblings)
  25 siblings, 1 reply; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 22 ++++++++++++++++------
 t/t7013-list-files.sh | 15 +++++++++++++++
 2 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 3cbd30d..31991a4 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -39,6 +39,7 @@ static int show_dirs;
 static int use_color = -1;
 static int show_indicator;
 static int show_cached, show_untracked;
+static int show_ignored;
 
 static const char * const ls_usage[] = {
 	N_("git list-files [options] [<pathspec>...]"),
@@ -51,6 +52,8 @@ struct option ls_options[] = {
 		 N_("show cached files (default)")),
 	OPT_BOOL('o', "others", &show_untracked,
 		 N_("show untracked files")),
+	OPT_BOOL('i', "ignored", &show_ignored,
+		 N_("show ignored files")),
 
 	OPT_GROUP(N_("Other")),
 	OPT_BOOL(0, "tag", &show_tag, N_("show tags")),
@@ -202,7 +205,8 @@ static void add_wt_item(struct item_list *result,
 }
 
 static void populate_untracked(struct item_list *result,
-			       const struct string_list *untracked)
+			       const struct string_list *untracked,
+			       const char *tag)
 {
 	int i;
 
@@ -217,7 +221,7 @@ static void populate_untracked(struct item_list *result,
 		if (!matched(result, name, st.st_mode))
 			continue;
 
-		add_wt_item(result, FROM_WORKTREE, name, "??", &st);
+		add_wt_item(result, FROM_WORKTREE, name, tag, &st);
 	}
 }
 
@@ -226,18 +230,22 @@ static void wt_status_populate(struct item_list *result,
 {
 	struct wt_status ws;
 
-	if (!show_untracked)
+	if (!show_untracked && !show_ignored)
 		return;
 
 	wt_status_prepare(&ws);
 	copy_pathspec(&ws.pathspec, &recursive_pathspec);
+	if (show_ignored)
+		ws.show_ignored_files = 1;
 	ws.relative_paths = 0;
 	ws.use_color = 0;
 	ws.fp = NULL;
 	wt_status_collect(&ws);
 
 	if (show_untracked)
-		populate_untracked(result, &ws.untracked);
+		populate_untracked(result, &ws.untracked, "??");
+	if (show_ignored)
+		populate_untracked(result, &ws.ignored, "!!");
 
 	remove_duplicates(result);
 }
@@ -251,7 +259,9 @@ static void cleanup_tags(struct item_list *result)
 		result->tag_len = 0;
 		return;
 	}
-	if (show_tag > 0 || show_cached + show_untracked > 1) {
+
+	if (show_tag > 0 ||
+	    show_cached + show_untracked + show_ignored > 1) {
 		result->tag_pos = 0;
 		result->tag_len = 2;
 		return;
@@ -388,7 +398,7 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 
 	argc = parse_options(argc, argv, prefix, ls_options, ls_usage, 0);
 
-	if (!show_cached && !show_untracked)
+	if (!show_cached && !show_untracked && !show_ignored)
 		show_cached = 1;
 
 	if (want_color(use_color))
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index 53dc745..6b76d1f 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -44,6 +44,21 @@ test_expect_success 'list-files --others' '
 	test_cmp expect actual
 '
 
+test_expect_success 'list-files --others' '
+	git list-files --ignored >actual &&
+	cat >expect <<-\EOF &&
+	!! foo
+	   sa
+	EOF
+	test_cmp expect actual &&
+	git list-files --ignored -R >actual &&
+	cat >expect <<-\EOF &&
+	foo
+	sa/foo
+	EOF
+	test_cmp expect actual
+'
+
 test_expect_success 'list-files -R from index' '
 	git list-files -R >actual &&
 	cat >expect <<-\EOF &&
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 16/25] list-files: add --unmerged
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (14 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 15/25] list-files: add --ignored Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 21:34   ` Eric Sunshine
  2015-04-06 13:52 ` [PATCH 17/25] list-files: add file modification options -[admADM] Nguyễn Thái Ngọc Duy
                   ` (9 subsequent siblings)
  25 siblings, 1 reply; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
 t/t7013-list-files.sh | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 31991a4..fe15417 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -11,7 +11,8 @@
 enum item_type {
 	FROM_INDEX,
 	FROM_WORKTREE,
-	IS_DIR
+	IS_DIR,
+	IS_UNMERGED
 };
 
 struct item {
@@ -38,7 +39,7 @@ static int max_depth;
 static int show_dirs;
 static int use_color = -1;
 static int show_indicator;
-static int show_cached, show_untracked;
+static int show_cached, show_untracked, show_unmerged;
 static int show_ignored;
 
 static const char * const ls_usage[] = {
@@ -54,6 +55,8 @@ struct option ls_options[] = {
 		 N_("show untracked files")),
 	OPT_BOOL('i', "ignored", &show_ignored,
 		 N_("show ignored files")),
+	OPT_BOOL('u', "unmerged", &show_unmerged,
+		 N_("show unmerged files")),
 
 	OPT_GROUP(N_("Other")),
 	OPT_BOOL(0, "tag", &show_tag, N_("show tags")),
@@ -97,6 +100,7 @@ static mode_t get_mode(const struct item *item)
 	case FROM_INDEX:
 		return item->ce->ce_mode;
 	case FROM_WORKTREE:
+	case IS_UNMERGED:
 		return item->st.st_mode;
 	}
 	return S_IFREG;
@@ -225,12 +229,46 @@ static void populate_untracked(struct item_list *result,
 	}
 }
 
+static void populate_unmerged(struct item_list *result,
+			      const struct string_list *change)
+{
+	int i;
+
+	for (i = 0; i < change->nr; i++) {
+		const struct string_list_item *it = change->items + i;
+		struct wt_status_change_data *d = it->util;
+		const char *name = it->string;
+		const char *tag;
+		struct stat st;
+
+		switch (d->stagemask) {
+		case 1: tag = "DD"; break; /* both deleted */
+		case 2: tag = "AU"; break; /* added by us */
+		case 3: tag = "UD"; break; /* deleted by them */
+		case 4: tag = "UA"; break; /* added by them */
+		case 5: tag = "DU"; break; /* deleted by us */
+		case 6: tag = "AA"; break; /* both added */
+		case 7: tag = "UU"; break; /* both modified */
+		default: continue;
+		}
+
+		if (lstat(name, &st))
+			/* color_filename() treats this as an orphan file */
+			st.st_mode = 0;
+
+		if (!matched(result, name, st.st_mode))
+			continue;
+
+		add_wt_item(result, IS_UNMERGED, name, tag, &st);
+	}
+}
+
 static void wt_status_populate(struct item_list *result,
 			       struct index_state *istate)
 {
 	struct wt_status ws;
 
-	if (!show_untracked && !show_ignored)
+	if (!show_untracked && !show_ignored && !show_unmerged)
 		return;
 
 	wt_status_prepare(&ws);
@@ -246,6 +284,8 @@ static void wt_status_populate(struct item_list *result,
 		populate_untracked(result, &ws.untracked, "??");
 	if (show_ignored)
 		populate_untracked(result, &ws.ignored, "!!");
+	if (show_unmerged)
+		populate_unmerged(result, &ws.change);
 
 	remove_duplicates(result);
 }
@@ -260,7 +300,7 @@ static void cleanup_tags(struct item_list *result)
 		return;
 	}
 
-	if (show_tag > 0 ||
+	if (show_tag > 0 || show_unmerged ||
 	    show_cached + show_untracked + show_ignored > 1) {
 		result->tag_pos = 0;
 		result->tag_len = 2;
@@ -398,7 +438,7 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 
 	argc = parse_options(argc, argv, prefix, ls_options, ls_usage, 0);
 
-	if (!show_cached && !show_untracked && !show_ignored)
+	if (!show_cached && !show_untracked && !show_ignored && !show_unmerged)
 		show_cached = 1;
 
 	if (want_color(use_color))
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index 6b76d1f..7fe9673 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -218,4 +218,39 @@ test_expect_success '--classify' '
 	)
 '
 
+test_expect_success 'list-files unmerged' '
+	(
+	add_stage() {
+		echo "100644 $1 $2	$3" | git update-index --index-info
+	}
+	git init 3 &&
+	cd 3 &&
+	test_commit 1 &&
+	SHA1=`echo 1 | git hash-object -w --stdin` &&
+	add_stage $SHA1 1 deleted-by-both &&
+	add_stage $SHA1 2 added-by-us &&
+	add_stage $SHA1 1 deleted-by-them &&
+	add_stage $SHA1 2 deleted-by-them &&
+	add_stage $SHA1 3 added-by-them &&
+	add_stage $SHA1 3 deleted-by-us &&
+	add_stage $SHA1 1 deleted-by-us &&
+	add_stage $SHA1 2 added-by-both &&
+	add_stage $SHA1 3 added-by-both &&
+	add_stage $SHA1 1 modified-by-both &&
+	add_stage $SHA1 2 modified-by-both &&
+	add_stage $SHA1 3 modified-by-both &&
+	git list-files -u >actual &&
+	cat >expected <<-\EOF &&
+	AA added-by-both
+	UA added-by-them
+	AU added-by-us
+	DD deleted-by-both
+	UD deleted-by-them
+	DU deleted-by-us
+	UU modified-by-both
+	EOF
+	test_cmp expected actual
+	)
+'
+
 test_done
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 17/25] list-files: add file modification options -[admADM]
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (15 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 16/25] list-files: add --unmerged Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 21:34   ` Eric Sunshine
  2015-04-06 13:52 ` [PATCH 18/25] list-files: delete redundant cached entries Nguyễn Thái Ngọc Duy
                   ` (8 subsequent siblings)
  25 siblings, 1 reply; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 73 ++++++++++++++++++++++++++++++++++++++++++++++++---
 t/t7013-list-files.sh | 62 +++++++++++++++++++++++++++++++++++++++++++
 wt-status.c           |  8 +++---
 wt-status.h           |  1 +
 4 files changed, 137 insertions(+), 7 deletions(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index fe15417..14ffd62 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -11,6 +11,7 @@
 enum item_type {
 	FROM_INDEX,
 	FROM_WORKTREE,
+	FROM_DIFF,
 	IS_DIR,
 	IS_UNMERGED
 };
@@ -39,8 +40,10 @@ static int max_depth;
 static int show_dirs;
 static int use_color = -1;
 static int show_indicator;
-static int show_cached, show_untracked, show_unmerged;
+static int show_cached, show_untracked, show_unmerged, show_changed;
 static int show_ignored;
+static int show_added, show_deleted, show_modified;
+static int show_wt_added, show_wt_deleted, show_wt_modified;
 
 static const char * const ls_usage[] = {
 	N_("git list-files [options] [<pathspec>...]"),
@@ -57,6 +60,18 @@ struct option ls_options[] = {
 		 N_("show ignored files")),
 	OPT_BOOL('u', "unmerged", &show_unmerged,
 		 N_("show unmerged files")),
+	OPT_BOOL('a', "added", &show_added,
+		 N_("show added files compared to HEAD")),
+	OPT_BOOL('d', "deleted", &show_deleted,
+		 N_("show deleted files compared to HEAD")),
+	OPT_BOOL('m', "modified", &show_modified,
+		 N_("show modified files compared to HEAD")),
+	OPT_BOOL('A', "wt-added", &show_wt_added,
+		 N_("show added files in worktree")),
+	OPT_BOOL('D', "wt-deleted", &show_wt_deleted,
+		 N_("show deleted files in worktree")),
+	OPT_BOOL('M', "wt-modified", &show_wt_modified,
+		 N_("show modified files on worktree")),
 
 	OPT_GROUP(N_("Other")),
 	OPT_BOOL(0, "tag", &show_tag, N_("show tags")),
@@ -100,6 +115,7 @@ static mode_t get_mode(const struct item *item)
 	case FROM_INDEX:
 		return item->ce->ce_mode;
 	case FROM_WORKTREE:
+	case FROM_DIFF:
 	case IS_UNMERGED:
 		return item->st.st_mode;
 	}
@@ -263,18 +279,59 @@ static void populate_unmerged(struct item_list *result,
 	}
 }
 
+static void populate_changed(struct item_list *result,
+			     const struct string_list *change)
+{
+	int i;
+
+	for (i = 0; i < change->nr; i++) {
+		const struct string_list_item *it = change->items + i;
+		struct wt_status_change_data *d = it->util;
+		const char *name = it->string;
+		struct stat st;
+		char tag[2];
+
+		switch (d->stagemask)
+			continue;
+
+		tag[0] = d->index_status ? d->index_status : ' ';
+		tag[1] = d->worktree_status ? d->worktree_status : ' ';
+
+		if ((show_added       && tag[0] == 'A') ||
+		    (show_deleted     && tag[0] == 'D') ||
+		    (show_modified    && tag[0] != ' ') ||
+		    (show_wt_added    && tag[1] == 'A') ||
+		    (show_wt_deleted  && tag[1] == 'D') ||
+		    (show_wt_modified && tag[1] != ' '))
+			;	/* keep going */
+		else
+			continue;
+
+		if (lstat(name, &st))
+			/* color_filename() treats this as an orphan file */
+			st.st_mode = 0;
+
+		if (!matched(result, name, st.st_mode))
+			continue;
+
+		add_wt_item(result, FROM_DIFF, name, tag, &st);
+	}
+}
+
 static void wt_status_populate(struct item_list *result,
 			       struct index_state *istate)
 {
 	struct wt_status ws;
 
-	if (!show_untracked && !show_ignored && !show_unmerged)
+	if (!show_untracked && !show_ignored &&
+	    !show_unmerged && !show_changed)
 		return;
 
 	wt_status_prepare(&ws);
 	copy_pathspec(&ws.pathspec, &recursive_pathspec);
 	if (show_ignored)
 		ws.show_ignored_files = 1;
+	ws.no_rename = 1;
 	ws.relative_paths = 0;
 	ws.use_color = 0;
 	ws.fp = NULL;
@@ -286,6 +343,8 @@ static void wt_status_populate(struct item_list *result,
 		populate_untracked(result, &ws.ignored, "!!");
 	if (show_unmerged)
 		populate_unmerged(result, &ws.change);
+	if (show_changed)
+		populate_changed(result, &ws.change);
 
 	remove_duplicates(result);
 }
@@ -301,7 +360,9 @@ static void cleanup_tags(struct item_list *result)
 	}
 
 	if (show_tag > 0 || show_unmerged ||
-	    show_cached + show_untracked + show_ignored > 1) {
+	    show_cached + show_untracked + show_ignored +
+	    show_added + show_deleted + show_wt_added + show_wt_deleted +
+	    show_modified + show_wt_modified > 1) {
 		result->tag_pos = 0;
 		result->tag_len = 2;
 		return;
@@ -438,7 +499,11 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 
 	argc = parse_options(argc, argv, prefix, ls_options, ls_usage, 0);
 
-	if (!show_cached && !show_untracked && !show_ignored && !show_unmerged)
+	show_changed =
+		show_added || show_deleted || show_modified ||
+		show_wt_added || show_wt_deleted || show_wt_modified;
+	if (!show_cached && !show_untracked && !show_ignored &&
+	    !show_unmerged && !show_changed)
 		show_cached = 1;
 
 	if (want_color(use_color))
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index 7fe9673..c747453 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -253,4 +253,66 @@ test_expect_success 'list-files unmerged' '
 	)
 '
 
+test_expect_success 'list-files --added' '
+	git list-files -a >actual &&
+	cat >expected <<-\EOF &&
+	A b
+	A c
+	  sa
+	  sc
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'list-files --modified' '
+	echo modified >>a &&
+	git add a &&
+	git list-files --modified >actual &&
+	cat >expected <<-\EOF &&
+	M a
+	A b
+	A c
+	  sa
+	  sc
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'list-files --deleted' '
+	git rm --cached a &&
+	git list-files --deleted >actual &&
+	cat >expected <<-\EOF &&
+	a
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'list-files --wt-modifed --wt-deleted' '
+	rm b &&
+	git list-files --wt-deleted >actual &&
+	cat >expected <<-\EOF &&
+	b
+	EOF
+	test_cmp expected actual &&
+	echo foo >>c &&
+	git list-files --wt-modified >actual &&
+	cat >expected <<-\EOF &&
+	D b
+	M c
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'list-files --wt-modifed --modified' '
+	git list-files -mM >actual &&
+	cat >expected <<-\EOF &&
+	D  a
+	AD b
+	AM c
+	   sa
+	   sc
+	EOF
+	test_cmp expected actual
+'
+
 test_done
diff --git a/wt-status.c b/wt-status.c
index cdbc8d7..ba9b56c 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -537,9 +537,11 @@ static void wt_status_collect_changes_index(struct wt_status *s)
 	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
 	rev.diffopt.format_callback = wt_status_collect_updated_cb;
 	rev.diffopt.format_callback_data = s;
-	rev.diffopt.detect_rename = 1;
-	rev.diffopt.rename_limit = 200;
-	rev.diffopt.break_opt = 0;
+	if (!s->no_rename) {
+		rev.diffopt.detect_rename = 1;
+		rev.diffopt.rename_limit = 200;
+		rev.diffopt.break_opt = 0;
+	}
 	copy_pathspec(&rev.prune_data, &s->pathspec);
 	run_diff_index(&rev, 1);
 }
diff --git a/wt-status.h b/wt-status.h
index 283a9fe..dc94f35 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -55,6 +55,7 @@ struct wt_status {
 	int relative_paths;
 	int submodule_summary;
 	int show_ignored_files;
+	int no_rename;
 	enum untracked_status_type show_untracked_files;
 	const char *ignore_submodule_arg;
 	char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 18/25] list-files: delete redundant cached entries
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (16 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 17/25] list-files: add file modification options -[admADM] Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 21:35   ` Eric Sunshine
  2015-04-06 13:52 ` [PATCH 19/25] list-files: make alias 'ls' default to 'list-files' Nguyễn Thái Ngọc Duy
                   ` (7 subsequent siblings)
  25 siblings, 1 reply; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

When both --cached and one of -amdAMD is used together we may have two
entries of the same path, e.g. "  foo" and "MM foo". In this case it's
pretty clear that "foo" must be tracked, no need to display "   foo".
The new function does that.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 12 ++++++++++--
 t/t7013-list-files.sh | 12 ++++++++++++
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 14ffd62..31c2336 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -93,7 +93,10 @@ static int compare_item(const void *a_, const void *b_)
 {
 	const struct item *a = a_;
 	const struct item *b = b_;
-	return strcmp(a->path, b->path);
+	int ret = strcmp(a->path, b->path);
+	if (ret)
+		return ret;
+	return strncmp(a->tag, b->tag, 2);
 }
 
 static void free_item(struct item *item)
@@ -132,7 +135,12 @@ static void remove_duplicates(struct item_list *list)
 	for (src = dst = 1; src < list->nr; src++) {
 		if (!compare_item(list->items + dst - 1, list->items + src))
 			free_item(list->items + src);
-		else
+		else if ((list->items[dst - 1].tag[0] == ' ' &&
+			  list->items[dst - 1].tag[1] == ' ' &&
+			  !strcmp(list->items[src].path, list->items[dst - 1].path))) {
+			free_item(list->items + dst - 1);
+			list->items[dst - 1] = list->items[src];
+		} else
 			list->items[dst++] = list->items[src];
 	}
 	list->nr = dst;
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index c747453..392cce1 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -315,4 +315,16 @@ test_expect_success 'list-files --wt-modifed --modified' '
 	test_cmp expected actual
 '
 
+test_expect_success 'list-files -mMc' '
+	git list-files -mMc >actual &&
+	cat >expected <<-\EOF &&
+	D  a
+	AD b
+	AM c
+	   sa
+	   sc
+	EOF
+	test_cmp expected actual
+'
+
 test_done
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 19/25] list-files: make alias 'ls' default to 'list-files'
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (17 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 18/25] list-files: delete redundant cached entries Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 20/25] list-files: preload index Nguyễn Thái Ngọc Duy
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 config.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/config.c b/config.c
index 15a2983..16209c6 100644
--- a/config.c
+++ b/config.c
@@ -40,6 +40,10 @@ static struct config_source *cf;
 
 static int zlib_compression_seen;
 
+static const char *builtin_config =
+	"[alias]\n"
+	"	ls = list-files\n";
+
 /*
  * Default config_set that contains key-value pairs from the usual set of config
  * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
@@ -1175,6 +1179,10 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
 	home_config_paths(&user_config, &xdg_config, "config");
 
+	if (git_config_system())
+		git_config_from_buf(fn, "<builtin>", builtin_config,
+				    strlen(builtin_config), data);
+
 	if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
 		ret += git_config_from_file(fn, git_etc_gitconfig(),
 					    data);
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 20/25] list-files: preload index
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (18 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 19/25] list-files: make alias 'ls' default to 'list-files' Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 21:35   ` Eric Sunshine
  2015-04-06 13:52 ` [PATCH 21/25] list-files: reduce match_pathspec calls in matched() Nguyễn Thái Ngọc Duy
                   ` (5 subsequent siblings)
  25 siblings, 1 reply; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Try to reduce refresh time. Note that we still need another
read_cache() at top top, before parse_pathspec() because this
*_SLASH_CHEAP needs the index loaded.

One day read_index() should be improved to notice that the on-disk
version is the same as the one in memory and skip I/O entirely..

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 31c2336..948b8e6 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -529,6 +529,7 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 	recursive_pathspec.max_depth = -1;
 	finalize_colopts(&colopts, -1);
 
+	read_cache_preload(&recursive_pathspec);
 	refresh_index(&the_index, REFRESH_QUIET | REFRESH_UNMERGED,
 		      &recursive_pathspec, NULL, NULL);
 
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 21/25] list-files: reduce match_pathspec calls in matched()
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (19 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 20/25] list-files: preload index Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 22/25] list-files: only do diff that is actually useful Nguyễn Thái Ngọc Duy
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

match_pathspec() is expensive and the loop of match_pathspec() in
add_directory() is even more so. Luckily the output string list is
usually sorted so if we add a directory "builtin", chances are
builtin/foo follows right after. Perform a cheaper strncasecmp() in
this case.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c | 49 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 37 insertions(+), 12 deletions(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 948b8e6..228c39b 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -146,8 +146,8 @@ static void remove_duplicates(struct item_list *list)
 	list->nr = dst;
 }
 
-static int add_directory(struct item_list *result,
-			 const char *name)
+static const char *add_directory(struct item_list *result,
+				 const char *name)
 {
 	struct strbuf sb = STRBUF_INIT;
 	struct item *item;
@@ -165,24 +165,37 @@ static int add_directory(struct item_list *result,
 		item->path = strbuf_detach(&sb, NULL);
 		item->tag[0] = ' ';
 		item->tag[1] = ' ';
-		return 1;
+		return item->path;
 	}
 	strbuf_release(&sb);
-	return 0;
+	return NULL;
 }
 
-static int matched(struct item_list *result, const char *name, int mode)
+static int matched(struct item_list *result, const char *name, int mode,
+		   const char **last_directory, int *last_dir_len)
 {
 	int len = strlen(name);
 
+	if (*last_dir_len && len > *last_dir_len) {
+		if (!strncasecmp(name, *last_directory, *last_dir_len) &&
+		    name[*last_dir_len] == '/')
+			return 0;
+		*last_dir_len = 0;
+	}
+
 	if (!match_pathspec(&recursive_pathspec, name, len, 0, NULL,
 			    S_ISDIR(mode) || S_ISGITLINK(mode)))
 		return 0;
 
 	if (show_dirs && strchr(name, '/') &&
-	    !match_pathspec(&pathspec, name, len, 0, NULL, 1) &&
-	    add_directory(result, name))
-		return 0;
+	    !match_pathspec(&pathspec, name, len, 0, NULL, 1)) {
+		const char *p = add_directory(result, name);
+		if (p) {
+			*last_directory = p;
+			*last_dir_len = strlen(p);
+			return 0;
+		}
+	}
 
 	return 1;
 }
@@ -190,6 +203,8 @@ static int matched(struct item_list *result, const char *name, int mode)
 static void populate_cached_entries(struct item_list *result,
 				    const struct index_state *istate)
 {
+	const char *last_directory;
+	int last_dir_len = 0;
 	int i;
 
 	if (!show_cached)
@@ -199,7 +214,8 @@ static void populate_cached_entries(struct item_list *result,
 		const struct cache_entry *ce = istate->cache[i];
 		struct item *item;
 
-		if (!matched(result, ce->name, ce->ce_mode))
+		if (!matched(result, ce->name, ce->ce_mode,
+			     &last_directory, &last_dir_len))
 			continue;
 
 		ALLOC_GROW(result->items, result->nr + 1, result->alloc);
@@ -236,6 +252,8 @@ static void populate_untracked(struct item_list *result,
 			       const struct string_list *untracked,
 			       const char *tag)
 {
+	const char *last_directory;
+	int last_dir_len = 0;
 	int i;
 
 	for (i = 0; i < untracked->nr; i++) {
@@ -246,7 +264,8 @@ static void populate_untracked(struct item_list *result,
 			/* color_filename() treats this as an orphan file */
 			st.st_mode = 0;
 
-		if (!matched(result, name, st.st_mode))
+		if (!matched(result, name, st.st_mode,
+			     &last_directory, &last_dir_len))
 			continue;
 
 		add_wt_item(result, FROM_WORKTREE, name, tag, &st);
@@ -256,6 +275,8 @@ static void populate_untracked(struct item_list *result,
 static void populate_unmerged(struct item_list *result,
 			      const struct string_list *change)
 {
+	const char *last_directory;
+	int last_dir_len = 0;
 	int i;
 
 	for (i = 0; i < change->nr; i++) {
@@ -280,7 +301,8 @@ static void populate_unmerged(struct item_list *result,
 			/* color_filename() treats this as an orphan file */
 			st.st_mode = 0;
 
-		if (!matched(result, name, st.st_mode))
+		if (!matched(result, name, st.st_mode,
+			     &last_directory, &last_dir_len))
 			continue;
 
 		add_wt_item(result, IS_UNMERGED, name, tag, &st);
@@ -290,6 +312,8 @@ static void populate_unmerged(struct item_list *result,
 static void populate_changed(struct item_list *result,
 			     const struct string_list *change)
 {
+	const char *last_directory;
+	int last_dir_len = 0;
 	int i;
 
 	for (i = 0; i < change->nr; i++) {
@@ -319,7 +343,8 @@ static void populate_changed(struct item_list *result,
 			/* color_filename() treats this as an orphan file */
 			st.st_mode = 0;
 
-		if (!matched(result, name, st.st_mode))
+		if (!matched(result, name, st.st_mode,
+			     &last_directory, &last_dir_len))
 			continue;
 
 		add_wt_item(result, FROM_DIFF, name, tag, &st);
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 22/25] list-files: only do diff that is actually useful
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (20 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 21/25] list-files: reduce match_pathspec calls in matched() Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 23/25] pathspec: move getenv() code out of prefix_pathspec() Nguyễn Thái Ngọc Duy
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c | 12 ++++++++++++
 wt-status.c          |  8 ++++++++
 wt-status.h          |  2 ++
 3 files changed, 22 insertions(+)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index 228c39b..fc9c8d4 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -365,6 +365,10 @@ static void wt_status_populate(struct item_list *result,
 	if (show_ignored)
 		ws.show_ignored_files = 1;
 	ws.no_rename = 1;
+	ws.show_index_changes = show_unmerged || show_added ||
+		show_modified || show_deleted;
+	ws.show_worktree_changes = show_unmerged || show_wt_added ||
+		show_wt_modified || show_wt_deleted;
 	ws.relative_paths = 0;
 	ws.use_color = 0;
 	ws.fp = NULL;
@@ -538,6 +542,14 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 	if (!show_cached && !show_untracked && !show_ignored &&
 	    !show_unmerged && !show_changed)
 		show_cached = 1;
+	if (show_unmerged) {
+		int i;
+		for (i = 0; i < the_index.cache_nr; i++)
+			if (ce_stage(the_index.cache[i]))
+				break;
+		if (i == the_index.cache_nr)
+			show_unmerged = 0;
+	}
 
 	if (want_color(use_color))
 		parse_ls_color();
diff --git a/wt-status.c b/wt-status.c
index ba9b56c..ce149b9 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -126,6 +126,8 @@ void wt_status_prepare(struct wt_status *s)
 	memcpy(s->color_palette, default_wt_status_colors,
 	       sizeof(default_wt_status_colors));
 	s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
+	s->show_index_changes = 1;
+	s->show_worktree_changes = 1;
 	s->use_color = -1;
 	s->relative_paths = 1;
 	s->branch = resolve_refdup("HEAD", 0, sha1, NULL);
@@ -493,6 +495,9 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
 {
 	struct rev_info rev;
 
+	if (!s->show_worktree_changes)
+		return;
+
 	init_revisions(&rev, NULL);
 	setup_revisions(0, NULL, &rev, NULL);
 	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
@@ -514,6 +519,9 @@ static void wt_status_collect_changes_index(struct wt_status *s)
 	struct rev_info rev;
 	struct setup_revision_opt opt;
 
+	if (!s->show_index_changes)
+		return;
+
 	init_revisions(&rev, NULL);
 	memset(&opt, 0, sizeof(opt));
 	opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference;
diff --git a/wt-status.h b/wt-status.h
index dc94f35..1d7ad3a 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -57,6 +57,8 @@ struct wt_status {
 	int show_ignored_files;
 	int no_rename;
 	enum untracked_status_type show_untracked_files;
+	int show_index_changes;
+	int show_worktree_changes;
 	const char *ignore_submodule_arg;
 	char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];
 	unsigned colopts;
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 23/25] pathspec: move getenv() code out of prefix_pathspec()
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (21 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 22/25] list-files: only do diff that is actually useful Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 24/25] list-files: make :(glob) pathspec default Nguyễn Thái Ngọc Duy
                   ` (2 subsequent siblings)
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pathspec.c | 55 +++++++++++++++++++++++++++----------------------------
 1 file changed, 27 insertions(+), 28 deletions(-)

diff --git a/pathspec.c b/pathspec.c
index 9304ee3..5573127 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -88,6 +88,13 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,
 	strbuf_addf(sb, ",prefix:%d)", prefixlen);
 }
 
+struct global_flags {
+	unsigned literal : 1;
+	unsigned glob : 1;
+	unsigned noglob : 1;
+	unsigned icase : 1;
+};
+
 /*
  * Take an element of a pathspec and check for magic signatures.
  * Append the result to the prefix. Return the magic bitmap.
@@ -105,39 +112,20 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
 				unsigned *p_short_magic,
 				const char **raw, unsigned flags,
 				const char *prefix, int prefixlen,
-				const char *elt)
+				const char *elt,
+				const struct global_flags *global)
 {
-	static int literal_global = -1;
-	static int glob_global = -1;
-	static int noglob_global = -1;
-	static int icase_global = -1;
 	unsigned magic = 0, short_magic = 0, global_magic = 0;
 	const char *copyfrom = elt, *long_magic_end = NULL;
 	char *match;
 	int i, pathspec_prefix = -1;
 
-	if (literal_global < 0)
-		literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
-	if (literal_global)
+	if (global->literal)
 		global_magic |= PATHSPEC_LITERAL;
-
-	if (glob_global < 0)
-		glob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
-	if (glob_global)
+	if (global->glob)
 		global_magic |= PATHSPEC_GLOB;
-
-	if (noglob_global < 0)
-		noglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);
-
-	if (glob_global && noglob_global)
-		die(_("global 'glob' and 'noglob' pathspec settings are incompatible"));
-
-
-	if (icase_global < 0)
-		icase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
-	if (icase_global)
+	if (global->icase)
 		global_magic |= PATHSPEC_ICASE;
-
 	if ((global_magic & PATHSPEC_LITERAL) &&
 	    (global_magic & ~PATHSPEC_LITERAL))
 		die(_("global 'literal' pathspec setting is incompatible "
@@ -146,7 +134,8 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
 	if (flags & PATHSPEC_LITERAL_PATH)
 		global_magic = 0;
 
-	if (elt[0] != ':' || literal_global ||
+
+	if (elt[0] != ':' || global->literal ||
 	    (flags & PATHSPEC_LITERAL_PATH)) {
 		; /* nothing to do */
 	} else if (elt[1] == '(') {
@@ -213,7 +202,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
 	*p_short_magic = short_magic;
 
 	/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */
-	if (noglob_global && !(magic & PATHSPEC_GLOB))
+	if (global->noglob && !(magic & PATHSPEC_GLOB))
 		global_magic |= PATHSPEC_LITERAL;
 
 	/* --glob-pathspec is overridden by :(literal) */
@@ -247,7 +236,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
 	 */
 	if (flags & PATHSPEC_PREFIX_ORIGIN) {
 		struct strbuf sb = STRBUF_INIT;
-		if (prefixlen && !literal_global) {
+		if (prefixlen && !global->literal) {
 			/* Preserve the actual prefix length of each pattern */
 			if (short_magic)
 				prefix_short_magic(&sb, prefixlen, short_magic);
@@ -365,6 +354,7 @@ void parse_pathspec(struct pathspec *pathspec,
 	struct pathspec_item *item;
 	const char *entry = argv ? *argv : NULL;
 	int i, n, prefixlen, nr_exclude = 0;
+	struct global_flags global;
 
 	memset(pathspec, 0, sizeof(*pathspec));
 
@@ -401,6 +391,14 @@ void parse_pathspec(struct pathspec *pathspec,
 		return;
 	}
 
+	memset(&global, 0, sizeof(global));
+	global.literal = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0) != 0;
+	global.glob    = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT,    0) != 0;
+	global.noglob  = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT,  0) != 0;
+	global.icase   = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT,   0) != 0;
+	if (global.glob && global.noglob)
+		die(_("global 'glob' and 'noglob' pathspec settings are incompatible"));
+
 	n = 0;
 	while (argv[n])
 		n++;
@@ -416,7 +414,8 @@ void parse_pathspec(struct pathspec *pathspec,
 
 		item[i].magic = prefix_pathspec(item + i, &short_magic,
 						argv + i, flags,
-						prefix, prefixlen, entry);
+						prefix, prefixlen, entry,
+						&global);
 		if ((flags & PATHSPEC_LITERAL_PATH) &&
 		    !(magic_mask & PATHSPEC_LITERAL))
 			item[i].magic |= PATHSPEC_LITERAL;
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 24/25] list-files: make :(glob) pathspec default
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (22 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 23/25] pathspec: move getenv() code out of prefix_pathspec() Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 13:52 ` [PATCH 25/25] list-files: documentation Nguyễn Thái Ngọc Duy
  2015-04-06 13:58 ` [PATCH v2 00/25] list-files redesign Duy Nguyen
  25 siblings, 0 replies; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/list-files.c  | 1 +
 pathspec.c            | 4 ++++
 pathspec.h            | 1 +
 t/t7013-list-files.sh | 7 ++++++-
 4 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/builtin/list-files.c b/builtin/list-files.c
index fc9c8d4..c85bb55 100644
--- a/builtin/list-files.c
+++ b/builtin/list-files.c
@@ -557,6 +557,7 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
 	parse_pathspec(&pathspec, 0,
 		       PATHSPEC_PREFER_CWD |
 		       (max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0) |
+		       PATHSPEC_DEFAULT_GLOB |
 		       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
 		       cmd_prefix, argv);
 	pathspec.max_depth = max_depth;
diff --git a/pathspec.c b/pathspec.c
index 5573127..3770c26 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -396,6 +396,10 @@ void parse_pathspec(struct pathspec *pathspec,
 	global.glob    = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT,    0) != 0;
 	global.noglob  = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT,  0) != 0;
 	global.icase   = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT,   0) != 0;
+	if ((flags & PATHSPEC_DEFAULT_GLOB) &&
+	    !getenv(GIT_GLOB_PATHSPECS_ENVIRONMENT) &&
+	    !getenv(GIT_NOGLOB_PATHSPECS_ENVIRONMENT))
+		global.glob = 1;
 	if (global.glob && global.noglob)
 		die(_("global 'glob' and 'noglob' pathspec settings are incompatible"));
 
diff --git a/pathspec.h b/pathspec.h
index 0c11262..7e4058f 100644
--- a/pathspec.h
+++ b/pathspec.h
@@ -67,6 +67,7 @@ struct pathspec {
  * allowed, then it will automatically set for every pathspec.
  */
 #define PATHSPEC_LITERAL_PATH (1<<8)
+#define PATHSPEC_DEFAULT_GLOB (1<<9) /* :(glob) by default */
 
 extern void parse_pathspec(struct pathspec *pathspec,
 			   unsigned magic_mask,
diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
index 392cce1..4a9368e 100755
--- a/t/t7013-list-files.sh
+++ b/t/t7013-list-files.sh
@@ -116,11 +116,16 @@ test_expect_success 'column output' '
 '
 
 test_expect_success 'list-files selectively from index' '
-	git list-files -R "*a" >actual &&
+	git list-files -R "**/a" >actual &&
 	cat >expect <<-\EOF &&
 	a
 	sa/a
 	EOF
+	test_cmp expect actual &&
+	git list-files -R "*a" >actual &&
+	cat >expect <<-\EOF &&
+	a
+	EOF
 	test_cmp expect actual
 '
 
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 25/25] list-files: documentation
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (23 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 24/25] list-files: make :(glob) pathspec default Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:52 ` Nguyễn Thái Ngọc Duy
  2015-04-06 21:37   ` Eric Sunshine
  2015-04-06 13:58 ` [PATCH v2 00/25] list-files redesign Duy Nguyen
  25 siblings, 1 reply; 36+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-04-06 13:52 UTC (permalink / raw)
  To: git
  Cc: 1425896314-10941-1-git-send-email-pclouds,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-list-files.txt (new) | 115 +++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)
 create mode 100644 Documentation/git-list-files.txt

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
new file mode 100644
index 0000000..9b9edce
--- /dev/null
+++ b/Documentation/git-list-files.txt
@@ -0,0 +1,115 @@
+git-list-files(1)
+===============
+
+NAME
+----
+git-list-files - List files
+
+SYNOPSIS
+--------
+[verse]
+'git list-files [options] [<pathspec>...]
+
+DESCRIPTION
+-----------
+List files (by default in current working directory) that are in the
+index. Depending on the chosen options, maybe only modified files in
+working tree are shown, or untracked files... The builtin alias "ls"
+is set to "list-files".
+
+OPTIONS
+-------
+-c::
+--cached::
+	Show cached files (default)
+
+-d::
+--deleted::
+	Show deleted files in index, compared to HEAD
+
+-a::
+--added::
+	Show added files in index, compared to HEAD
+
+-m::
+--modified::
+	Show modified files in index, compared to HEAD. This implies
+	--deleted and --added
+
+-D::
+--wt-deleted::
+	Show deleted files in working directory
+
+-A::
+--wt-added::
+	Show added files in working directory
+
+-M::
+--wt-modified::
+	Show modified files in working directory. This implies
+	--wt-deleted and --wt-added
+
+-o::
+--others::
+	Show untracked files (and only unignored ones unless -i is
+	specified)
+
+-i::
+--ignored::
+	Show only ignored files. When showing files in the index,
+	print only those matched by an exclude pattern. When showing
+	"other" files, show only those matched by an exclude pattern.
+
+-u::
+--unmerged::
+	Show unmerged files
+
+-F::
+--classify::
+	Append indicator (one of `*/=>@|&`, which is executable,
+	directory, socket, Solaris door, symlink, fifo, or submodule
+	respectively) to entries.
+
+--color[=<when>]::
+--no-color::
+	Color file names. The value must be `always`, `never`, or
+	`auto`. `--no-color` is equivalent to
+	`--color=never`. `--color` is equivalent to
+	`--color=auto`. See configuration variable `color.list-files`
+	for the default settings.
+
+--column[=<options>]::
+--no-column::
+-1::
+	Display files in columns. See configuration variable column.ui
+	for option syntax. `--column` and `--no-column` without options
+	are equivalent to 'always' and 'never' respectively.
+	`-1` is a shortcut for --no-column.
+
+--max-depth=<depth>::
+--recursive::
+-R::
+	For each <pathspec> given on command line, descend at most <depth>
+	levels of directories. A negative value means no limit.
+	This option is ignored if <pathspec> contains active wildcards.
+	In other words if "a*" matches a directory named "a*",
+	"*" is matched literally so --max-depth is still effective.
+	`-R` or `--recursive` is equivalent of `--max-depth=-1`
+	(infinite recursion).  The default is `--max-depth=0`.
+
+--tag::
+--no-tag::
+	Usually when tags are displayed by the left of the file name if
+	there are more than one file selection. Use either of these options
+	to force always or never display tags.
+
+<pathspec>::
+	Files to show. :(glob) magic is enabled by default.
+
+SEE ALSO
+--------
+linkgit:git-ls-files[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
-- 
2.3.0.rc1.137.g477eb31

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 00/25] list-files redesign
  2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
                   ` (24 preceding siblings ...)
  2015-04-06 13:52 ` [PATCH 25/25] list-files: documentation Nguyễn Thái Ngọc Duy
@ 2015-04-06 13:58 ` Duy Nguyen
  25 siblings, 0 replies; 36+ messages in thread
From: Duy Nguyen @ 2015-04-06 13:58 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Nguyễn Thái Ngọc Duy

On Mon, Apr 6, 2015 at 8:52 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> The UI part is the same (or nearly the same) with the last round. The
> internal data structure is reorignized to avoid abusing string_list.
> Tests and documentation are added back.

It's supposed to be a reply to the last round [1] but I missed
--in-reply-to and screwed it up. Sorry.

[1] http://permalink.gmane.org/gmane.comp.version-control.git/265142
-- 
Duy

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 07/25] list-files: add tag to each entry, filter duplicate tags
  2015-04-06 13:52 ` [PATCH 07/25] list-files: add tag to each entry, filter duplicate tags Nguyễn Thái Ngọc Duy
@ 2015-04-06 21:32   ` Eric Sunshine
  0 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-04-06 21:32 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: Git List, 1425896314-10941-1-git-send-email-pclouds

On Mon, Apr 6, 2015 at 9:52 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> All entries have a two-letter tag. If all entries have the same tags,
> tags are not displayed.
>
> The outcome before and after this patch is the same. But it will be
> useful in future when there are more than one type of entry.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/builtin/list-files.c b/builtin/list-files.c
> index 51ff19d..ec9ca17 100644
> --- a/builtin/list-files.c
> +++ b/builtin/list-files.c
> @@ -52,10 +56,61 @@ static void populate_cached_entries(struct item_list *result,
> +static void cleanup_tags(struct item_list *result)
> +{
> +       int i, same_1 = 1, same_2 = 1;
> +
> +       if (!show_tag) {
> +               result->tag_pos = 0;
> +               result->tag_len = 0;
> +               return;
> +       }
> [...]
> +}
> +
> +/* this is similar to quote_path_relative() except it does not clear sb */

This comment is a bit confusing since it talks about 'sb', which is a
local variable, rather than the intended 'out'. Perhaps rephrase:

    /* similar to quote_path_relative() but does not clear 'out' */

> +static void quote_item(struct strbuf *out, const struct item *item)
> +{
> +       static struct strbuf sb = STRBUF_INIT;
> +       const char *rel;
> +
> +       strbuf_reset(&sb);
> +       rel = relative_path(item->path, prefix, &sb);
> +       quote_c_style(rel, out, NULL, 0);
> +}
> +
>  static void display(const struct item_list *result)
>  {
>         struct strbuf quoted = STRBUF_INIT;

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 11/25] list-files: add --color
  2015-04-06 13:52 ` [PATCH 11/25] list-files: add --color Nguyễn Thái Ngọc Duy
@ 2015-04-06 21:33   ` Eric Sunshine
  0 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-04-06 21:33 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Mon, Apr 6, 2015 at 9:52 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
> index a4916d8..cdbc34a 100755
> --- a/t/t7013-list-files.sh
> +++ b/t/t7013-list-files.sh
> @@ -110,4 +110,48 @@ test_expect_success 'list-files from subdir (2)' '
>         )
>  '
>
> +test_expect_success 'setup 2' '
> +       git init 2 &&
> +       (
> +       cd 2 &&
> +       mkdir dir &&
> +       touch file dir/file &&
> +       git init gitlink &&
> +       ( cd gitlink && test_commit foo ) &&
> +       git add file dir/file gitlink &&
> +       git commit -qm1

Minor: Why -q?

> +       )
> +'
> +
> +test_expect_success 'LS_COLORS env variable' '
> +       (
> +       cd 2 &&
> +       LS_COLORS="rs=0:fi=31:di=32" &&
> +       export LS_COLORS &&
> +       git list-files --color=always | test_decode_color | \
> +               grep -v gitlink >actual &&
> +       cat >expected <<-\EOF &&
> +       <GREEN>dir<RESET>
> +       <RED>file<RESET>
> +       EOF
> +       test_cmp expected actual
> +       )
> +'
> +
> +test_expect_success 'color.ls.*' '
> +       (
> +       cd 2 &&
> +       test_config color.ls.file red &&
> +       test_config color.ls.directory green &&
> +       test_config color.ls.submodule yellow &&
> +       git list-files --color=always | test_decode_color >actual &&
> +       cat >expected <<-\EOF &&
> +       <GREEN>dir<RESET>
> +       <RED>file<RESET>
> +       <YELLOW>gitlink<RESET>
> +       EOF
> +       test_cmp expected actual
> +       )
> +'
> +
>  test_done
> --
> 2.3.0.rc1.137.g477eb31

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 15/25] list-files: add --ignored
  2015-04-06 13:52 ` [PATCH 15/25] list-files: add --ignored Nguyễn Thái Ngọc Duy
@ 2015-04-06 21:34   ` Eric Sunshine
  0 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-04-06 21:34 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Mon, Apr 6, 2015 at 9:52 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/builtin/list-files.c b/builtin/list-files.c
> index 3cbd30d..31991a4 100644
> --- a/builtin/list-files.c
> +++ b/builtin/list-files.c
> @@ -39,6 +39,7 @@ static int show_dirs;
>  static int use_color = -1;
>  static int show_indicator;
>  static int show_cached, show_untracked;
> +static int show_ignored;
>
>  static const char * const ls_usage[] = {
>         N_("git list-files [options] [<pathspec>...]"),
> @@ -51,6 +52,8 @@ struct option ls_options[] = {
>                  N_("show cached files (default)")),
>         OPT_BOOL('o', "others", &show_untracked,
>                  N_("show untracked files")),
> +       OPT_BOOL('i', "ignored", &show_ignored,
> +                N_("show ignored files")),
>
>         OPT_GROUP(N_("Other")),
>         OPT_BOOL(0, "tag", &show_tag, N_("show tags")),
> @@ -202,7 +205,8 @@ static void add_wt_item(struct item_list *result,
>  }
>
>  static void populate_untracked(struct item_list *result,
> -                              const struct string_list *untracked)
> +                              const struct string_list *untracked,
> +                              const char *tag)

Minor: I could easily see patch 14/25 declaring populate_untracked()
this way in the first place...

>  {
>         int i;
>
> @@ -217,7 +221,7 @@ static void populate_untracked(struct item_list *result,
>                 if (!matched(result, name, st.st_mode))
>                         continue;
>
> -               add_wt_item(result, FROM_WORKTREE, name, "??", &st);
> +               add_wt_item(result, FROM_WORKTREE, name, tag, &st);

...since doing so would eliminate this change from 15/25 and...
(continued below)

>         }
>  }
>
> @@ -226,18 +230,22 @@ static void wt_status_populate(struct item_list *result,
>  {
>         struct wt_status ws;
>
> -       if (!show_untracked)
> +       if (!show_untracked && !show_ignored)
>                 return;
>
>         wt_status_prepare(&ws);
>         copy_pathspec(&ws.pathspec, &recursive_pathspec);
> +       if (show_ignored)
> +               ws.show_ignored_files = 1;

Simpler:

    ws.show_ignored_files = show_ignored;

>         ws.relative_paths = 0;
>         ws.use_color = 0;
>         ws.fp = NULL;
>         wt_status_collect(&ws);
>
>         if (show_untracked)
> -               populate_untracked(result, &ws.untracked);
> +               populate_untracked(result, &ws.untracked, "??");

(continued from above) ...and this change.

More below.

> +       if (show_ignored)
> +               populate_untracked(result, &ws.ignored, "!!");
>
>         remove_duplicates(result);
>  }
> @@ -251,7 +259,9 @@ static void cleanup_tags(struct item_list *result)
>                 result->tag_len = 0;
>                 return;
>         }
> -       if (show_tag > 0 || show_cached + show_untracked > 1) {
> +
> +       if (show_tag > 0 ||
> +           show_cached + show_untracked + show_ignored > 1) {
>                 result->tag_pos = 0;
>                 result->tag_len = 2;
>                 return;
> @@ -388,7 +398,7 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
>
>         argc = parse_options(argc, argv, prefix, ls_options, ls_usage, 0);
>
> -       if (!show_cached && !show_untracked)
> +       if (!show_cached && !show_untracked && !show_ignored)
>                 show_cached = 1;
>
>         if (want_color(use_color))
> diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
> index 53dc745..6b76d1f 100755
> --- a/t/t7013-list-files.sh
> +++ b/t/t7013-list-files.sh
> @@ -44,6 +44,21 @@ test_expect_success 'list-files --others' '
>         test_cmp expect actual
>  '
>
> +test_expect_success 'list-files --others' '

s/others/ignored/

> +       git list-files --ignored >actual &&
> +       cat >expect <<-\EOF &&
> +       !! foo
> +          sa
> +       EOF
> +       test_cmp expect actual &&
> +       git list-files --ignored -R >actual &&
> +       cat >expect <<-\EOF &&
> +       foo
> +       sa/foo
> +       EOF
> +       test_cmp expect actual
> +'
> +
>  test_expect_success 'list-files -R from index' '
>         git list-files -R >actual &&
>         cat >expect <<-\EOF &&
> --
> 2.3.0.rc1.137.g477eb31

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 16/25] list-files: add --unmerged
  2015-04-06 13:52 ` [PATCH 16/25] list-files: add --unmerged Nguyễn Thái Ngọc Duy
@ 2015-04-06 21:34   ` Eric Sunshine
  0 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-04-06 21:34 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Mon, Apr 6, 2015 at 9:52 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/builtin/list-files.c b/builtin/list-files.c
> index 31991a4..fe15417 100644
> --- a/builtin/list-files.c
> +++ b/builtin/list-files.c
> @@ -225,12 +229,46 @@ static void populate_untracked(struct item_list *result,
>         }
>  }
>
> +static void populate_unmerged(struct item_list *result,
> +                             const struct string_list *change)
> +{
> +       int i;
> +
> +       for (i = 0; i < change->nr; i++) {
> +               const struct string_list_item *it = change->items + i;
> +               struct wt_status_change_data *d = it->util;
> +               const char *name = it->string;
> +               const char *tag;
> +               struct stat st;
> +
> +               switch (d->stagemask) {
> +               case 1: tag = "DD"; break; /* both deleted */
> +               case 2: tag = "AU"; break; /* added by us */
> +               case 3: tag = "UD"; break; /* deleted by them */
> +               case 4: tag = "UA"; break; /* added by them */
> +               case 5: tag = "DU"; break; /* deleted by us */
> +               case 6: tag = "AA"; break; /* both added */
> +               case 7: tag = "UU"; break; /* both modified */
> +               default: continue;

Does the 'default' case represent a "cannot happen" situation? If so,
does it deserve some sort of "BUG" diagnostic message or something?

More below.

> +               }
> +
> +               if (lstat(name, &st))
> +                       /* color_filename() treats this as an orphan file */
> +                       st.st_mode = 0;
> +
> +               if (!matched(result, name, st.st_mode))
> +                       continue;
> +
> +               add_wt_item(result, IS_UNMERGED, name, tag, &st);
> +       }
> +}
> +
> diff --git a/t/t7013-list-files.sh b/t/t7013-list-files.sh
> index 6b76d1f..7fe9673 100755
> --- a/t/t7013-list-files.sh
> +++ b/t/t7013-list-files.sh
> @@ -218,4 +218,39 @@ test_expect_success '--classify' '
>         )
>  '
>
> +test_expect_success 'list-files unmerged' '
> +       (
> +       add_stage() {
> +               echo "100644 $1 $2      $3" | git update-index --index-info
> +       }
> +       git init 3 &&
> +       cd 3 &&
> +       test_commit 1 &&
> +       SHA1=`echo 1 | git hash-object -w --stdin` &&

    SHA1=$(echo 1 | git hash-object -w --stdin) &&

> +       add_stage $SHA1 1 deleted-by-both &&
> +       add_stage $SHA1 2 added-by-us &&
> +       add_stage $SHA1 1 deleted-by-them &&
> +       add_stage $SHA1 2 deleted-by-them &&
> +       add_stage $SHA1 3 added-by-them &&
> +       add_stage $SHA1 3 deleted-by-us &&
> +       add_stage $SHA1 1 deleted-by-us &&
> +       add_stage $SHA1 2 added-by-both &&
> +       add_stage $SHA1 3 added-by-both &&
> +       add_stage $SHA1 1 modified-by-both &&
> +       add_stage $SHA1 2 modified-by-both &&
> +       add_stage $SHA1 3 modified-by-both &&
> +       git list-files -u >actual &&
> +       cat >expected <<-\EOF &&
> +       AA added-by-both
> +       UA added-by-them
> +       AU added-by-us
> +       DD deleted-by-both
> +       UD deleted-by-them
> +       DU deleted-by-us
> +       UU modified-by-both
> +       EOF
> +       test_cmp expected actual
> +       )
> +'
> +
>  test_done
> --
> 2.3.0.rc1.137.g477eb31

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 17/25] list-files: add file modification options -[admADM]
  2015-04-06 13:52 ` [PATCH 17/25] list-files: add file modification options -[admADM] Nguyễn Thái Ngọc Duy
@ 2015-04-06 21:34   ` Eric Sunshine
  0 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-04-06 21:34 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Mon, Apr 6, 2015 at 9:52 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/wt-status.c b/wt-status.c
> index cdbc8d7..ba9b56c 100644
> --- a/wt-status.c
> +++ b/wt-status.c
> @@ -537,9 +537,11 @@ static void wt_status_collect_changes_index(struct wt_status *s)
>         rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
>         rev.diffopt.format_callback = wt_status_collect_updated_cb;
>         rev.diffopt.format_callback_data = s;
> -       rev.diffopt.detect_rename = 1;
> -       rev.diffopt.rename_limit = 200;
> -       rev.diffopt.break_opt = 0;
> +       if (!s->no_rename) {

Double-negatives are difficult. Perhaps call this 'detect_rename'?

> +               rev.diffopt.detect_rename = 1;
> +               rev.diffopt.rename_limit = 200;
> +               rev.diffopt.break_opt = 0;
> +       }
>         copy_pathspec(&rev.prune_data, &s->pathspec);
>         run_diff_index(&rev, 1);
>  }
> diff --git a/wt-status.h b/wt-status.h
> index 283a9fe..dc94f35 100644
> --- a/wt-status.h
> +++ b/wt-status.h
> @@ -55,6 +55,7 @@ struct wt_status {
>         int relative_paths;
>         int submodule_summary;
>         int show_ignored_files;
> +       int no_rename;
>         enum untracked_status_type show_untracked_files;
>         const char *ignore_submodule_arg;
>         char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];
> --
> 2.3.0.rc1.137.g477eb31

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 18/25] list-files: delete redundant cached entries
  2015-04-06 13:52 ` [PATCH 18/25] list-files: delete redundant cached entries Nguyễn Thái Ngọc Duy
@ 2015-04-06 21:35   ` Eric Sunshine
  2015-04-08  2:39     ` Junio C Hamano
  0 siblings, 1 reply; 36+ messages in thread
From: Eric Sunshine @ 2015-04-06 21:35 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Mon, Apr 6, 2015 at 9:52 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> When both --cached and one of -amdAMD is used together we may have two
> entries of the same path, e.g. "  foo" and "MM foo". In this case it's
> pretty clear that "foo" must be tracked, no need to display "   foo".
> The new function does that.
>
> Helped-by: Eric Sunshine <sunshine@sunshineco.com>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/builtin/list-files.c b/builtin/list-files.c
> index 14ffd62..31c2336 100644
> --- a/builtin/list-files.c
> +++ b/builtin/list-files.c
> @@ -93,7 +93,10 @@ static int compare_item(const void *a_, const void *b_)
>  {
>         const struct item *a = a_;
>         const struct item *b = b_;
> -       return strcmp(a->path, b->path);
> +       int ret = strcmp(a->path, b->path);
> +       if (ret)
> +               return ret;
> +       return strncmp(a->tag, b->tag, 2);
>  }
>
>  static void free_item(struct item *item)
> @@ -132,7 +135,12 @@ static void remove_duplicates(struct item_list *list)
>         for (src = dst = 1; src < list->nr; src++) {
>                 if (!compare_item(list->items + dst - 1, list->items + src))
>                         free_item(list->items + src);
> -               else
> +               else if ((list->items[dst - 1].tag[0] == ' ' &&
> +                         list->items[dst - 1].tag[1] == ' ' &&
> +                         !strcmp(list->items[src].path, list->items[dst - 1].path))) {
> +                       free_item(list->items + dst - 1);
> +                       list->items[dst - 1] = list->items[src];

I was wondering if you could drop this backward-patching case by
having tag=="  " items sort after tag="xx" items and just fold out the
tag=="  " items normally in the preceding 'if', however, when I
started coding it, I found that the resulting code wasn't any more
pleasant.

> +               } else
>                         list->items[dst++] = list->items[src];
>         }
>         list->nr = dst;

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 20/25] list-files: preload index
  2015-04-06 13:52 ` [PATCH 20/25] list-files: preload index Nguyễn Thái Ngọc Duy
@ 2015-04-06 21:35   ` Eric Sunshine
  0 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-04-06 21:35 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Mon, Apr 6, 2015 at 9:52 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> Try to reduce refresh time. Note that we still need another
> read_cache() at top top, before parse_pathspec() because this

s/top top/the/top/

> *_SLASH_CHEAP needs the index loaded.
>
> One day read_index() should be improved to notice that the on-disk
> version is the same as the one in memory and skip I/O entirely..

s/\.\.$/./

> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  builtin/list-files.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/builtin/list-files.c b/builtin/list-files.c
> index 31c2336..948b8e6 100644
> --- a/builtin/list-files.c
> +++ b/builtin/list-files.c
> @@ -529,6 +529,7 @@ int cmd_list_files(int argc, const char **argv, const char *cmd_prefix)
>         recursive_pathspec.max_depth = -1;
>         finalize_colopts(&colopts, -1);
>
> +       read_cache_preload(&recursive_pathspec);
>         refresh_index(&the_index, REFRESH_QUIET | REFRESH_UNMERGED,
>                       &recursive_pathspec, NULL, NULL);
>
> --
> 2.3.0.rc1.137.g477eb31

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 25/25] list-files: documentation
  2015-04-06 13:52 ` [PATCH 25/25] list-files: documentation Nguyễn Thái Ngọc Duy
@ 2015-04-06 21:37   ` Eric Sunshine
  0 siblings, 0 replies; 36+ messages in thread
From: Eric Sunshine @ 2015-04-06 21:37 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Mon, Apr 6, 2015 at 9:52 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
> new file mode 100644
> index 0000000..9b9edce
> --- /dev/null
> +++ b/Documentation/git-list-files.txt
> @@ -0,0 +1,115 @@
> +git-list-files(1)
> +===============
> +
> +NAME
> +----
> +git-list-files - List files
> +
> +SYNOPSIS
> +--------
> +[verse]
> +'git list-files [options] [<pathspec>...]
> +
> +DESCRIPTION
> +-----------
> +List files (by default in current working directory) that are in the
> +index. Depending on the chosen options, maybe only modified files in
> +working tree are shown, or untracked files... The builtin alias "ls"
> +is set to "list-files".
> +
> +OPTIONS
> +-------
> +-c::
> +--cached::
> +       Show cached files (default)

Here and elsewhere: s/$/./

> +-d::
> +--deleted::
> +       Show deleted files in index, compared to HEAD
> +
> +-a::
> +--added::
> +       Show added files in index, compared to HEAD
> +
> +-m::
> +--modified::
> +       Show modified files in index, compared to HEAD. This implies
> +       --deleted and --added

s/--deleted/`--deleted`/
s/--added/`--added`/

> +-D::
> +--wt-deleted::
> +       Show deleted files in working directory
> +
> +-A::
> +--wt-added::
> +       Show added files in working directory
> +
> +-M::
> +--wt-modified::
> +       Show modified files in working directory. This implies
> +       --wt-deleted and --wt-added

s/--wt-deleted/`--wt-deleted`/
s/--wt-added/`--wt-added`/

> +-o::
> +--others::
> +       Show untracked files (and only unignored ones unless -i is

s/-i/`-i`/ ...or... s/-i/`--ignored`/

> +       specified)
> +
> +-i::
> +--ignored::
> +       Show only ignored files. When showing files in the index,
> +       print only those matched by an exclude pattern. When showing
> +       "other" files, show only those matched by an exclude pattern.
> +
> +-u::
> +--unmerged::
> +       Show unmerged files
> +
> +-F::
> +--classify::
> +       Append indicator (one of `*/=>@|&`, which is executable,
> +       directory, socket, Solaris door, symlink, fifo, or submodule
> +       respectively) to entries.
> +
> +--color[=<when>]::
> +--no-color::
> +       Color file names. The value must be `always`, `never`, or
> +       `auto`. `--no-color` is equivalent to
> +       `--color=never`. `--color` is equivalent to
> +       `--color=auto`. See configuration variable `color.list-files`

Is 'color.list-files' documented anywhere?

> +       for the default settings.
> +
> +--column[=<options>]::
> +--no-column::
> +-1::
> +       Display files in columns. See configuration variable column.ui

s/column.ui/`column.ui`/

> +       for option syntax. `--column` and `--no-column` without options
> +       are equivalent to 'always' and 'never' respectively.
> +       `-1` is a shortcut for --no-column.

s/--no-column/`--no-column`/

> +--max-depth=<depth>::
> +--recursive::
> +-R::
> +       For each <pathspec> given on command line, descend at most <depth>
> +       levels of directories. A negative value means no limit.
> +       This option is ignored if <pathspec> contains active wildcards.
> +       In other words if "a*" matches a directory named "a*",
> +       "*" is matched literally so --max-depth is still effective.

s/--max-depth/`--max-depth`/

> +       `-R` or `--recursive` is equivalent of `--max-depth=-1`
> +       (infinite recursion).  The default is `--max-depth=0`.
> +
> +--tag::
> +--no-tag::
> +       Usually when tags are displayed by the left of the file name if
> +       there are more than one file selection. Use either of these options
> +       to force always or never display tags.

This is somewhat difficult to parse. Perhaps it could be rephrased
something like this:

    If the disposition of listed files differs from one another, then
    tags ("D" deleted, "M" modified, etc.) are displayed in front of
    the file names; otherwise tags are suppressed. These options
    override the the behavior and explicitly show or suppress tags,
    respectively.

> +
> +<pathspec>::
> +       Files to show. :(glob) magic is enabled by default.
> +
> +SEE ALSO
> +--------
> +linkgit:git-ls-files[1]
> +
> +GIT
> +---
> +Part of the linkgit:git[1] suite
> --
> 2.3.0.rc1.137.g477eb31

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 18/25] list-files: delete redundant cached entries
  2015-04-06 21:35   ` Eric Sunshine
@ 2015-04-08  2:39     ` Junio C Hamano
  0 siblings, 0 replies; 36+ messages in thread
From: Junio C Hamano @ 2015-04-08  2:39 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Nguyễn Thái Ngọc Duy, Git List

Eric Sunshine <sunshine@sunshineco.com> writes:

> On Mon, Apr 6, 2015 at 9:52 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
>> When both --cached and one of -amdAMD is used together we may have two
>> entries of the same path, e.g. "  foo" and "MM foo". In this case it's
>> pretty clear that "foo" must be tracked, no need to display "   foo".
>> The new function does that.
>>
>> Helped-by: Eric Sunshine <sunshine@sunshineco.com>
>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
>> ---
>> diff --git a/builtin/list-files.c b/builtin/list-files.c
>> index 14ffd62..31c2336 100644
>> --- a/builtin/list-files.c
>> +++ b/builtin/list-files.c
>> @@ -93,7 +93,10 @@ static int compare_item(const void *a_, const void *b_)
>>  {
>>         const struct item *a = a_;
>>         const struct item *b = b_;
>> -       return strcmp(a->path, b->path);
>> +       int ret = strcmp(a->path, b->path);
>> +       if (ret)
>> +               return ret;
>> +       return strncmp(a->tag, b->tag, 2);
>>  }
>>
>>  static void free_item(struct item *item)
>> @@ -132,7 +135,12 @@ static void remove_duplicates(struct item_list *list)
>>         for (src = dst = 1; src < list->nr; src++) {
>>                 if (!compare_item(list->items + dst - 1, list->items + src))
>>                         free_item(list->items + src);
>> -               else
>> +               else if ((list->items[dst - 1].tag[0] == ' ' &&
>> +                         list->items[dst - 1].tag[1] == ' ' &&
>> +                         !strcmp(list->items[src].path, list->items[dst - 1].path))) {
>> +                       free_item(list->items + dst - 1);
>> +                       list->items[dst - 1] = list->items[src];
>
> I was wondering if you could drop this backward-patching case by
> having tag=="  " items sort after tag="xx" items and just fold out the
> tag=="  " items normally in the preceding 'if', however, when I
> started coding it, I found that the resulting code wasn't any more
> pleasant.


You may read from wt-status and then index (or the other way around)
into the set of files to be listed---instead of deduping at the end,
you should logically do "add in from index only for entries we did
not see in wt-status output".  So some deduping is necessary.

But I actually think that the worst aspect of the series this part
of the code shows is the same issue I raised in the previous review
round in the approach, which has not been addressed at all as far as
I can see in this round.

Why does tag[] record the semantic meaning in textual form?  Isn't
this a sympotom that shows the code is turning the information into
textual form way too early, which makes the code very unpleasant to
read and hard to maintain and modify.

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2015-04-08  2:39 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-06 13:52 [PATCH v2 00/25] list-files redesign Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 01/25] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 02/25] ls_colors.c: parse color.ls.* from config file Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 03/25] ls_colors.c: add a function to color a file name Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 04/25] ls_colors.c: highlight submodules like directories Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 05/25] list-files: command skeleton Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 06/25] list-files: show paths relative to cwd Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 07/25] list-files: add tag to each entry, filter duplicate tags Nguyễn Thái Ngọc Duy
2015-04-06 21:32   ` Eric Sunshine
2015-04-06 13:52 ` [PATCH 08/25] list-files: add --[no-]column, -C and -1 Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 09/25] list-files: add --max-depth, -R and default to --max-depth=0 Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 10/25] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 11/25] list-files: add --color Nguyễn Thái Ngọc Duy
2015-04-06 21:33   ` Eric Sunshine
2015-04-06 13:52 ` [PATCH 12/25] list-files: add -F/--classify Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 13/25] list-files: new indicator '&' for submodules when -F is used Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 14/25] list-files: add --cached and --others Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 15/25] list-files: add --ignored Nguyễn Thái Ngọc Duy
2015-04-06 21:34   ` Eric Sunshine
2015-04-06 13:52 ` [PATCH 16/25] list-files: add --unmerged Nguyễn Thái Ngọc Duy
2015-04-06 21:34   ` Eric Sunshine
2015-04-06 13:52 ` [PATCH 17/25] list-files: add file modification options -[admADM] Nguyễn Thái Ngọc Duy
2015-04-06 21:34   ` Eric Sunshine
2015-04-06 13:52 ` [PATCH 18/25] list-files: delete redundant cached entries Nguyễn Thái Ngọc Duy
2015-04-06 21:35   ` Eric Sunshine
2015-04-08  2:39     ` Junio C Hamano
2015-04-06 13:52 ` [PATCH 19/25] list-files: make alias 'ls' default to 'list-files' Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 20/25] list-files: preload index Nguyễn Thái Ngọc Duy
2015-04-06 21:35   ` Eric Sunshine
2015-04-06 13:52 ` [PATCH 21/25] list-files: reduce match_pathspec calls in matched() Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 22/25] list-files: only do diff that is actually useful Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 23/25] pathspec: move getenv() code out of prefix_pathspec() Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 24/25] list-files: make :(glob) pathspec default Nguyễn Thái Ngọc Duy
2015-04-06 13:52 ` [PATCH 25/25] list-files: documentation Nguyễn Thái Ngọc Duy
2015-04-06 21:37   ` Eric Sunshine
2015-04-06 13:58 ` [PATCH v2 00/25] list-files redesign Duy Nguyen

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).