]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/ls-tree.c
Merge branch 'rs/ls-tree-path-expansion-fix' into maint-2.39
[thirdparty/git.git] / builtin / ls-tree.c
index 35e793d4afc7f9b78cdf9b79445f14c667a5f429..b1f69fbe92d89704a5e7e11f8f560f65ef092216 100644 (file)
@@ -24,7 +24,6 @@ static struct pathspec pathspec;
 static int chomp_prefix;
 static const char *ls_tree_prefix;
 static const char *format;
-
 struct show_tree_data {
        unsigned mode;
        enum object_type type;
@@ -42,6 +41,8 @@ static enum ls_tree_cmdmode {
        MODE_DEFAULT = 0,
        MODE_LONG,
        MODE_NAME_ONLY,
+       MODE_NAME_STATUS,
+       MODE_OBJECT_ONLY,
 } cmdmode;
 
 static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
@@ -141,7 +142,7 @@ static int show_recursive(const char *base, size_t baselen, const char *pathname
 }
 
 static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
-                        const char *pathname, unsigned mode, void *context)
+                        const char *pathname, unsigned mode, void *context UNUSED)
 {
        int recurse = 0;
        struct strbuf sb = STRBUF_INIT;
@@ -169,99 +170,160 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
        return recurse;
 }
 
-static int show_default(struct show_tree_data *data)
-{
-       size_t baselen = data->base->len;
-
-       if (cmdmode == MODE_LONG) {
-               char size_text[24];
-               if (data->type == OBJ_BLOB) {
-                       unsigned long size;
-                       if (oid_object_info(the_repository, data->oid, &size) == OBJ_BAD)
-                               xsnprintf(size_text, sizeof(size_text), "BAD");
-                       else
-                               xsnprintf(size_text, sizeof(size_text),
-                                         "%" PRIuMAX, (uintmax_t)size);
-               } else {
-                       xsnprintf(size_text, sizeof(size_text), "-");
-               }
-               printf("%06o %s %s %7s\t", data->mode, type_name(data->type),
-               find_unique_abbrev(data->oid, abbrev), size_text);
-       } else {
-               printf("%06o %s %s\t", data->mode, type_name(data->type),
-               find_unique_abbrev(data->oid, abbrev));
-       }
-       baselen = data->base->len;
-       strbuf_addstr(data->base, data->pathname);
-       write_name_quoted_relative(data->base->buf,
-                                  chomp_prefix ? ls_tree_prefix : NULL, stdout,
-                                  line_termination);
-       strbuf_setlen(data->base, baselen);
-       return 1;
-}
-
-static int show_tree(const struct object_id *oid, struct strbuf *base,
-               const char *pathname, unsigned mode, void *context)
+static int show_tree_common(struct show_tree_data *data, int *recurse,
+                           const struct object_id *oid, struct strbuf *base,
+                           const char *pathname, unsigned mode)
 {
-       int recurse = 0;
-       size_t baselen;
        enum object_type type = object_type(mode);
-       struct show_tree_data data = {
-               .mode = mode,
-               .type = type,
-               .oid = oid,
-               .pathname = pathname,
-               .base = base,
-       };
+       int ret = -1;
+
+       *recurse = 0;
+       data->mode = mode;
+       data->type = type;
+       data->oid = oid;
+       data->pathname = pathname;
+       data->base = base;
 
        if (type == OBJ_BLOB) {
                if (ls_options & LS_TREE_ONLY)
-                       return 0;
+                       ret = 0;
        } else if (type == OBJ_TREE &&
                   show_recursive(base->buf, base->len, pathname)) {
-               recurse = READ_TREE_RECURSIVE;
+               *recurse = READ_TREE_RECURSIVE;
                if (!(ls_options & LS_SHOW_TREES))
-                       return recurse;
+                       ret = *recurse;
        }
 
-       if (cmdmode == MODE_NAME_ONLY) {
-               baselen = base->len;
-               strbuf_addstr(base, pathname);
-               write_name_quoted_relative(base->buf,
-                                          chomp_prefix ? ls_tree_prefix : NULL,
-                                          stdout, line_termination);
-               strbuf_setlen(base, baselen);
-               return recurse;
+       return ret;
+}
+
+static void show_tree_common_default_long(struct strbuf *base,
+                                         const char *pathname,
+                                         const size_t baselen)
+{
+       strbuf_addstr(base, pathname);
+       write_name_quoted_relative(base->buf,
+                                  chomp_prefix ? ls_tree_prefix : NULL, stdout,
+                                  line_termination);
+       strbuf_setlen(base, baselen);
+}
+
+static int show_tree_default(const struct object_id *oid, struct strbuf *base,
+                            const char *pathname, unsigned mode,
+                            void *context UNUSED)
+{
+       int early;
+       int recurse;
+       struct show_tree_data data = { 0 };
+
+       early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+       if (early >= 0)
+               return early;
+
+       printf("%06o %s %s\t", data.mode, type_name(data.type),
+              find_unique_abbrev(data.oid, abbrev));
+       show_tree_common_default_long(base, pathname, data.base->len);
+       return recurse;
+}
+
+static int show_tree_long(const struct object_id *oid, struct strbuf *base,
+                         const char *pathname, unsigned mode,
+                         void *context UNUSED)
+{
+       int early;
+       int recurse;
+       struct show_tree_data data = { 0 };
+       char size_text[24];
+
+       early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+       if (early >= 0)
+               return early;
+
+       if (data.type == OBJ_BLOB) {
+               unsigned long size;
+               if (oid_object_info(the_repository, data.oid, &size) == OBJ_BAD)
+                       xsnprintf(size_text, sizeof(size_text), "BAD");
+               else
+                       xsnprintf(size_text, sizeof(size_text),
+                                 "%" PRIuMAX, (uintmax_t)size);
+       } else {
+               xsnprintf(size_text, sizeof(size_text), "-");
        }
 
-       if (cmdmode == MODE_LONG ||
-               (!ls_options || (ls_options & LS_RECURSIVE)
-                || (ls_options & LS_SHOW_TREES)
-                || (ls_options & LS_TREE_ONLY)))
-                        show_default(&data);
+       printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
+              find_unique_abbrev(data.oid, abbrev), size_text);
+       show_tree_common_default_long(base, pathname, data.base->len);
+       return recurse;
+}
+
+static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
+                              const char *pathname, unsigned mode,
+                              void *context UNUSED)
+{
+       int early;
+       int recurse;
+       const size_t baselen = base->len;
+       struct show_tree_data data = { 0 };
+
+       early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+       if (early >= 0)
+               return early;
+
+       strbuf_addstr(base, pathname);
+       write_name_quoted_relative(base->buf,
+                                  chomp_prefix ? ls_tree_prefix : NULL,
+                                  stdout, line_termination);
+       strbuf_setlen(base, baselen);
+       return recurse;
+}
+
+static int show_tree_object(const struct object_id *oid, struct strbuf *base,
+                           const char *pathname, unsigned mode,
+                           void *context UNUSED)
+{
+       int early;
+       int recurse;
+       struct show_tree_data data = { 0 };
+
+       early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+       if (early >= 0)
+               return early;
 
+       printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
        return recurse;
 }
 
 struct ls_tree_cmdmode_to_fmt {
        enum ls_tree_cmdmode mode;
        const char *const fmt;
+       read_tree_fn_t fn;
 };
 
 static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
        {
                .mode = MODE_DEFAULT,
                .fmt = "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
+               .fn = show_tree_default,
        },
        {
                .mode = MODE_LONG,
                .fmt = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
+               .fn = show_tree_long,
        },
        {
                .mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
                .fmt = "%(path)",
+               .fn = show_tree_name_only,
+       },
+       {
+               .mode = MODE_OBJECT_ONLY,
+               .fmt = "%(objectname)",
+               .fn = show_tree_object
+       },
+       {
+               /* fallback */
+               .fn = show_tree_default,
        },
-       { 0 },
 };
 
 int cmd_ls_tree(int argc, const char **argv, const char *prefix)
@@ -269,7 +331,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
        struct object_id oid;
        struct tree *tree;
        int i, full_tree = 0;
-       read_tree_fn_t fn = show_tree;
+       read_tree_fn_t fn = NULL;
        const struct option ls_tree_options[] = {
                OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
                        LS_TREE_ONLY),
@@ -284,7 +346,9 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
                OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
                            MODE_NAME_ONLY),
                OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
-                           MODE_NAME_ONLY),
+                           MODE_NAME_STATUS),
+               OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
+                           MODE_OBJECT_ONLY),
                OPT_SET_INT(0, "full-name", &chomp_prefix,
                            N_("use full path names"), 0),
                OPT_BOOL(0, "full-tree", &full_tree,
@@ -296,10 +360,11 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
                OPT__ABBREV(&abbrev),
                OPT_END()
        };
+       struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
 
        git_config(git_default_config, NULL);
        ls_tree_prefix = prefix;
-       if (prefix && *prefix)
+       if (prefix)
                chomp_prefix = strlen(prefix);
 
        argc = parse_options(argc, argv, prefix, ls_tree_options,
@@ -308,6 +373,14 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
                ls_tree_prefix = prefix = NULL;
                chomp_prefix = 0;
        }
+       /*
+        * We wanted to detect conflicts between --name-only and
+        * --name-status, but once we're done with that subsequent
+        * code should only need to check the primary name.
+        */
+       if (cmdmode == MODE_NAME_STATUS)
+               cmdmode = MODE_NAME_ONLY;
+
        /* -d -r should imply -t, but -d by itself should not have to. */
        if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
            ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
@@ -342,18 +415,19 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
         * The generic show_tree_fmt() is slower than show_tree(), so
         * take the fast path if possible.
         */
-       if (format) {
-               struct ls_tree_cmdmode_to_fmt *m2f;
-
-               fn = show_tree_fmt;
-               for (m2f = ls_tree_cmdmode_format; m2f->fmt; m2f++) {
-                       if (strcmp(format, m2f->fmt))
-                               continue;
-
+       while (m2f) {
+               if (!m2f->fmt) {
+                       fn = format ? show_tree_fmt : show_tree_default;
+               } else if (format && !strcmp(format, m2f->fmt)) {
                        cmdmode = m2f->mode;
-                       fn = show_tree;
-                       break;
+                       fn = m2f->fn;
+               } else if (!format && cmdmode == m2f->mode) {
+                       fn = m2f->fn;
+               } else {
+                       m2f++;
+                       continue;
                }
+               break;
        }
 
        return !!read_tree(the_repository, tree, &pathspec, fn, NULL);