@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git ls-tree' [-d] [-r] [-t] [-l] [-z]
- [--name-only] [--name-status] [--full-name] [--full-tree] [--abbrev[=<n>]] [--format=<format>]
+ [--name-only] [--name-status] [--object-only] [--full-name] [--full-tree] [--abbrev[=<n>]] [--format=<format>]
<tree-ish> [<path>...]
DESCRIPTION
@@ -59,6 +59,15 @@ OPTIONS
--name-only::
--name-status::
List only filenames (instead of the "long" output), one per line.
+ Cannot be combined with `--object-only`.
+
+--object-only::
+ List only names of the objects, one per line. Cannot be combined
+ with `--name-only` or `--name-status`.
+ This is equivalent to specifying `--format='%(objectname)'`, but
+ for both this option and that exact format the command takes a
+ hand-optimized codepath instead of going through the generic
+ formatting mechanism.
--abbrev[=<n>]::
Instead of showing the full 40-byte hexadecimal object
@@ -34,6 +34,7 @@ static const char *format;
static const char *default_format = "%(objectmode) %(objecttype) %(objectname)%x09%(path)";
static const char *long_format = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)";
static const char *name_only_format = "%(path)";
+static const char *object_only_format = "%(objectname)";
struct show_tree_data {
unsigned mode;
enum object_type type;
@@ -51,6 +52,7 @@ static const char * const ls_tree_usage[] = {
static enum ls_tree_cmdmode {
MODE_LONG = 1,
MODE_NAME_ONLY,
+ MODE_OBJECT_ONLY,
} cmdmode;
static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
@@ -125,7 +127,10 @@ static int parse_shown_fields(unsigned int *shown_fields)
*shown_fields = FIELD_PATH_NAME;
return 0;
}
-
+ if (cmdmode == MODE_OBJECT_ONLY) {
+ *shown_fields = FIELD_OBJECT_NAME;
+ return 0;
+ }
if (!ls_options || (ls_options & LS_RECURSIVE)
|| (ls_options & LS_SHOW_TREES)
|| (ls_options & LS_TREE_ONLY))
@@ -254,6 +259,11 @@ static int show_tree(const struct object_id *oid, struct strbuf *base,
return recurse;
}
+ if (shown_fields == FIELD_OBJECT_NAME) {
+ printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
+ return recurse;
+ }
+
if (shown_fields == FIELD_PATH_NAME) {
baselen = base->len;
strbuf_addstr(base, pathname);
@@ -292,6 +302,8 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
MODE_NAME_ONLY),
OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
MODE_NAME_ONLY),
+ 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,
@@ -360,6 +372,9 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
} else if (format && (!strcmp(format, name_only_format))) {
shown_fields = FIELD_PATH_NAME;
fn = show_tree;
+ } else if (format && (!strcmp(format, object_only_format))) {
+ shown_fields = FIELD_OBJECT_NAME;
+ fn = show_tree;
} else if (format)
fn = show_tree_fmt;
@@ -25,11 +25,14 @@ test_expect_success 'ls-tree fails with non-zero exit code on broken tree' '
for opts in \
"--name-only --long" \
- "--name-status --long"
+ "--name-status --long" \
+ "--name-only --object-only" \
+ "--name-status --object-only" \
+ "--object-only --long" \
+ "--object-only --format"
do
test_expect_success "usage: incompatible options: $opts" '
test_expect_code 129 git ls-tree $opts $tree
'
done
-
test_done
@@ -49,6 +49,15 @@ test_ls_tree_format \
"%(path)" \
"--name-only"
+test_ls_tree_format \
+ "%(objectname)" \
+ "--object-only"
+
+test_ls_tree_format \
+ "%(objectname)" \
+ "--object-only --abbrev" \
+ "--abbrev"
+
test_ls_tree_format \
"%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
"-t" \
'--object-only' is an alias for '--format=%(objectname)'. It cannot be used together other format-altering options like '--name-only', '--long' or '--format', they are mutually exclusive. The "--name-only" option outputs <filepath> only. Likewise, <objectName> is another high frequency used field, so implement '--object-only' option will bring intuitive and clear semantics for this scenario. Using '--format=%(objectname)' we can achieve a similar effect, but the former is with a lower learning cost(without knowing the format requirement of '--format' option). Even so, if a user is prefer to use "--format=%(objectname)", this is entirely welcome because they are not only equivalent in function, but also have almost identical performance. The reason is this commit also add the specific of "--format=%(objectname)" to the current fast-pathes (builtin formats) to avoid running unnecessary parsing mechanisms. The following performance benchmarks are based on torvalds/linux.git: When hit the fast-path: Benchmark 1: /opt/git/ls-tree-oid-only/bin/git ls-tree -r --object-only HEAD Time (mean ± σ): 83.6 ms ± 2.0 ms [User: 59.4 ms, System: 24.1 ms] Range (min … max): 80.4 ms … 87.2 ms 35 runs Benchmark 1: /opt/git/ls-tree-oid-only/bin/git ls-tree -r --format='%(objectname)' HEAD Time (mean ± σ): 84.1 ms ± 1.8 ms [User: 61.7 ms, System: 22.3 ms] Range (min … max): 80.9 ms … 87.5 ms 35 runs But for a customized format, it will be slower: Benchmark 1: /opt/git/ls-tree-oid-only/bin/git ls-tree -r --format='oid: %(objectname)' HEAD Time (mean ± σ): 96.5 ms ± 2.5 ms [User: 72.9 ms, System: 23.5 ms] Range (min … max): 93.1 ms … 104.1 ms 31 runs Signed-off-by: Teng Long <dyroneteng@gmail.com> --- Documentation/git-ls-tree.txt | 11 ++++++++++- builtin/ls-tree.c | 17 ++++++++++++++++- t/t3103-ls-tree-misc.sh | 7 +++++-- t/t3104-ls-tree-format.sh | 9 +++++++++ 4 files changed, 40 insertions(+), 4 deletions(-)