Skip to content

Commit cab851c

Browse files
dyronegitster
authored andcommitted
ls-tree: support --object-only option for "git-ls-tree"
'--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 Helped-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Teng Long <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 455923e commit cab851c

File tree

4 files changed

+36
-4
lines changed

4 files changed

+36
-4
lines changed

Documentation/git-ls-tree.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SYNOPSIS
1010
--------
1111
[verse]
1212
'git ls-tree' [-d] [-r] [-t] [-l] [-z]
13-
[--name-only] [--name-status] [--full-name] [--full-tree] [--abbrev[=<n>]] [--format=<format>]
13+
[--name-only] [--name-status] [--object-only] [--full-name] [--full-tree] [--abbrev[=<n>]] [--format=<format>]
1414
<tree-ish> [<path>...]
1515

1616
DESCRIPTION
@@ -59,6 +59,15 @@ OPTIONS
5959
--name-only::
6060
--name-status::
6161
List only filenames (instead of the "long" output), one per line.
62+
Cannot be combined with `--object-only`.
63+
64+
--object-only::
65+
List only names of the objects, one per line. Cannot be combined
66+
with `--name-only` or `--name-status`.
67+
This is equivalent to specifying `--format='%(objectname)'`, but
68+
for both this option and that exact format the command takes a
69+
hand-optimized codepath instead of going through the generic
70+
formatting mechanism.
6271

6372
--abbrev[=<n>]::
6473
Instead of showing the full 40-byte hexadecimal object

builtin/ls-tree.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ static struct pathspec pathspec;
2424
static int chomp_prefix;
2525
static const char *ls_tree_prefix;
2626
static const char *format;
27-
2827
struct show_tree_data {
2928
unsigned mode;
3029
enum object_type type;
@@ -42,6 +41,7 @@ static enum ls_tree_cmdmode {
4241
MODE_DEFAULT = 0,
4342
MODE_LONG,
4443
MODE_NAME_ONLY,
44+
MODE_OBJECT_ONLY,
4545
} cmdmode;
4646

4747
static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
@@ -227,6 +227,11 @@ static int show_tree(const struct object_id *oid, struct strbuf *base,
227227
return recurse;
228228
}
229229

230+
if (cmdmode == MODE_OBJECT_ONLY) {
231+
printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
232+
return recurse;
233+
}
234+
230235
if (cmdmode == MODE_NAME_ONLY) {
231236
baselen = base->len;
232237
strbuf_addstr(base, pathname);
@@ -264,6 +269,10 @@ static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
264269
.mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
265270
.fmt = "%(path)",
266271
},
272+
{
273+
.mode = MODE_OBJECT_ONLY,
274+
.fmt = "%(objectname)",
275+
},
267276
{ 0 },
268277
};
269278

@@ -288,6 +297,8 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
288297
MODE_NAME_ONLY),
289298
OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
290299
MODE_NAME_ONLY),
300+
OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
301+
MODE_OBJECT_ONLY),
291302
OPT_SET_INT(0, "full-name", &chomp_prefix,
292303
N_("use full path names"), 0),
293304
OPT_BOOL(0, "full-tree", &full_tree,

t/t3103-ls-tree-misc.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ test_expect_success 'ls-tree fails with non-zero exit code on broken tree' '
2525

2626
for opts in \
2727
"--name-only --long" \
28-
"--name-status --long"
28+
"--name-status --long" \
29+
"--name-only --object-only" \
30+
"--name-status --object-only" \
31+
"--object-only --long" \
32+
"--object-only --format"
2933
do
3034
test_expect_success "usage: incompatible options: $opts" '
3135
test_expect_code 129 git ls-tree $opts $tree
3236
'
3337
done
34-
3538
test_done

t/t3104-ls-tree-format.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ test_ls_tree_format \
4949
"%(path)" \
5050
"--name-only"
5151

52+
test_ls_tree_format \
53+
"%(objectname)" \
54+
"--object-only"
55+
56+
test_ls_tree_format \
57+
"%(objectname)" \
58+
"--object-only --abbrev" \
59+
"--abbrev"
60+
5261
test_ls_tree_format \
5362
"%(objectmode) %(objecttype) %(objectname)%x09%(path)" \
5463
"-t" \

0 commit comments

Comments
 (0)