Re: [PATCH v2 3/3] show-ref: add --symbolic-name option

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Patrick,

On 10 Apr 2024, at 2:53, Patrick Steinhardt wrote:

> On Mon, Apr 08, 2024 at 05:38:13PM +0000, John Cai via GitGitGadget wrote:
>> From: John Cai <johncai86@xxxxxxxxx>
>>
>> For reftable development, it would be handy to have a tool to provide
>> the direct value of any ref whether it be a symbolic ref or not.
>> Currently there is git-symbolic-ref, which only works for symbolic refs,
>> and git-rev-parse, which will resolve the ref. Let's teach show-ref a
>> --symbolic-name option that will cause git-show-ref(1) to print out the
>> value symbolic references points to.
>
> I think it was Peff who shared a way to achieve this without actually
> introducing a new option via `git for-each-ref --format=`. Can we maybe
> provide some benchmarks to demonstrate that this variant is preferable
> over what's already possible?

Yes, it would be better to not introduce a new option. I've done a quick
benchmark including my changes to add the unresolved symref to the iterator, and
some changes to integrate this into ref-filter.c. Here are the results:

$ hyperfine --warmup 5 "git for-each-ref \
--format='%(refname) %(objectname) %(symref)'" "./git for-each-ref \
--format='%(refname) %(objectname) %(symref)'"

Benchmark 1: git for-each-ref --format='%(refname) %(objectname) %(symref)'
  Time (mean ± σ):     213.5 ms ±   9.9 ms    [User: 7.5 ms, System: 14.3 ms]
  Range (min … max):   202.7 ms … 236.3 ms    14 runs

Benchmark 2: ./git for-each-ref --format='%(refname) %(objectname) %(symref)'
  Time (mean ± σ):      10.8 ms ±   1.3 ms    [User: 4.4 ms, System: 6.2 ms]
  Range (min … max):     9.5 ms …  17.5 ms    189 runs

Summary
  ./git for-each-ref --format='%(refname) %(objectname) %(symref)' ran
   19.72 ± 2.62 times faster than git for-each-ref --format='%(refname) %(objectname) %(symref)'

It looks like this gives us a nice speedup. I will send up a new version that improves git-for-each-ref
instead.

thanks
John

>
> Patrick
>
>> Signed-off-by: John Cai <johncai86@xxxxxxxxx>
>> ---
>>  Documentation/git-show-ref.txt | 21 ++++++++++++++++++-
>>  builtin/show-ref.c             | 38 ++++++++++++++++++++++++----------
>>  refs.c                         |  6 ++++++
>>  refs.h                         |  2 +-
>>  t/t1403-show-ref.sh            | 20 ++++++++++++++++++
>>  5 files changed, 74 insertions(+), 13 deletions(-)
>>
>> diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
>> index ba757470059..9627b34b37f 100644
>> --- a/Documentation/git-show-ref.txt
>> +++ b/Documentation/git-show-ref.txt
>> @@ -10,7 +10,7 @@ SYNOPSIS
>>  [verse]
>>  'git show-ref' [--head] [-d | --dereference]
>>  	     [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]
>> -	     [--heads] [--] [<pattern>...]
>> +	     [--heads] [--symbolic-name] [--] [<pattern>...]
>>  'git show-ref' --verify [-q | --quiet] [-d | --dereference]
>>  	     [-s | --hash[=<n>]] [--abbrev[=<n>]]
>>  	     [--] [<ref>...]
>> @@ -58,6 +58,11 @@ OPTIONS
>>  	Dereference tags into object IDs as well. They will be shown with `^{}`
>>  	appended.
>>
>> +--symbolic-name::
>> +
>> +	Print out the value the reference points to without dereferencing. This
>> +	is useful to know the reference that a symbolic ref is pointing to.
>> +
>>  -s::
>>  --hash[=<n>]::
>>
>> @@ -146,6 +151,20 @@ $ git show-ref --heads --hash
>>  ...
>>  -----------------------------------------------------------------------------
>>
>> +When using `--symbolic-name`, the output is in the format:
>> +
>> +-----------
>> +<oid> SP <ref> SP <symbolic-name>
>> +-----------
>> +
>> +For example,
>> +
>> +-----------------------------------------------------------------------------
>> +$ git show-ref --symbolic-name
>> +b75428bae1d090f60bdd4b67185f814bc8f0819d refs/heads/SYMBOLIC_REF ref:refs/heads/main
>> +...
>> +-----------------------------------------------------------------------------
>> +
>>  EXAMPLES
>>  --------
>>
>> diff --git a/builtin/show-ref.c b/builtin/show-ref.c
>> index 1c15421e600..1d681505eac 100644
>> --- a/builtin/show-ref.c
>> +++ b/builtin/show-ref.c
>> @@ -12,7 +12,7 @@
>>  static const char * const show_ref_usage[] = {
>>  	N_("git show-ref [--head] [-d | --dereference]\n"
>>  	   "             [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags]\n"
>> -	   "             [--heads] [--] [<pattern>...]"),
>> +	   "             [--heads] [--symbolic-name] [--] [<pattern>...]"),
>>  	N_("git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
>>  	   "             [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
>>  	   "             [--] [<ref>...]"),
>> @@ -26,10 +26,13 @@ struct show_one_options {
>>  	int hash_only;
>>  	int abbrev;
>>  	int deref_tags;
>> +	int symbolic_name;
>>  };
>>
>>  static void show_one(const struct show_one_options *opts,
>> -		     const char *refname, const struct object_id *oid)
>> +		     const char *refname,
>> +		     const char *referent,
>> +		     const struct object_id *oid, const int is_symref)
>>  {
>>  	const char *hex;
>>  	struct object_id peeled;
>> @@ -44,7 +47,9 @@ static void show_one(const struct show_one_options *opts,
>>  	hex = repo_find_unique_abbrev(the_repository, oid, opts->abbrev);
>>  	if (opts->hash_only)
>>  		printf("%s\n", hex);
>> -	else
>> +	else if (opts->symbolic_name & is_symref) {
>> +		printf("%s %s ref:%s\n", hex, refname, referent);
>> +	} else
>>  		printf("%s %s\n", hex, refname);
>>
>>  	if (!opts->deref_tags)
>> @@ -63,8 +68,11 @@ struct show_ref_data {
>>  	int show_head;
>>  };
>>
>> -static int show_ref(const char *refname, const struct object_id *oid,
>> -		    int flag UNUSED, void *cbdata)
>> +static int show_ref_referent(struct repository *repo UNUSED,
>> +			     const char *refname,
>> +			     const char *referent,
>> +			     const struct object_id *oid,
>> +			     int flag, void *cbdata)
>>  {
>>  	struct show_ref_data *data = cbdata;
>>
>> @@ -91,11 +99,17 @@ static int show_ref(const char *refname, const struct object_id *oid,
>>  match:
>>  	data->found_match++;
>>
>> -	show_one(data->show_one_opts, refname, oid);
>> +	show_one(data->show_one_opts, refname, referent, oid, flag & REF_ISSYMREF);
>>
>>  	return 0;
>>  }
>>
>> +static int show_ref(const char *refname, const struct object_id *oid,
>> +		    int flag, void *cbdata)
>> +{
>> +	return show_ref_referent(NULL, refname, NULL, oid, flag, cbdata);
>> +}
>> +
>>  static int add_existing(const char *refname,
>>  			const struct object_id *oid UNUSED,
>>  			int flag UNUSED, void *cbdata)
>> @@ -171,10 +185,11 @@ static int cmd_show_ref__verify(const struct show_one_options *show_one_opts,
>>
>>  	while (*refs) {
>>  		struct object_id oid;
>> +		int flags = 0;
>>
>>  		if ((starts_with(*refs, "refs/") || refname_is_safe(*refs)) &&
>> -		    !read_ref(*refs, &oid)) {
>> -			show_one(show_one_opts, *refs, &oid);
>> +		    !read_ref_full(*refs, 0, &oid, &flags)) {
>> +			show_one(show_one_opts, *refs, NULL, &oid, flags & REF_ISSYMREF);
>>  		}
>>  		else if (!show_one_opts->quiet)
>>  			die("'%s' - not a valid ref", *refs);
>> @@ -208,11 +223,11 @@ static int cmd_show_ref__patterns(const struct patterns_options *opts,
>>  		head_ref(show_ref, &show_ref_data);
>>  	if (opts->heads_only || opts->tags_only) {
>>  		if (opts->heads_only)
>> -			for_each_fullref_in("refs/heads/", show_ref, &show_ref_data);
>> +			for_each_ref_all("refs/heads/", show_ref_referent, &show_ref_data);
>>  		if (opts->tags_only)
>> -			for_each_fullref_in("refs/tags/", show_ref, &show_ref_data);
>> +			for_each_ref_all("refs/tags/", show_ref_referent, &show_ref_data);
>>  	} else {
>> -		for_each_ref(show_ref, &show_ref_data);
>> +		for_each_ref_all("", show_ref_referent, &show_ref_data);
>>  	}
>>  	if (!show_ref_data.found_match)
>>  		return 1;
>> @@ -289,6 +304,7 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
>>  		OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with heads)")),
>>  		OPT_BOOL(0, "heads", &patterns_opts.heads_only, N_("only show heads (can be combined with tags)")),
>>  		OPT_BOOL(0, "exists", &exists, N_("check for reference existence without resolving")),
>> +		OPT_BOOL(0, "symbolic-name", &show_one_opts.symbolic_name, N_("print out symbolic reference values")),
>>  		OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
>>  			    "requires exact ref path")),
>>  		OPT_HIDDEN_BOOL('h', NULL, &patterns_opts.show_head,
>> diff --git a/refs.c b/refs.c
>> index 77ae38ea214..9488ad9594d 100644
>> --- a/refs.c
>> +++ b/refs.c
>> @@ -1734,6 +1734,12 @@ int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_dat
>>  				    DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
>>  }
>>
>> +int for_each_ref_all(const char *prefix, each_repo_ref_fn fn, void *cb_data)
>> +{
>> +	return do_for_each_repo_ref(the_repository, prefix, fn, 0,
>> +				    0, cb_data);
>> +}
>> +
>>  int for_each_namespaced_ref(const char **exclude_patterns,
>>  			    each_ref_fn fn, void *cb_data)
>>  {
>> diff --git a/refs.h b/refs.h
>> index 23e5aaba2e9..54b459375be 100644
>> --- a/refs.h
>> +++ b/refs.h
>> @@ -337,7 +337,6 @@ int refs_for_each_branch_ref(struct ref_store *refs,
>>  			     each_ref_fn fn, void *cb_data);
>>  int refs_for_each_remote_ref(struct ref_store *refs,
>>  			     each_ref_fn fn, void *cb_data);
>> -
>>  /* just iterates the head ref. */
>>  int head_ref(each_ref_fn fn, void *cb_data);
>>
>> @@ -381,6 +380,7 @@ int for_each_tag_ref(each_ref_fn fn, void *cb_data);
>>  int for_each_branch_ref(each_ref_fn fn, void *cb_data);
>>  int for_each_remote_ref(each_ref_fn fn, void *cb_data);
>>  int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data);
>> +int for_each_ref_all(const char *prefix, each_repo_ref_fn fn, void *cb_data);
>>
>>  /* iterates all refs that match the specified glob pattern. */
>>  int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
>> diff --git a/t/t1403-show-ref.sh b/t/t1403-show-ref.sh
>> index 33fb7a38fff..0aebe709dca 100755
>> --- a/t/t1403-show-ref.sh
>> +++ b/t/t1403-show-ref.sh
>> @@ -286,4 +286,24 @@ test_expect_success '--exists with existing special ref' '
>>  	git show-ref --exists FETCH_HEAD
>>  '
>>
>> +test_expect_success '--symbolic-name with a non symbolic ref' '
>> +	commit_oid=$(git rev-parse refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME) &&
>> +	cat >expect <<-EOF &&
>> +	$commit_oid refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
>> +	EOF
>> +	git show-ref --symbolic-name refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME >actual &&
>> +	test_cmp expect actual
>> +'
>> +
>> +test_expect_success '--symbolic-name with symbolic ref' '
>> +	test_when_finished "git symbolic-ref -d refs/heads/SYMBOLIC_REF_A" &&
>> +	commit_oid=$(git rev-parse refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME) &&
>> +	cat >expect <<-EOF &&
>> +	$commit_oid refs/heads/SYMBOLIC_REF_A ref:refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
>> +	EOF
>> +	git symbolic-ref refs/heads/SYMBOLIC_REF_A refs/heads/$GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME &&
>> +	git show-ref --symbolic-name SYMBOLIC_REF_A >actual &&
>> +	test_cmp expect actual
>> +'
>> +
>>  test_done
>> -- 
>> gitgitgadget





[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux