git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] symbolic-ref: teach "--[no-]recurse" option
@ 2022-10-07 22:00 Junio C Hamano
  2022-10-08  3:35 ` Eric Sunshine
  2022-10-08  4:34 ` [PATCH v2] " Junio C Hamano
  0 siblings, 2 replies; 13+ messages in thread
From: Junio C Hamano @ 2022-10-07 22:00 UTC (permalink / raw)
  To: git

Suppose you are managing many maintenance tracks in your project,
and some of the more recent ones are maint-2.36 and maint-2.37.
Further imagine that your project recently tagged the official 2.38
release, which means you would need to start maint-2.38 track soon,
by doing:

  $ git checkout -b maint-2.38 v2.38.0^0
  $ git branch --list 'maint-2.3[6-9]'
  * maint-2.38
    maint-2.36
    maint-2.37

So far, so good.  But it also is reasonable to want not to have to
worry about which maintenance track is the latest, by pointing a
more generic-sounding 'maint' branch at it, by doing:

  $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38

which would allow you to say "whichever it is, check out the latest
maintenance track", by doing:

  $ git checkout maint
  $ git branch --show-current
  maint-2.38

It is arguably better to say that we are on 'maint-2.38' rather than
on 'maint', and "git merge/pull" would record "into maint-2.38" and
not "into maint", so I think what we have is a good behaviour.

One thing that is slightly irritating, however, is that I do not
think there is a good way (other than "cat .git/HEAD") to learn that
you checked out 'maint' to get into that state.  Just like the output
of "git branch --show-current" shows above, "git symbolic-ref HEAD"
would report 'refs/heads/maint-2.38', bypassing the intermediate
symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.

The internal resolve_ref() API already has the necessary support for
stopping after resolving a single level of a symbolic-ref, and we
can expose it by adding a "--[no-]recurse" option to the command.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/symbolic-ref.c  | 16 ++++++++++------
 t/t1401-symbolic-ref.sh | 14 ++++++++++++++
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git c/builtin/symbolic-ref.c w/builtin/symbolic-ref.c
index 1b0f10225f..5c9de63267 100644
--- c/builtin/symbolic-ref.c
+++ w/builtin/symbolic-ref.c
@@ -10,10 +10,13 @@ static const char * const git_symbolic_ref_usage[] = {
 	NULL
 };
 
-static int check_symref(const char *HEAD, int quiet, int shorten, int print)
+static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)
 {
-	int flag;
-	const char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);
+	int resolve_flags, flag;
+	const char *refname;
+
+	resolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);
+	refname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);
 
 	if (!refname)
 		die("No such ref: %s", HEAD);
@@ -35,13 +38,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)
 
 int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 {
-	int quiet = 0, delete = 0, shorten = 0, ret = 0;
+	int quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;
 	const char *msg = NULL;
 	struct option options[] = {
 		OPT__QUIET(&quiet,
 			N_("suppress error message for non-symbolic (detached) refs")),
 		OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")),
 		OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
+		OPT_BOOL(0, "recurse", &recurse, N_("recursively dereference (default)")),
 		OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
 		OPT_END(),
 	};
@@ -55,7 +59,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 	if (delete) {
 		if (argc != 1)
 			usage_with_options(git_symbolic_ref_usage, options);
-		ret = check_symref(argv[0], 1, 0, 0);
+		ret = check_symref(argv[0], 1, 0, 0, 0);
 		if (ret)
 			die("Cannot delete %s, not a symbolic ref", argv[0]);
 		if (!strcmp(argv[0], "HEAD"))
@@ -65,7 +69,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 
 	switch (argc) {
 	case 1:
-		ret = check_symref(argv[0], quiet, shorten, 1);
+		ret = check_symref(argv[0], quiet, shorten, recurse, 1);
 		break;
 	case 2:
 		if (!strcmp(argv[0], "HEAD") &&
diff --git c/t/t1401-symbolic-ref.sh w/t/t1401-symbolic-ref.sh
index 0c204089b8..d708acdb81 100755
--- c/t/t1401-symbolic-ref.sh
+++ w/t/t1401-symbolic-ref.sh
@@ -175,4 +175,18 @@ test_expect_success 'symbolic-ref allows top-level target for non-HEAD' '
 	test_cmp_rev top-level HEAD
 '
 
+test_expect_success 'symbolic-ref pointing at another' '
+	git update-ref refs/heads/maint-2.37 HEAD &&
+	git symbolic-ref refs/heads/maint refs/heads/maint-2.37 &&
+	git checkout maint &&
+
+	git symbolic-ref HEAD >actual &&
+	echo refs/heads/maint-2.37 >expect &&
+	test_cmp expect actual &&
+
+	git symbolic-ref --no-recurse HEAD >actual &&
+	echo refs/heads/maint >expect &&
+	test_cmp expect actual
+'
+
 test_done

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH] symbolic-ref: teach "--[no-]recurse" option
  2022-10-07 22:00 [PATCH] symbolic-ref: teach "--[no-]recurse" option Junio C Hamano
@ 2022-10-08  3:35 ` Eric Sunshine
  2022-10-08  4:20   ` Junio C Hamano
  2022-10-08  4:34 ` [PATCH v2] " Junio C Hamano
  1 sibling, 1 reply; 13+ messages in thread
From: Eric Sunshine @ 2022-10-08  3:35 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List

On Fri, Oct 7, 2022 at 6:19 PM Junio C Hamano <gitster@pobox.com> wrote:
> [...]
> One thing that is slightly irritating, however, is that I do not
> think there is a good way (other than "cat .git/HEAD") to learn that
> you checked out 'maint' to get into that state.  Just like the output
> of "git branch --show-current" shows above, "git symbolic-ref HEAD"
> would report 'refs/heads/maint-2.38', bypassing the intermediate
> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.
>
> The internal resolve_ref() API already has the necessary support for
> stopping after resolving a single level of a symbolic-ref, and we
> can expose it by adding a "--[no-]recurse" option to the command.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>  builtin/symbolic-ref.c  | 16 ++++++++++------
>  t/t1401-symbolic-ref.sh | 14 ++++++++++++++
>  2 files changed, 24 insertions(+), 6 deletions(-)

Should this be accompanied by a documentation update or is the patch
intended as an RFC?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] symbolic-ref: teach "--[no-]recurse" option
  2022-10-08  3:35 ` Eric Sunshine
@ 2022-10-08  4:20   ` Junio C Hamano
  0 siblings, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2022-10-08  4:20 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List

Eric Sunshine <sunshine@sunshineco.com> writes:

> On Fri, Oct 7, 2022 at 6:19 PM Junio C Hamano <gitster@pobox.com> wrote:
>> [...]
>> One thing that is slightly irritating, however, is that I do not
>> think there is a good way (other than "cat .git/HEAD") to learn that
>> you checked out 'maint' to get into that state.  Just like the output
>> of "git branch --show-current" shows above, "git symbolic-ref HEAD"
>> would report 'refs/heads/maint-2.38', bypassing the intermediate
>> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.
>>
>> The internal resolve_ref() API already has the necessary support for
>> stopping after resolving a single level of a symbolic-ref, and we
>> can expose it by adding a "--[no-]recurse" option to the command.
>>
>> Signed-off-by: Junio C Hamano <gitster@pobox.com>
>> ---
>>  builtin/symbolic-ref.c  | 16 ++++++++++------
>>  t/t1401-symbolic-ref.sh | 14 ++++++++++++++
>>  2 files changed, 24 insertions(+), 6 deletions(-)
>
> Should this be accompanied by a documentation update or is the patch
> intended as an RFC?

It started its life as an RFC but I had an actual need during
today's integration run ;-).  Will try to come up with a
documentation patch when I have time.

Thanks.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2] symbolic-ref: teach "--[no-]recurse" option
  2022-10-07 22:00 [PATCH] symbolic-ref: teach "--[no-]recurse" option Junio C Hamano
  2022-10-08  3:35 ` Eric Sunshine
@ 2022-10-08  4:34 ` Junio C Hamano
  2022-10-08  4:54   ` Eric Sunshine
                     ` (3 more replies)
  1 sibling, 4 replies; 13+ messages in thread
From: Junio C Hamano @ 2022-10-08  4:34 UTC (permalink / raw)
  To: git; +Cc: Eric Sunshine

Suppose you are managing many maintenance tracks in your project,
and some of the more recent ones are maint-2.36 and maint-2.37.
Further imagine that your project recently tagged the official 2.38
release, which means you would need to start maint-2.38 track soon,
by doing:

  $ git checkout -b maint-2.38 v2.38.0^0
  $ git branch --list 'maint-2.3[6-9]'
  * maint-2.38
    maint-2.36
    maint-2.37

So far, so good.  But it also is reasonable to want not to have to
worry about which maintenance track is the latest, by pointing a
more generic-sounding 'maint' branch at it, by doing:

  $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38

which would allow you to say "whichever it is, check out the latest
maintenance track", by doing:

  $ git checkout maint
  $ git branch --show-current
  maint-2.38

It is arguably better to say that we are on 'maint-2.38' rather than
on 'maint', and "git merge/pull" would record "into maint-2.38" and
not "into maint", so I think what we have is a good behaviour.

One thing that is slightly irritating, however, is that I do not
think there is a good way (other than "cat .git/HEAD") to learn that
you checked out 'maint' to get into that state.  Just like the output
of "git branch --show-current" shows above, "git symbolic-ref HEAD"
would report 'refs/heads/maint-2.38', bypassing the intermediate
symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.

The internal resolve_ref() API already has the necessary support for
stopping after resolving a single level of a symbolic-ref, and we
can expose it by adding a "--[no-]recurse" option to the command.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---

 * Updates documentation, which was entirely lacking in v1, with no
   other changes.

 Documentation/git-symbolic-ref.txt |  9 +++++++++
 builtin/symbolic-ref.c             | 16 ++++++++++------
 t/t1401-symbolic-ref.sh            | 14 ++++++++++++++
 3 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
index ef68ad2b71..3b5a97ea2b 100644
--- a/Documentation/git-symbolic-ref.txt
+++ b/Documentation/git-symbolic-ref.txt
@@ -46,6 +46,15 @@ OPTIONS
 	When showing the value of <name> as a symbolic ref, try to shorten the
 	value, e.g. from `refs/heads/master` to `master`.
 
+--recurse::
+--no-recurse::
+	When showing the value of <name> as a symbolic ref, if
+	<name> refers to another symbolic ref, follow such a chain
+	of symbolic refs until the result no longer points at a
+	symbolic ref (`--recurse`, which is the default).
+	`--no-recurse` stops after dereferencing only a single level
+	of symbolic ref.
+
 -m::
 	Update the reflog for <name> with <reason>.  This is valid only
 	when creating or updating a symbolic ref.
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index e547a08d6c..1af27b3a68 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -10,10 +10,13 @@ static const char * const git_symbolic_ref_usage[] = {
 	NULL
 };
 
-static int check_symref(const char *HEAD, int quiet, int shorten, int print)
+static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)
 {
-	int flag;
-	const char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);
+	int resolve_flags, flag;
+	const char *refname;
+
+	resolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);
+	refname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);
 
 	if (!refname)
 		die("No such ref: %s", HEAD);
@@ -35,13 +38,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)
 
 int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 {
-	int quiet = 0, delete = 0, shorten = 0, ret = 0;
+	int quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;
 	const char *msg = NULL;
 	struct option options[] = {
 		OPT__QUIET(&quiet,
 			N_("suppress error message for non-symbolic (detached) refs")),
 		OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")),
 		OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
+		OPT_BOOL(0, "recurse", &recurse, N_("recursively dereference (default)")),
 		OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
 		OPT_END(),
 	};
@@ -55,7 +59,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 	if (delete) {
 		if (argc != 1)
 			usage_with_options(git_symbolic_ref_usage, options);
-		ret = check_symref(argv[0], 1, 0, 0);
+		ret = check_symref(argv[0], 1, 0, 0, 0);
 		if (ret)
 			die("Cannot delete %s, not a symbolic ref", argv[0]);
 		if (!strcmp(argv[0], "HEAD"))
@@ -65,7 +69,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 
 	switch (argc) {
 	case 1:
-		ret = check_symref(argv[0], quiet, shorten, 1);
+		ret = check_symref(argv[0], quiet, shorten, recurse, 1);
 		break;
 	case 2:
 		if (!strcmp(argv[0], "HEAD") &&
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index 132a1b885a..773a6e8e01 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -163,4 +163,18 @@ test_expect_success 'symbolic-ref can resolve d/f name (ENOTDIR)' '
 	test_cmp expect actual
 '
 
+test_expect_success 'symbolic-ref pointing at another' '
+	git update-ref refs/heads/maint-2.37 HEAD &&
+	git symbolic-ref refs/heads/maint refs/heads/maint-2.37 &&
+	git checkout maint &&
+
+	git symbolic-ref HEAD >actual &&
+	echo refs/heads/maint-2.37 >expect &&
+	test_cmp expect actual &&
+
+	git symbolic-ref --no-recurse HEAD >actual &&
+	echo refs/heads/maint >expect &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.38.0-165-ga5df27c8e1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] symbolic-ref: teach "--[no-]recurse" option
  2022-10-08  4:34 ` [PATCH v2] " Junio C Hamano
@ 2022-10-08  4:54   ` Eric Sunshine
  2022-10-09  4:41     ` Junio C Hamano
  2022-10-08  9:37   ` Bagas Sanjaya
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Eric Sunshine @ 2022-10-08  4:54 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Sat, Oct 8, 2022 at 12:34 AM Junio C Hamano <gitster@pobox.com> wrote:
> [...]
> One thing that is slightly irritating, however, is that I do not
> think there is a good way (other than "cat .git/HEAD") to learn that
> you checked out 'maint' to get into that state.  Just like the output
> of "git branch --show-current" shows above, "git symbolic-ref HEAD"
> would report 'refs/heads/maint-2.38', bypassing the intermediate
> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.
> [...]
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
> diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
> @@ -46,6 +46,15 @@ OPTIONS
> +--recurse::
> +--no-recurse::
> +       When showing the value of <name> as a symbolic ref, if
> +       <name> refers to another symbolic ref, follow such a chain
> +       of symbolic refs until the result no longer points at a
> +       symbolic ref (`--recurse`, which is the default).
> +       `--no-recurse` stops after dereferencing only a single level
> +       of symbolic ref.

With his recent documentation-normalization work, I suspect Ævar would
appreciate an update to the synopsis, as well:

    SYNOPSIS
    --------
    [verse]
    'git symbolic-ref' [-m <reason>] <name> <ref>
   -'git symbolic-ref' [-q] [--short] <name>
   +'git symbolic-ref' [-q] [--short] [--no-recurse] <name>
    'git symbolic-ref' --delete [-q] <name>

or something similar (i.e. plain [--recurse] or composite
[--[no-]-recurse] or [--recurse | --no-recurse]).

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] symbolic-ref: teach "--[no-]recurse" option
  2022-10-08  4:34 ` [PATCH v2] " Junio C Hamano
  2022-10-08  4:54   ` Eric Sunshine
@ 2022-10-08  9:37   ` Bagas Sanjaya
  2022-10-09 12:47     ` Junio C Hamano
  2022-10-08 12:28   ` Philip Oakley
  2022-10-09 22:13   ` [PATCH v3] " Junio C Hamano
  3 siblings, 1 reply; 13+ messages in thread
From: Bagas Sanjaya @ 2022-10-08  9:37 UTC (permalink / raw)
  To: Junio C Hamano, git; +Cc: Eric Sunshine

On 10/8/22 11:34, Junio C Hamano wrote:
> Suppose you are managing many maintenance tracks in your project,
> and some of the more recent ones are maint-2.36 and maint-2.37.
> Further imagine that your project recently tagged the official 2.38
> release, which means you would need to start maint-2.38 track soon,
> by doing:
> 
>   $ git checkout -b maint-2.38 v2.38.0^0
>   $ git branch --list 'maint-2.3[6-9]'
>   * maint-2.38
>     maint-2.36
>     maint-2.37
> 
> So far, so good.  But it also is reasonable to want not to have to
> worry about which maintenance track is the latest, by pointing a
> more generic-sounding 'maint' branch at it, by doing:
> 
>   $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38
> 
> which would allow you to say "whichever it is, check out the latest
> maintenance track", by doing:
> 
>   $ git checkout maint
>   $ git branch --show-current
>   maint-2.38
> 
> It is arguably better to say that we are on 'maint-2.38' rather than
> on 'maint', and "git merge/pull" would record "into maint-2.38" and
> not "into maint", so I think what we have is a good behaviour.
> 
> One thing that is slightly irritating, however, is that I do not
> think there is a good way (other than "cat .git/HEAD") to learn that
> you checked out 'maint' to get into that state.  Just like the output
> of "git branch --show-current" shows above, "git symbolic-ref HEAD"
> would report 'refs/heads/maint-2.38', bypassing the intermediate
> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.
> 
> The internal resolve_ref() API already has the necessary support for
> stopping after resolving a single level of a symbolic-ref, and we
> can expose it by adding a "--[no-]recurse" option to the command.
> 

The example case above is from recent Git releases, right?

I think the wording should instead use generalized version numbers.
For example the still maintained release tracks are X.Y-1 and X.Y,
but now X+1 have been tagged, which creates X+1.Y track.

Thanks.

-- 
An old man doll... just what I always wanted! - Clara

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] symbolic-ref: teach "--[no-]recurse" option
  2022-10-08  4:34 ` [PATCH v2] " Junio C Hamano
  2022-10-08  4:54   ` Eric Sunshine
  2022-10-08  9:37   ` Bagas Sanjaya
@ 2022-10-08 12:28   ` Philip Oakley
  2022-10-08 15:28     ` Philip Oakley
  2022-10-09 12:07     ` Junio C Hamano
  2022-10-09 22:13   ` [PATCH v3] " Junio C Hamano
  3 siblings, 2 replies; 13+ messages in thread
From: Philip Oakley @ 2022-10-08 12:28 UTC (permalink / raw)
  To: Junio C Hamano, git; +Cc: Eric Sunshine

Hi Junio

On 08/10/2022 05:34, Junio C Hamano wrote:
> Suppose you are managing many maintenance tracks in your project,
> and some of the more recent ones are maint-2.36 and maint-2.37.
> Further imagine that your project recently tagged the official 2.38
> release, which means you would need to start maint-2.38 track soon,
> by doing:
>
>   $ git checkout -b maint-2.38 v2.38.0^0
>   $ git branch --list 'maint-2.3[6-9]'
>   * maint-2.38
>     maint-2.36
>     maint-2.37
>
> So far, so good.  But it also is reasonable to want not to have to
> worry about which maintenance track is the latest, by pointing a
> more generic-sounding 'maint' branch at it, by doing:
>
>   $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38
>
> which would allow you to say "whichever it is, check out the latest
> maintenance track", by doing:
>
>   $ git checkout maint
>   $ git branch --show-current
>   maint-2.38
>
> It is arguably better to say that we are on 'maint-2.38' rather than
> on 'maint', and "git merge/pull" would record "into maint-2.38" and
> not "into maint", so I think what we have is a good behaviour.
>
> One thing that is slightly irritating, however, is that I do not
> think there is a good way (other than "cat .git/HEAD") to learn that
> you checked out 'maint' to get into that state.  Just like the output
> of "git branch --show-current" shows above, "git symbolic-ref HEAD"
> would report 'refs/heads/maint-2.38', bypassing the intermediate
> symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.
>
> The internal resolve_ref() API already has the necessary support for
> stopping after resolving a single level of a symbolic-ref, and we
> can expose it by adding a "--[no-]recurse" option to the command.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
>
>  * Updates documentation, which was entirely lacking in v1, with no
>    other changes.
>
>  Documentation/git-symbolic-ref.txt |  9 +++++++++

Is there also a need to update SubmittingPatches to clarify the
distinctions between the generic name 'maint', the specific `maint-xx`
branches, and the symbolic ref linkages from `maint`.

The existence of the `maint-xx` branches, and where they came from, was
something that eluded me for a long time.

The descriptions give the impression there is just a single main branch,
with a singular name, and that was the end of it. It was only much later
when some security patches were pushed down to numerous older `maint-xx`
branches. The use of the singular `maint` is also used in examples a
number of places further cementing the singular maintenance view.

A few words clarifying the `maint` vs `maint-x.yy` branches could help
users past the confusion.
--
Philip

>  builtin/symbolic-ref.c             | 16 ++++++++++------
>  t/t1401-symbolic-ref.sh            | 14 ++++++++++++++
>  3 files changed, 33 insertions(+), 6 deletions(-)
>
> diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
> index ef68ad2b71..3b5a97ea2b 100644
> --- a/Documentation/git-symbolic-ref.txt
> +++ b/Documentation/git-symbolic-ref.txt
> @@ -46,6 +46,15 @@ OPTIONS
>  	When showing the value of <name> as a symbolic ref, try to shorten the
>  	value, e.g. from `refs/heads/master` to `master`.
>  
> +--recurse::
> +--no-recurse::
> +	When showing the value of <name> as a symbolic ref, if
> +	<name> refers to another symbolic ref, follow such a chain
> +	of symbolic refs until the result no longer points at a
> +	symbolic ref (`--recurse`, which is the default).
> +	`--no-recurse` stops after dereferencing only a single level
> +	of symbolic ref.
> +
>  -m::
>  	Update the reflog for <name> with <reason>.  This is valid only
>  	when creating or updating a symbolic ref.
> diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
> index e547a08d6c..1af27b3a68 100644
> --- a/builtin/symbolic-ref.c
> +++ b/builtin/symbolic-ref.c
> @@ -10,10 +10,13 @@ static const char * const git_symbolic_ref_usage[] = {
>  	NULL
>  };
>  
> -static int check_symref(const char *HEAD, int quiet, int shorten, int print)
> +static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)
>  {
> -	int flag;
> -	const char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);
> +	int resolve_flags, flag;
> +	const char *refname;
> +
> +	resolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);
> +	refname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);
>  
>  	if (!refname)
>  		die("No such ref: %s", HEAD);
> @@ -35,13 +38,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)
>  
>  int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
>  {
> -	int quiet = 0, delete = 0, shorten = 0, ret = 0;
> +	int quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;
>  	const char *msg = NULL;
>  	struct option options[] = {
>  		OPT__QUIET(&quiet,
>  			N_("suppress error message for non-symbolic (detached) refs")),
>  		OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")),
>  		OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
> +		OPT_BOOL(0, "recurse", &recurse, N_("recursively dereference (default)")),
>  		OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
>  		OPT_END(),
>  	};
> @@ -55,7 +59,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
>  	if (delete) {
>  		if (argc != 1)
>  			usage_with_options(git_symbolic_ref_usage, options);
> -		ret = check_symref(argv[0], 1, 0, 0);
> +		ret = check_symref(argv[0], 1, 0, 0, 0);
>  		if (ret)
>  			die("Cannot delete %s, not a symbolic ref", argv[0]);
>  		if (!strcmp(argv[0], "HEAD"))
> @@ -65,7 +69,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
>  
>  	switch (argc) {
>  	case 1:
> -		ret = check_symref(argv[0], quiet, shorten, 1);
> +		ret = check_symref(argv[0], quiet, shorten, recurse, 1);
>  		break;
>  	case 2:
>  		if (!strcmp(argv[0], "HEAD") &&
> diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
> index 132a1b885a..773a6e8e01 100755
> --- a/t/t1401-symbolic-ref.sh
> +++ b/t/t1401-symbolic-ref.sh
> @@ -163,4 +163,18 @@ test_expect_success 'symbolic-ref can resolve d/f name (ENOTDIR)' '
>  	test_cmp expect actual
>  '
>  
> +test_expect_success 'symbolic-ref pointing at another' '
> +	git update-ref refs/heads/maint-2.37 HEAD &&
> +	git symbolic-ref refs/heads/maint refs/heads/maint-2.37 &&
> +	git checkout maint &&
> +
> +	git symbolic-ref HEAD >actual &&
> +	echo refs/heads/maint-2.37 >expect &&
> +	test_cmp expect actual &&
> +
> +	git symbolic-ref --no-recurse HEAD >actual &&
> +	echo refs/heads/maint >expect &&
> +	test_cmp expect actual
> +'
> +
>  test_done


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] symbolic-ref: teach "--[no-]recurse" option
  2022-10-08 12:28   ` Philip Oakley
@ 2022-10-08 15:28     ` Philip Oakley
  2022-10-09 12:07     ` Junio C Hamano
  1 sibling, 0 replies; 13+ messages in thread
From: Philip Oakley @ 2022-10-08 15:28 UTC (permalink / raw)
  To: Junio C Hamano, git; +Cc: Eric Sunshine

spelling correction

On 08/10/2022 13:28, Philip Oakley wrote:
> The existence of the `maint-xx` branches, and where they came from, was
> something that eluded me for a long time.
>
> The descriptions give the impression there is just a single main branch,

s/main/`maint`/ 
> with a singular name, and that was the end of it. It was only much later
> when some security patches were pushed down to numerous older `maint-xx`
> branches. The use of the singular `maint` is also used in examples a
> number of places further cementing the singular maintenance view.
>
> A few words clarifying the `maint` vs `maint-x.yy` branches could help
> users past the confusion.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] symbolic-ref: teach "--[no-]recurse" option
  2022-10-08  4:54   ` Eric Sunshine
@ 2022-10-09  4:41     ` Junio C Hamano
  0 siblings, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2022-10-09  4:41 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git

Eric Sunshine <sunshine@sunshineco.com> writes:

> With his recent documentation-normalization work, I suspect Ævar would
> appreciate an update to the synopsis, as well:
>
>     SYNOPSIS
>     --------
>     [verse]
>     'git symbolic-ref' [-m <reason>] <name> <ref>
>    -'git symbolic-ref' [-q] [--short] <name>
>    +'git symbolic-ref' [-q] [--short] [--no-recurse] <name>
>     'git symbolic-ref' --delete [-q] <name>
>
> or something similar (i.e. plain [--recurse] or composite
> [--[no-]-recurse] or [--recurse | --no-recurse]).

Yeah, that looks good.

I checked the in-code usage that used [<options>] (hence I didn't
have to do anything new), but apparently forgot about the doc.

As there is (and there will ever be) no configuration knob for this
plumbing command to make the non-recursive behaviour the default, I
think listing [--no-recurse] alone, not [--[no-]recurse], would be
the right thing to do in the documentation.

Thanks.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] symbolic-ref: teach "--[no-]recurse" option
  2022-10-08 12:28   ` Philip Oakley
  2022-10-08 15:28     ` Philip Oakley
@ 2022-10-09 12:07     ` Junio C Hamano
  2022-10-11 14:49       ` Philip Oakley
  1 sibling, 1 reply; 13+ messages in thread
From: Junio C Hamano @ 2022-10-09 12:07 UTC (permalink / raw)
  To: Philip Oakley; +Cc: git, Eric Sunshine

Philip Oakley <philipoakley@iee.email> writes:

> Is there also a need to update SubmittingPatches to clarify the
> distinctions between the generic name 'maint', the specific `maint-xx`
> branches, and the symbolic ref linkages from `maint`.

Not at all.  Perhaps you are thinking about MaintNotes, but even
there, general public do not have to be concerned about maint-xx
most of the time.  I myself would not be keeping branches for
ancient maintenance tracks anywhere.  As the older maintenance
tracks, other than the most recent ones, do not get topics graduated
to 'master' merged down by me (even though topic branches that fix
notable bugs may fork from an older version to allow motivated third
party maintainers to merge them down to older maintenance releases),
there is not really a reason to keep branches like maint-2.15 for
daily operation.  Only when we need security updates that go back to
older maintenance tracks, I may do

    $ git checkout -b maint-2.30 v2.30.5
    $ git merge cve-something-fix
    ... edit release notes etc. ...
    $ git commit -m 'Git 2.30.6'
    $ git tag -s -m 'Git 2.30.6' v2.30.6

but after that is done, there is no reason to keep an old branch
like maint-2.30 lying around, other than to make it easier to
prepare for v2.30.7 (as maint-2.30 will remember what tag was the
latest on that particular maintenance track).

> The descriptions give the impression there is just a single main branch,
> with a singular name, and that was the end of it.

And that is the correct world view for most of the  general public.

    https://github.com/git/git/

shows 'maint', 'master' ('main'), 'next', and 'seen' from the
project code, plus 'todo' which holds an unrelated history that
keeps track of maintenance tools and misc stuff.

By the way, I do not personally have 'main' in my working
repository.  The only trick I have to help folks who expect to see
'main' instead of 'master' is the push refspec to distribute the
integration results to various repositories.  My 'master' is pushed
to both 'master' and 'main' in destination repositories.

The mirror/backup repository of my private working repository does
have tentive branches, like the broken-out topic branches that are
still active, which are pruned when they no longer are needed.
Some maint-xx branches are also there but they are there not because
they are necessary but because I just haven't bothered to clean them
up ;-)


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] symbolic-ref: teach "--[no-]recurse" option
  2022-10-08  9:37   ` Bagas Sanjaya
@ 2022-10-09 12:47     ` Junio C Hamano
  0 siblings, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2022-10-09 12:47 UTC (permalink / raw)
  To: Bagas Sanjaya; +Cc: git, Eric Sunshine

Bagas Sanjaya <bagasdotme@gmail.com> writes:

> On 10/8/22 11:34, Junio C Hamano wrote:
>> Suppose you are managing many maintenance tracks in your project,
>> and some of the more recent ones are maint-2.36 and maint-2.37.
>
> The example case above is from recent Git releases, right?

It is left to reader's imagination.  Concrete numbers are easier to
understand, as it would be clear that 2.36 comes before 2.37 which
comes before 2.38.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3] symbolic-ref: teach "--[no-]recurse" option
  2022-10-08  4:34 ` [PATCH v2] " Junio C Hamano
                     ` (2 preceding siblings ...)
  2022-10-08 12:28   ` Philip Oakley
@ 2022-10-09 22:13   ` Junio C Hamano
  3 siblings, 0 replies; 13+ messages in thread
From: Junio C Hamano @ 2022-10-09 22:13 UTC (permalink / raw)
  To: git

Suppose you are managing many maintenance tracks in your project,
and some of the more recent ones are maint-2.36 and maint-2.37.
Further imagine that your project recently tagged the official 2.38
release, which means you would need to start maint-2.38 track soon,
by doing:

  $ git checkout -b maint-2.38 v2.38.0^0
  $ git branch --list 'maint-2.3[6-9]'
  * maint-2.38
    maint-2.36
    maint-2.37

So far, so good.  But it also is reasonable to want not to have to
worry about which maintenance track is the latest, by pointing a
more generic-sounding 'maint' branch at it, by doing:

  $ git symbolic-ref refs/heads/maint refs/heads/maint-2.38

which would allow you to say "whichever it is, check out the latest
maintenance track", by doing:

  $ git checkout maint
  $ git branch --show-current
  maint-2.38

It is arguably better to say that we are on 'maint-2.38' rather than
on 'maint', and "git merge/pull" would record "into maint-2.38" and
not "into maint", so I think what we have is a good behaviour.

One thing that is slightly irritating, however, is that I do not
think there is a good way (other than "cat .git/HEAD") to learn that
you checked out 'maint' to get into that state.  Just like the output
of "git branch --show-current" shows above, "git symbolic-ref HEAD"
would report 'refs/heads/maint-2.38', bypassing the intermediate
symbolic ref at 'refs/heads/maint' that is pointed at by HEAD.

The internal resolve_ref() API already has the necessary support for
stopping after resolving a single level of a symbolic-ref, and we
can expose it by adding a "--[no-]recurse" option to the command.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---

 * The third time is the charm?  The only change since v2 is to make
   sure that Ævar's "doc SYNOPSIS and cmd -h help must match" topic
   is not upset with the new option.

 Documentation/git-symbolic-ref.txt | 11 ++++++++++-
 builtin/symbolic-ref.c             | 18 +++++++++++-------
 t/t1401-symbolic-ref.sh            | 14 ++++++++++++++
 3 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
index ef68ad2b71..102c83eb19 100644
--- a/Documentation/git-symbolic-ref.txt
+++ b/Documentation/git-symbolic-ref.txt
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git symbolic-ref' [-m <reason>] <name> <ref>
-'git symbolic-ref' [-q] [--short] <name>
+'git symbolic-ref' [-q] [--short] [--no-recurse] <name>
 'git symbolic-ref' --delete [-q] <name>
 
 DESCRIPTION
@@ -46,6 +46,15 @@ OPTIONS
 	When showing the value of <name> as a symbolic ref, try to shorten the
 	value, e.g. from `refs/heads/master` to `master`.
 
+--recurse::
+--no-recurse::
+	When showing the value of <name> as a symbolic ref, if
+	<name> refers to another symbolic ref, follow such a chain
+	of symbolic refs until the result no longer points at a
+	symbolic ref (`--recurse`, which is the default).
+	`--no-recurse` stops after dereferencing only a single level
+	of symbolic ref.
+
 -m::
 	Update the reflog for <name> with <reason>.  This is valid only
 	when creating or updating a symbolic ref.
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
index e547a08d6c..d5a70e7bd8 100644
--- a/builtin/symbolic-ref.c
+++ b/builtin/symbolic-ref.c
@@ -6,14 +6,17 @@
 
 static const char * const git_symbolic_ref_usage[] = {
 	N_("git symbolic-ref [<options>] <name> [<ref>]"),
-	N_("git symbolic-ref -d [-q] <name>"),
+	N_("git symbolic-ref -d [-q] [--no-recurse] <name>"),
 	NULL
 };
 
-static int check_symref(const char *HEAD, int quiet, int shorten, int print)
+static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)
 {
-	int flag;
-	const char *refname = resolve_ref_unsafe(HEAD, 0, NULL, &flag);
+	int resolve_flags, flag;
+	const char *refname;
+
+	resolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);
+	refname = resolve_ref_unsafe(HEAD, resolve_flags, NULL, &flag);
 
 	if (!refname)
 		die("No such ref: %s", HEAD);
@@ -35,13 +38,14 @@ static int check_symref(const char *HEAD, int quiet, int shorten, int print)
 
 int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 {
-	int quiet = 0, delete = 0, shorten = 0, ret = 0;
+	int quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;
 	const char *msg = NULL;
 	struct option options[] = {
 		OPT__QUIET(&quiet,
 			N_("suppress error message for non-symbolic (detached) refs")),
 		OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")),
 		OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
+		OPT_BOOL(0, "recurse", &recurse, N_("recursively dereference (default)")),
 		OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
 		OPT_END(),
 	};
@@ -55,7 +59,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 	if (delete) {
 		if (argc != 1)
 			usage_with_options(git_symbolic_ref_usage, options);
-		ret = check_symref(argv[0], 1, 0, 0);
+		ret = check_symref(argv[0], 1, 0, 0, 0);
 		if (ret)
 			die("Cannot delete %s, not a symbolic ref", argv[0]);
 		if (!strcmp(argv[0], "HEAD"))
@@ -65,7 +69,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
 
 	switch (argc) {
 	case 1:
-		ret = check_symref(argv[0], quiet, shorten, 1);
+		ret = check_symref(argv[0], quiet, shorten, recurse, 1);
 		break;
 	case 2:
 		if (!strcmp(argv[0], "HEAD") &&
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index 132a1b885a..773a6e8e01 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -163,4 +163,18 @@ test_expect_success 'symbolic-ref can resolve d/f name (ENOTDIR)' '
 	test_cmp expect actual
 '
 
+test_expect_success 'symbolic-ref pointing at another' '
+	git update-ref refs/heads/maint-2.37 HEAD &&
+	git symbolic-ref refs/heads/maint refs/heads/maint-2.37 &&
+	git checkout maint &&
+
+	git symbolic-ref HEAD >actual &&
+	echo refs/heads/maint-2.37 >expect &&
+	test_cmp expect actual &&
+
+	git symbolic-ref --no-recurse HEAD >actual &&
+	echo refs/heads/maint >expect &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.38.0-167-gf9a88ca9e9


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] symbolic-ref: teach "--[no-]recurse" option
  2022-10-09 12:07     ` Junio C Hamano
@ 2022-10-11 14:49       ` Philip Oakley
  0 siblings, 0 replies; 13+ messages in thread
From: Philip Oakley @ 2022-10-11 14:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Eric Sunshine

Hi Junio,

On 09/10/2022 13:07, Junio C Hamano wrote:
> Philip Oakley <philipoakley@iee.email> writes:
>
>> Is there also a need to update SubmittingPatches to clarify the
>> distinctions between the generic name 'maint', the specific `maint-xx`
>> branches, and the symbolic ref linkages from `maint`.
> Not at all.  Perhaps you are thinking about MaintNotes, but even
> there, general public do not have to be concerned about maint-xx
> most of the time.  I myself would not be keeping branches for
> ancient maintenance tracks anywhere.  As the older maintenance
> tracks, other than the most recent ones, do not get topics graduated
> to 'master' merged down by me (even though topic branches that fix
> notable bugs may fork from an older version to allow motivated third
> party maintainers to merge them down to older maintenance releases),
> there is not really a reason to keep branches like maint-2.15 for
> daily operation.  Only when we need security updates that go back to
> older maintenance tracks, I may do
>
>     $ git checkout -b maint-2.30 v2.30.5
>     $ git merge cve-something-fix
>     ... edit release notes etc. ...
>     $ git commit -m 'Git 2.30.6'
>     $ git tag -s -m 'Git 2.30.6' v2.30.6
>
> but after that is done, there is no reason to keep an old branch
> like maint-2.30 lying around, other than to make it easier to
> prepare for v2.30.7 (as maint-2.30 will remember what tag was the
> latest on that particular maintenance track).
>
>> The descriptions give the impression there is just a single main branch,
>> with a singular name, and that was the end of it.
> And that is the correct world view for most of the  general public.
>
>     https://github.com/git/git/
>
> shows 'maint', 'master' ('main'), 'next', and 'seen' from the
> project code, plus 'todo' which holds an unrelated history that
> keeps track of maintenance tools and misc stuff.
>
> By the way, I do not personally have 'main' in my working
> repository.  The only trick I have to help folks who expect to see
> 'main' instead of 'master' is the push refspec to distribute the
> integration results to various repositories.  My 'master' is pushed
> to both 'master' and 'main' in destination repositories.
>
> The mirror/backup repository of my private working repository does
> have tentive branches, like the broken-out topic branches that are
> still active, which are pruned when they no longer are needed.
> Some maint-xx branches are also there but they are there not because
> they are necessary but because I just haven't bothered to clean them
> up ;-)
>
Thanks for the clarification.

My confusion about `maint` started quite a few years back and may be a
mixture of a number of different issues, or simply my misunderstanding.

I'm guessing here, but it may have been, that back then, that the maint
branch was a link to the relevant maint-xx, rather than a 'symref' and
that at that time the Git-for-Windows didn't really handle them, so
`maint` may not have shown for me (similar to how RelNotes is configured
in the Git repo).

It may also have been early confusion about remotes and their branches,
and the impression that I needed (or should expect) a local branch of
the same name and this wasn't happening (obvious in retrospect), so I
never found any `maint` in my repo.

The whole 'remote tracking branches' stuff took a long time to
understand and was non-obvious from my perspective. I suspect many
newbies have similar issues (e.g. the current thread
https://lore.kernel.org/git/DU2P194MB15841850A17436C7AE34C149E3239@DU2P194MB1584.EURP194.PROD.OUTLOOK.COM/T/#t)

--
Philip

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-10-11 14:49 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-07 22:00 [PATCH] symbolic-ref: teach "--[no-]recurse" option Junio C Hamano
2022-10-08  3:35 ` Eric Sunshine
2022-10-08  4:20   ` Junio C Hamano
2022-10-08  4:34 ` [PATCH v2] " Junio C Hamano
2022-10-08  4:54   ` Eric Sunshine
2022-10-09  4:41     ` Junio C Hamano
2022-10-08  9:37   ` Bagas Sanjaya
2022-10-09 12:47     ` Junio C Hamano
2022-10-08 12:28   ` Philip Oakley
2022-10-08 15:28     ` Philip Oakley
2022-10-09 12:07     ` Junio C Hamano
2022-10-11 14:49       ` Philip Oakley
2022-10-09 22:13   ` [PATCH v3] " Junio C Hamano

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).