threads / discuss / 62017

Tags auto fetched by "git fetch origin" but not "git fetch origin main"

Subject: Tags auto fetched by "git fetch origin" but not "git fetch origin main"

## tl;dr

6 messages between Aug 28, 2024 and Aug 29, 2024.

replies: 5people: 3as markdown or json

Yukai Chou· Aug 28, 2024, 23:23 UTC · lore
In using `git fetch [<options>] [<repository> [<refspec>…]]`,
- when a branch is specified as <refspec>, no tags are fetched automatically;
- when no <refspec>s are specified, tags are fetched automatically.

This reproduces with both glob (`+refs/heads/*:refs/remotes/origin/*`) or restricted (`+refs/heads/main:refs/remotes/origin/main`) `remote.<name>.fetch`.

From the git-fetch doc in Git v2.46.0 [1], I don't understand why they behave differently.

Show 5 quoted lines
> DESCRIPTION
> [...]
> By default, any tag that points into the histories being fetched is
> also fetched; the effect is to fetch tags that
> point at branches that you are interested in.
Show 5 quoted lines
> <refspec>
> [...] Since
> Git version 2.20, fetching to update `refs/tags/*` works the same way
> as when pushing. I.e. any updates will be rejected without `+` in the
> refspec (or `--force`).
Show 14 quoted lines
> CONFIGURED REMOTE-TRACKING BRANCHES
> [...]
> This configuration is used in two ways:
>
> * When `git fetch` is run without specifying what branches
> and/or tags to fetch on the command line, e.g. `git fetch origin`
> or `git fetch`, `remote.<repository>.fetch` values are used as
> the refspecs ...
>
> * When `git fetch` is run with explicit branches and/or tags
> to fetch on the command line, e.g. `git fetch origin master`, the
> <refspec>s given on the command line determine what are to be
> fetched (...). The `remote.<repository>.fetch` values determine
> which remote-tracking branch, if any, is updated.
Steps to reproduce

```shell # prepare a local upstream and fork it git init local-upstream && cd local-upstream for i in 1 2 3; do git commit --allow-empty -m "commit $i"; done git tag v0.3 cd .. git clone file://$(pwd)/local-upstream local-fork # now local-fork has all three commits and a tag v0.3

# add more commits and a new tag to upstream cd local-upstream for i in 4 5; do git commit --allow-empty -m "commit $i"; done git tag v0.5 cd ..

# try to fetch new commits and the new tag v0.5 cd local-fork # this fetches commits only git fetch origin main # this finally fetches the tag new v0.5, but why? git fetch origin cd .. ```

[1] https://git-scm.com/docs/git-fetch/2.46.0
Yukai
brian m. carlson· Aug 29, 2024, 21:32 UTC · re: Yukai Chou · lore

Re: Tags auto fetched by "git fetch origin" but not "git fetch origin main"

On 2024-08-28 at 23:23:57, Yukai Chou wrote:
> In using `git fetch [<options>] [<repository> [<refspec>…]]`,
> - when a branch is specified as <refspec>, no tags are fetched automatically;
> - when no <refspec>s are specified, tags are fetched automatically.

Yes, this is expected. Tags are refs, and when you specify no refspec, you're asking for the default behaviour, which usually involves fetching tags. But when you specify a refspec, you are saying, "I want you to fetch this, and only this; don't fetch anything else."

For example, if I say, `git fetch origin refs/heads/main:refs/heads/main`, it would be very unexpected for it to fetch tags as well; I only wanted it to fetch the main branch. In fact, I might be explicitly relying on it not affecting any other refs.

If you want tags nonetheless, you can use the `--tags` option, which should fetch tags in addition to the refspec provided.

-- 
brian m. carlson (they/them or he/him)
Toronto, Ontario, CA
Junio C Hamano· Aug 29, 2024, 21:44 UTC · re: brian m. carlson · lore

Re: Tags auto fetched by "git fetch origin" but not "git fetch origin main"

"brian m. carlson" <sandals@crustytoothpaste.net> writes:
> If you want tags nonetheless, you can use the `--tags` option, which
> should fetch tags in addition to the refspec provided.

But doesn't that grab _all_ tags, not only the relevant tags that point into the history leading to the commits being fetched?

brian m. carlson· Aug 29, 2024, 22:22 UTC · re: Junio C Hamano · lore

Re: Tags auto fetched by "git fetch origin" but not "git fetch origin main"

On 2024-08-29 at 21:44:02, Junio C Hamano wrote:
Show 7 quoted lines
> "brian m. carlson" <sandals@crustytoothpaste.net> writes:
> 
> > If you want tags nonetheless, you can use the `--tags` option, which
> > should fetch tags in addition to the refspec provided.
> 
> But doesn't that grab _all_ tags, not only the relevant tags that
> point into the history leading to the commits being fetched?
It's not clear to me.  The description says this:
  By default, any tag that points into the histories being fetched is
  also fetched; the effect is to fetch tags that point at branches that
  you are interested in. This default behavior can be changed by using
  the --tags or --no-tags options or by configuring
  remote.<name>.tagOpt. By using a refspec that fetches tags explicitly,
  you can fetch tags that do not point into branches you are interested
  in as well.

That implies that `--tags` or `--no-tags` simply changes whether that limited set of tags is fetched.

But the `--tags` option says this:
  Fetch all tags from the remote (i.e., fetch remote tags refs/tags/* into
  local tags with the same name), in addition to whatever else would
  otherwise be fetched. Using this option alone does not subject tags to
  pruning, even if --prune is used (though tags may be pruned anyway if
  they are also the destination of an explicit refspec; see --prune).
That implies that all tags are fetched.

I think we need somebody to test things and clarify the documentation. (I'm not volunteering because I have a lot of things on my plate right now.)

In addition, it might be useful to add a `--relevant-tags` option or some such that simply fetches the relevant tags when arbitrary refspecs are specified. If someone felt super interested, they could even make an additional generic option over other refspecs (I can imagine something like GitHub's refs/pull might be interesting for users).

-- 
brian m. carlson (they/them or he/him)
Toronto, Ontario, CA
Junio C Hamano· Aug 29, 2024, 22:38 UTC · re: brian m. carlson · lore

Re: Tags auto fetched by "git fetch origin" but not "git fetch origin main"

"brian m. carlson" <sandals@crustytoothpaste.net> writes:
Show 9 quoted lines
> But the `--tags` option says this:
>
>   Fetch all tags from the remote (i.e., fetch remote tags refs/tags/* into
>   local tags with the same name), in addition to whatever else would
>   otherwise be fetched. Using this option alone does not subject tags to
>   pruning, even if --prune is used (though tags may be pruned anyway if
>   they are also the destination of an explicit refspec; see --prune).
>
> That implies that all tags are fetched.

That is stronger than "implies", I would think. Indeed I know from the code inspection that the auto-following only triggers when neither --tags or --no-tags option is given, i.e. builtin/fetch.c has this:

	if (tags == TAGS_DEFAULT && autotags)
		transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");

where the variable tags is initialized to TAGS_DEFAULT, --tags/--no-tags sets it to TAGS_SET or TAGS_UNSET, and autotags is incremented only if a refspec we use has right hand side after the colon, i.e. stores what we fetched in our refs/ namespace.

> I think we need somebody to test things and clarify the documentation.
Done ;-)
> In addition, it might be useful to add a `--relevant-tags` option or

A similar option is called "--follow-tags" on the "git push" side. I _think_ it is just the matter of adding the option and have it set the tags variable back to TAGS_DEFAULT, i.e.

diff --git c/builtin/fetch.c w/builtin/fetch.c
index c297569a47..f22c00a39d 100644
--- c/builtin/fetch.c
+++ w/builtin/fetch.c
@@ -2186,6 +2186,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
 			    N_("fetch all tags and associated objects"), TAGS_SET),
 		OPT_SET_INT('n', NULL, &tags,
 			    N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
+		OPT_SET_INT(0, "follow-tags", &tags,
+			    N_("auto-follow tags"), TAGS_DEFAULT)),
 		OPT_INTEGER('j', "jobs", &max_jobs,
 			    N_("number of submodules fetched in parallel")),
 		OPT_BOOL(0, "prefetch", &prefetch,


but I didn't look too deeply into it.  It needs compile testing,
documentation updates and new teststo cover the behaviour.

Thanks.
Yukai Chou· Aug 29, 2024, 23:16 UTC · re: brian m. carlson · lore

Re: Tags auto fetched by "git fetch origin" but not "git fetch origin main"

brian m. carlson <sandals@crustytoothpaste.net> 于2024年8月30日周五 05:32写道:
Show 9 quoted lines
>
> On 2024-08-28 at 23:23:57, Yukai Chou wrote:
> > In using `git fetch [<options>] [<repository> [<refspec>…]]`,
> > - when a branch is specified as <refspec>, no tags are fetched automatically;
> > - when no <refspec>s are specified, tags are fetched automatically.
>
> Yes, this is expected.  Tags are refs, and when you specify no refspec,
> you're asking for the default behaviour, which usually involves fetching
> tags.

According to the doc section CONFIGURED REMOTE-TRACKING BRANCHES [1], when no refspec is specified,

  remote.<repository>.fetch values are used as the refspecs
Then according to doc of <refspec> [2],
  Since Git version 2.20, fetching to update refs/tags/* works the same
  way as when pushing. I.e. any updates will be rejected without + in
  the refspec (or --force).

So the tags are fetched due to the + in the remote.<repository>.fetch values, are they?

> For example, if I say, `git fetch origin
> refs/heads/main:refs/heads/main`, it would be very unexpected for it to
> fetch tags as well; ... .
Actually,
  git fetch --update-head-ok origin refs/heads/main:refs/heads/main
does fetch tags "that points into the histories being fetched".
This time the refspec is given on the command line, without +.
According to the doc of CONFIGURED REMOTE-TRACKING BRANCHES [1],
  When used in this way, the remote.<repository>.fetch values do not
  have any effect in deciding what gets fetched (i.e. the values are
  not used as refspecs when the command-line lists refspecs); they
  are only used to decide where the refs that are fetched are stored
  by acting as a mapping.

[1] https://git-scm.com/docs/git-fetch#_configured_remote_tracking_branches [2] https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt-ltrefspecgt

Yukai

← back to recent threads