Diffs from patch v5: * Let "write_name_quoted_relative" support two terminations, they are "CQ_NO_TERMINATOR_C_QUOTED" and "CQ_NO_TERMINATOR_AS_IS" (They are used to let the function write "name" at a 'c_quoted' way or just 'as-is', but without print a terminator). * Rename "follow" to "interspace" (Representing whether any further output needs an inter-field space). * Nits fixed. Many thanks to Junio and Ævar for your help and patient explanation. I noticed Ævar suggest the solution with using `--format`, but in this patch, the current approach continues. If this part of code needs to be improved or we want to support "--format" in "ls-tree" in the future, I'm more than glad to continue to contribute. Thanks. Teng Long (1): ls-tree.c: support `--object-only` option for "git-ls-tree" Documentation/git-ls-tree.txt | 7 +- builtin/ls-tree.c | 131 ++++++++++++++++++++++++---------- quote.c | 8 +-- quote.h | 19 +++++ t/t3103-ls-tree-misc.sh | 8 +++ t/t3104-ls-tree-oid.sh | 51 +++++++++++++ 6 files changed, 183 insertions(+), 41 deletions(-) create mode 100755 t/t3104-ls-tree-oid.sh Range-diff against v5: 1: 38d55a878c ! 1: 2e449d1c79 ls-tree.c: support `--object-only` option for "git-ls-tree" @@ builtin/ls-tree.c -#define LS_SHOW_TREES 4 -#define LS_NAME_ONLY 8 -#define LS_SHOW_SIZE 16 -+#define LS_TREE_ONLY 1 << 1 -+#define LS_SHOW_TREES 1 << 2 -+#define LS_NAME_ONLY 1 << 3 -+#define LS_SHOW_SIZE 1 << 4 -+#define LS_OBJECT_ONLY 1 << 5 ++#define LS_TREE_ONLY (1 << 1) ++#define LS_SHOW_TREES (1 << 2) ++#define LS_NAME_ONLY (1 << 3) ++#define LS_SHOW_SIZE (1 << 4) ++#define LS_OBJECT_ONLY (1 << 5) static int abbrev; static int ls_options; static struct pathspec pathspec; static int chomp_prefix; static const char *ls_tree_prefix; -+static unsigned int shown_bits = 0; -+#define SHOW_DEFAULT 29 /* 11101 size is not shown to output by default */ -+#define SHOW_MODE 1 << 4 -+#define SHOW_TYPE 1 << 3 -+#define SHOW_OBJECT_NAME 1 << 2 -+#define SHOW_SIZE 1 << 1 ++static unsigned int shown_bits; +#define SHOW_FILE_NAME 1 ++#define SHOW_SIZE (1 << 1) ++#define SHOW_OBJECT_NAME (1 << 2) ++#define SHOW_TYPE (1 << 3) ++#define SHOW_MODE (1 << 4) ++#define SHOW_DEFAULT 29 /* 11101 size is not shown to output by default */ static const char * const ls_tree_usage[] = { N_("git ls-tree [<options>] <tree-ish> [<path>...]"), @@ builtin/ls-tree.c + MODE_UNSPECIFIED = 0, + MODE_NAME_ONLY, + MODE_OBJECT_ONLY, -+ MODE_LONG ++ MODE_LONG, +}; + +static int cmdmode = MODE_UNSPECIFIED; @@ builtin/ls-tree.c: static int show_tree(const struct object_id *oid, struct strb { int retval = 0; int baselen; -+ int follow = 0; ++ int interspace = 0; const char *type = blob_type; if (S_ISGITLINK(mode)) { @@ builtin/ls-tree.c: static int show_tree(const struct object_id *oid, struct strb - find_unique_abbrev(oid, abbrev), - size_text); + if (shown_bits & SHOW_MODE) { -+ printf("%06o",mode); -+ follow = 1; ++ printf("%06o", mode); ++ interspace = 1; + } + if (shown_bits & SHOW_TYPE) { -+ printf("%s%s", follow == 1 ? " " : "", type); -+ follow = 1; ++ printf("%s%s", interspace ? " " : "", type); ++ interspace = 1; + } + if (shown_bits & SHOW_OBJECT_NAME) { -+ printf("%s%s", follow == 1 ? " " : "", ++ printf("%s%s", interspace ? " " : "", + find_unique_abbrev(oid, abbrev)); + if (!(shown_bits ^ SHOW_OBJECT_NAME)) -+ printf("%c", line_termination); -+ follow = 1; ++ goto LINE_FINISH; ++ interspace = 1; + } + if (shown_bits & SHOW_SIZE) { + char size_text[24]; @@ builtin/ls-tree.c: static int show_tree(const struct object_id *oid, struct strb - printf("%06o %s %s\t", mode, type, - find_unique_abbrev(oid, abbrev)); + xsnprintf(size_text, sizeof(size_text), "-"); -+ printf("%s%7s", follow == 1 ? " " : "", size_text); -+ follow = 1; ++ printf("%s%7s", interspace ? " " : "", size_text); ++ interspace = 1; + } + if (shown_bits & SHOW_FILE_NAME) { -+ if (follow) ++ if (interspace) + printf("\t"); + baselen = base->len; + strbuf_addstr(base, pathname); + write_name_quoted_relative(base->buf, + chomp_prefix ? ls_tree_prefix : NULL, -+ stdout, line_termination); ++ stdout, ++ line_termination ++ ? CQ_NO_TERMINATOR_C_QUOTED ++ : CQ_NO_TERMINATOR_AS_IS); + strbuf_setlen(base, baselen); } - baselen = base->len; @@ builtin/ls-tree.c: static int show_tree(const struct object_id *oid, struct strb - chomp_prefix ? ls_tree_prefix : NULL, - stdout, line_termination); - strbuf_setlen(base, baselen); ++ ++LINE_FINISH: ++ putchar(line_termination); return retval; } @@ builtin/ls-tree.c: int cmd_ls_tree(int argc, const char **argv, const char *pref * show_recursive() rolls its own matching code and is * generally ignorant of 'struct pathspec'. The magic mask + ## quote.c ## +@@ quote.c: void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, + + void write_name_quoted(const char *name, FILE *fp, int terminator) + { +- if (terminator) { ++ if (0 < terminator || terminator == CQ_NO_TERMINATOR_C_QUOTED) + quote_c_style(name, NULL, fp, 0); +- } else { ++ else + fputs(name, fp); +- } +- fputc(terminator, fp); ++ if (0 <= terminator) ++ fputc(terminator, fp); + } + + void write_name_quoted_relative(const char *name, const char *prefix, + + ## quote.h ## +@@ quote.h: int unquote_c_style(struct strbuf *, const char *quoted, const char **endp); + #define CQUOTE_NODQ 01 + size_t quote_c_style(const char *name, struct strbuf *, FILE *, unsigned); + void quote_two_c_style(struct strbuf *, const char *, const char *, unsigned); ++/* ++ * Write a name, typically a filename, followed by a terminator that ++ * separates it from what comes next. ++ * When terminator is NUL, the name is given as-is. Otherwise, the ++ * name is c-quoted, suitable for text output. HT and LF are typical ++ * values used for the terminator, but other positive values are possible. ++ * ++ * In addition to non-negative values two special values in terminator ++ * are possible. ++ * ++ * -1: show the name c-quoted, without adding any terminator. ++ * -2: show the name as-is, without adding any terminator. ++ */ ++#define CQ_NO_TERMINATOR_C_QUOTED (-1) ++#define CQ_NO_TERMINATOR_AS_IS (-2) + + void write_name_quoted(const char *name, FILE *, int terminator); ++/* ++ * Similar to the above, but the name is first made relative to the prefix ++ * before being shown. ++ */ + void write_name_quoted_relative(const char *name, const char *prefix, + FILE *fp, int terminator); + + ## t/t3103-ls-tree-misc.sh ## @@ t/t3103-ls-tree-misc.sh: test_expect_success 'ls-tree fails with non-zero exit code on broken tree' ' test_must_fail git ls-tree -r HEAD -- 2.33.1.10.g5f17c1a2c1.dirty