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 <avarab@gmail.com>
Signed-off-by: Teng Long <dyroneteng@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
			
			
This commit is contained in:
		
				
					committed by
					
						
						Junio C Hamano
					
				
			
			
				
	
			
			
			
						parent
						
							455923e0a1
						
					
				
				
					commit
					cab851c2f8
				
			@ -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
 | 
			
		||||
 | 
			
		||||
@ -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,7 @@ static enum ls_tree_cmdmode {
 | 
			
		||||
	MODE_DEFAULT = 0,
 | 
			
		||||
	MODE_LONG,
 | 
			
		||||
	MODE_NAME_ONLY,
 | 
			
		||||
	MODE_OBJECT_ONLY,
 | 
			
		||||
} cmdmode;
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
			return recurse;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cmdmode == MODE_OBJECT_ONLY) {
 | 
			
		||||
		printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
 | 
			
		||||
		return recurse;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cmdmode == MODE_NAME_ONLY) {
 | 
			
		||||
		baselen = base->len;
 | 
			
		||||
		strbuf_addstr(base, pathname);
 | 
			
		||||
@ -264,6 +269,10 @@ static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
 | 
			
		||||
		.mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
 | 
			
		||||
		.fmt = "%(path)",
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		.mode = MODE_OBJECT_ONLY,
 | 
			
		||||
		.fmt = "%(objectname)",
 | 
			
		||||
	},
 | 
			
		||||
	{ 0 },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -288,6 +297,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,
 | 
			
		||||
 | 
			
		||||
@ -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" \
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user