From: Patrick Steinhardt <ps@pks.im>
To: Karthik Nayak <karthik.188@gmail.com>
Cc: git@vger.kernel.org, jltobler@gmail.com, sunshine@sunshineco.com,
David Bohman <debohman@gmail.com>
Subject: Re: [PATCH v2] fetch: fix non-conflicting tags not being committed
Date: Thu, 6 Nov 2025 12:50:20 +0100 [thread overview]
Message-ID: <aQyLfD_zx0ndCLvU@pks.im> (raw)
In-Reply-To: <20251106-fix-tags-not-fetching-v2-1-610cb4b0e7c8@gmail.com>
On Thu, Nov 06, 2025 at 09:39:25AM +0100, Karthik Nayak wrote:
> The commit 0e358de64a (fetch: use batched reference updates, 2025-05-19)
> updated the 'git-fetch(1)' command to use batched updates. This batches
> updates to gain performance improvements. When fetching references, each
> update is added to the transaction. Finally, when committing, individual
> updates are allowed to fail with reason, while the transaction itself
> succeeds.
>
> One scenario which was missed here, was fetching tags. When fetching
> conflicting tags, the `fetch_and_consume_refs()` function returns '1',
> which skipped committing the transaction and directly jumped to the
> cleanup section. This mean that no updates were applied.
Okay, this is obviously broken indeed.
> This also extends to backfilling tags when using the now deprecated
> 'branches/' format for remotes.
I'm a bit lost here -- what does backfilling have to do with the
"branches/" directory? The backfill is supposed to create tags that
point into the history that one has just fetched. So:
- With `--tags` we fetch all tags announced by the remote.
- With `--no-tags` we fetch no tags.
- Otherwise we fetch those tags that point into our history.
The last behaviour is a bit more on the esoteric side, but it's
described as such in git-fetch(1):
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.
The following test demonstrates this behaviour:
test_expect_success "fetch single branch without explicit tag option" '
git init source &&
git -C source commit --allow-empty --message common &&
git clone file://"$(pwd)"/source target &&
(
cd source &&
git commit --allow-empty --message discard-me &&
git tag discard-me &&
git commit --amend --allow-empty --message fetch-me &&
git tag fetch-me
) &&
# The "discard-me" tag does not point into the history that we are
# about to fetch, so it should not have been created.
git -C target fetch origin &&
git -C target tag -l >actual &&
echo "fetch-me" >expect &&
# But with "--tags" we instruct git-fetch(1) to fetch all tags, so we
# should now see it.
git -C target fetch origin --tags &&
git -C target tag -l >actual &&
cat >expect <<-\EOF &&
discard-me
fetch-me
EOF
test_cmp expect actual
'
> diff --git a/builtin/fetch.c b/builtin/fetch.c
> index c7ff3480fb..d5aee5af10 100644
> --- a/builtin/fetch.c
> +++ b/builtin/fetch.c
> @@ -1686,6 +1686,42 @@ static void ref_transaction_rejection_handler(const char *refname,
> *data->retcode = 1;
> }
>
> +/*
> + * Commit the reference transaction. If it isn't an atomic transaction, handle
> + * rejected updates as part of using batched updates.
> + */
> +static int commit_ref_transaction(struct ref_transaction **transaction,
> + bool is_atomic, const char *remote_name,
> + struct strbuf *err)
> +{
> + int retcode = ref_transaction_commit(*transaction, err);
> + if (retcode) {
> + /*
> + * Explicitly handle transaction cleanup to avoid
> + * aborting an already closed transaction.
> + */
> + ref_transaction_free(*transaction);
> + *transaction = NULL;
> + }
> +
> + if (*transaction && !is_atomic) {
> + struct ref_rejection_data data = {
> + .conflict_msg_shown = 0,
> + .remote_name = remote_name,
> + .retcode = &retcode,
> + };
> +
> + ref_transaction_for_each_rejected_update(*transaction,
> + ref_transaction_rejection_handler,
> + &data);
> +
> + ref_transaction_free(*transaction);
> + *transaction = NULL;
> + }
Okay. Do we need to discern cases where this is called and we haven't
managed to even queue a single reference update?
> + return retcode;
> +}
> +
> static int do_fetch(struct transport *transport,
> struct refspec *rs,
> const struct fetch_config *config)
Nit: it might make sense to have a preparatory commit that extracts the
function but that is otherwise a no-op change.
> @@ -1826,6 +1862,10 @@ static int do_fetch(struct transport *transport,
>
> if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map,
> &fetch_head, config)) {
> + /* As we're using batched updates, commit any pending updates. */
> + if (!atomic_fetch)
> + commit_ref_transaction(&transaction, false,
> + transport->remote->name, &err);
> retcode = 1;
> goto cleanup;
> }
Hm. Don't we also have to unset the transaction now? Ah, no, you pass
the pointer to the transaction here and set it to `NULL` in
`commit_ref_transaction()`. Makes sense.
> @@ -1848,8 +1888,12 @@ static int do_fetch(struct transport *transport,
> * the transaction and don't commit anything.
> */
> if (backfill_tags(&display_state, transport, transaction, tags_ref_map,
> - &fetch_head, config))
> + &fetch_head, config)) {
> + if (!atomic_fetch)
> + commit_ref_transaction(&transaction, false,
> + transport->remote->name, &err);
> retcode = 1;
> + }
> }
>
> free_refs(tags_ref_map);
We now have three different callsites where we commit the transaction.
It gets better due to the newly introduced function, but it overall
feels somewhat fragile regardless of that.
Thanks!
Patrick
next prev parent reply other threads:[~2025-11-06 11:50 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-03 13:49 [PATCH] fetch: fix non-conflicting tags not being committed Karthik Nayak
2025-11-03 17:53 ` Eric Sunshine
2025-11-03 21:22 ` Karthik Nayak
2025-11-03 20:52 ` Justin Tobler
2025-11-06 8:39 ` [PATCH v2] " Karthik Nayak
2025-11-06 11:50 ` Patrick Steinhardt [this message]
2025-11-06 18:56 ` Junio C Hamano
2025-11-07 13:15 ` Karthik Nayak
2025-11-07 14:07 ` Patrick Steinhardt
2025-11-07 15:13 ` Karthik Nayak
2025-11-06 22:10 ` Justin Tobler
2025-11-07 14:01 ` Karthik Nayak
2025-11-08 21:34 ` [PATCH v3 0/2] " Karthik Nayak
2025-11-08 21:34 ` [PATCH v3 1/2] fetch: extract out reference committing logic Karthik Nayak
2025-11-10 7:34 ` Patrick Steinhardt
2025-11-10 13:11 ` Karthik Nayak
2025-11-08 21:34 ` [PATCH v3 2/2] fetch: fix non-conflicting tags not being committed Karthik Nayak
2025-11-10 7:34 ` Patrick Steinhardt
2025-11-10 13:23 ` Karthik Nayak
2025-11-11 13:27 ` [PATCH v4 0/2] " Karthik Nayak
2025-11-11 13:27 ` [PATCH v4 1/2] fetch: extract out reference committing logic Karthik Nayak
2025-11-11 13:27 ` [PATCH v4 2/2] fetch: fix non-conflicting tags not being committed Karthik Nayak
2025-11-12 6:16 ` Patrick Steinhardt
2025-11-12 8:52 ` Karthik Nayak
2025-11-12 16:34 ` Junio C Hamano
2025-11-13 13:38 ` [PATCH v5 0/2] " Karthik Nayak
2025-11-13 13:38 ` [PATCH v5 1/2] fetch: extract out reference committing logic Karthik Nayak
2025-11-13 13:38 ` [PATCH v5 2/2] fetch: fix non-conflicting tags not being committed Karthik Nayak
2025-11-13 21:23 ` Junio C Hamano
2025-11-15 22:16 ` Karthik Nayak
2025-11-17 0:02 ` Junio C Hamano
2025-11-17 15:38 ` Karthik Nayak
2025-11-18 11:27 ` [PATCH v6 0/3] " Karthik Nayak
2025-11-18 11:27 ` [PATCH v6 1/3] fetch: extract out reference committing logic Karthik Nayak
2025-11-18 11:27 ` [PATCH v6 2/3] fetch: fix non-conflicting tags not being committed Karthik Nayak
2025-11-18 11:27 ` [PATCH v6 3/3] fetch: fix failed batched updates skipping operations Karthik Nayak
2025-11-18 18:03 ` Junio C Hamano
2025-11-19 8:59 ` Karthik Nayak
2025-11-19 21:46 ` [PATCH v7 0/3] fetch: fix non-conflicting tags not being committed Karthik Nayak
2025-11-19 21:46 ` [PATCH v7 1/3] fetch: extract out reference committing logic Karthik Nayak
2025-11-19 21:46 ` [PATCH v7 2/3] fetch: fix non-conflicting tags not being committed Karthik Nayak
2025-11-19 21:46 ` [PATCH v7 3/3] fetch: fix failed batched updates skipping operations Karthik Nayak
2025-11-19 22:20 ` Eric Sunshine
2025-11-19 23:08 ` Junio C Hamano
2025-11-21 11:00 ` Karthik Nayak
2025-11-21 11:13 ` [PATCH v8 0/3] fetch: fix non-conflicting tags not being committed Karthik Nayak
2025-11-21 11:13 ` [PATCH v8 1/3] fetch: extract out reference committing logic Karthik Nayak
2025-11-21 11:13 ` [PATCH v8 2/3] fetch: fix non-conflicting tags not being committed Karthik Nayak
2025-12-01 12:58 ` Patrick Steinhardt
2025-12-02 22:26 ` Karthik Nayak
2025-11-21 11:13 ` [PATCH v8 3/3] fetch: fix failed batched updates skipping operations Karthik Nayak
2025-12-01 12:58 ` Patrick Steinhardt
2025-12-02 22:35 ` Karthik Nayak
2025-11-21 19:58 ` [PATCH v8 0/3] fetch: fix non-conflicting tags not being committed Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aQyLfD_zx0ndCLvU@pks.im \
--to=ps@pks.im \
--cc=debohman@gmail.com \
--cc=git@vger.kernel.org \
--cc=jltobler@gmail.com \
--cc=karthik.188@gmail.com \
--cc=sunshine@sunshineco.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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 NNTP newsgroup(s).