From patchwork Thu Sep 19 12:13:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bence Ferdinandy X-Patchwork-Id: 13807682 Received: from aib29agh124.zrh1.oracleemaildelivery.com (aib29agh124.zrh1.oracleemaildelivery.com [192.29.178.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C4851198A37 for ; Thu, 19 Sep 2024 12:20:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.29.178.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726748407; cv=none; b=Ncyle5FhZJSmmYWNXrFDurn41BPqUWbRdjTuG66iU49ee8BxLIH8itutyTsX9VFHqMkPiZ12K+nJGu0RjSSJ5tX22FteOt/8NkfJ9J4sDcO9qt65XFwOFWV7mKwhU3oDkSHcoFVP8VvTpu5HGggIacldMhncwI1H4Wv1KLqM7eg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726748407; c=relaxed/simple; bh=JGqlBryfT98xrSredQ6mWDGr3o5DYY/MjA03aP0K+ew=; h=From:To:Cc:Subject:Date:Message-id:In-reply-to:References: MIME-version; b=foOVIR/aMqwK7Ym4i2gUXkyY7WR4rsU9NPp3wzlrCwroPaxfxlN4ULIeFibUDeAmXV6Blqfn+kol1hb+wG+x9i1zZ//E/OtEe9BaGBetExtjgDnPguVoBMAPUn0JMlkb+jAuNHkNcQ0NuikdSSpI0wnW5QiBgHt/iVRcUbvMsW8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=ferdinandy.com; spf=pass smtp.mailfrom=zrh1.rp.oracleemaildelivery.com; dkim=pass (2048-bit key) header.d=zrh1.rp.oracleemaildelivery.com header.i=@zrh1.rp.oracleemaildelivery.com header.b=NWAbSmbL; arc=none smtp.client-ip=192.29.178.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=ferdinandy.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zrh1.rp.oracleemaildelivery.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=zrh1.rp.oracleemaildelivery.com header.i=@zrh1.rp.oracleemaildelivery.com header.b="NWAbSmbL" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; s=prod-zrh-20200406; d=zrh1.rp.oracleemaildelivery.com; h=Date:To:From:Subject:Message-Id:MIME-Version:Sender:List-Unsubscribe:List-Unsubscribe-Post; bh=OVRj4ESxsVhX3YNddLMMIart2X4C192x1RkNncjcHdY=; b=NWAbSmbLup81jKuapTUfMG6pPe10De01PSWwDuzLQXGGCg4AaEgWYMVV07jRGUafIdlsE9xijZv6 x7xhGiHv0wcSVINNVYEJrd4BEOMzAKuWG0ZIybqUY0/VLeceoKjrFLpGNfol9/WNpAAn5r8tS6P5 kLKr2suIr18LITSY7LcSCVycJ6i/pBSjgzJ0Y6A1AqCrIcTfhexFNByeNZ5YPMjR7Kwk3GgSmbCT to1llb8NdtY8HyPZ5pWKNZSE+IXxtp440YOx5DAzb4vUTY3ku2+ZuwTNbuV3hI5ZHFwo7OeAD//v PG9ZkMKXCn+nP1EYpU4uCPAWRoAm/uWCvRkRxw== Received: by omta-ad1-fd2-401-eu-zurich-1.omtaad1.vcndpzrh.oraclevcn.com (Oracle Communications Messaging Server 8.1.0.1.20240709 64bit (built Jul 9 2024)) with ESMTPS id <0SK20048R7CVPQD0@omta-ad1-fd2-401-eu-zurich-1.omtaad1.vcndpzrh.oraclevcn.com> for git@vger.kernel.org; Thu, 19 Sep 2024 12:14:55 +0000 (GMT) List-Unsubscribe-Post: List-Unsubscribe=One-Click From: Bence Ferdinandy To: git@vger.kernel.org Cc: Junio C Hamano , Taylor Blau , Patrick Steinhardt , =?utf-8?q?Ren=C3=A9_Scharfe?= , Johannes Schindelin , Bence Ferdinandy Subject: [PATCH v3 1/2] update_symref: add REF_CREATE_ONLY option Date: Thu, 19 Sep 2024 14:13:25 +0200 Message-id: <20240919121335.298856-2-bence@ferdinandy.com> In-reply-to: <20240919121335.298856-1-bence@ferdinandy.com> References: <20240919121335.298856-1-bence@ferdinandy.com> Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-version: 1.0 Content-transfer-encoding: 8bit Reporting-Meta: AAF8UFOguL/DO0ghxiHdOacJKVBEcxWiQeVl3d5cpWtIMkUYqE6pk4VfTf20b6C1 u9w+gDLTj8kyew7D3y6gA8fb/Rt6NjggIQvVE23no3toEixtxDkYyCjVN/3QlX4R VJsUjCHq03Cnl8H3VZapxnFJvoG4u7DUpHgBQNMJXjVCIxq9jnV1j83p0ZVHbHrK 1QK8x8fVgORw7D4WlxL58ZB35uT05ImklkO+RUv73/4GKi9jjkCQ539jSz8re7Q5 Al9JFog4hRqaxkCURJUD3lYrpzEZjSAM9FT2gNdnXfmC31w/McH+J3bTX0+PDh4L wPLWcBC3ez3sTLY6ykJRJpZ6OSMaAMo8ah0YMTIuoNbJIdbfEE+rztVNCk44J3Z6 XMbPRJVPUW9+MAxiC+EkHwC4ti0a74D1D2lyUCvlzogEDZ9qkSoEvPPXEweWExj6 QtwLHVjk7YXPTb+XM6mpRXO9hu03rGQnfuDUvCrWdRTi0LTwO2ffhTBp Add a new REF_CREATE_ONLY flag for use by the files backend which will only update the symref if it doesn't already exist. Add the possibility to pass extra flags to refs_update_symref so that it can utilize this new flag. Signed-off-by: Bence Ferdinandy --- Notes: v3: new patch, passes all tests on it's own builtin/branch.c | 2 +- builtin/checkout.c | 4 ++-- builtin/clone.c | 6 +++--- builtin/notes.c | 2 +- builtin/remote.c | 6 +++--- builtin/symbolic-ref.c | 2 +- builtin/worktree.c | 2 +- refs.c | 6 +++--- refs.h | 12 ++++++++++-- refs/files-backend.c | 8 ++++++++ reset.c | 2 +- sequencer.c | 2 +- setup.c | 2 +- t/helper/test-ref-store.c | 2 +- 14 files changed, 37 insertions(+), 21 deletions(-) diff --git a/builtin/branch.c b/builtin/branch.c index c98601c6fe..6025bca45e 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -559,7 +559,7 @@ static int replace_each_worktree_head_symref(struct worktree **worktrees, continue; refs = get_worktree_ref_store(worktrees[i]); - if (refs_update_symref(refs, "HEAD", newref, logmsg)) + if (refs_update_symref(refs, "HEAD", newref, 0, logmsg)) ret = error(_("HEAD of working tree %s is not updated"), worktrees[i]->path); } diff --git a/builtin/checkout.c b/builtin/checkout.c index 4cfe6fab50..23e28321d6 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1011,7 +1011,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts, describe_detached_head(_("HEAD is now at"), new_branch_info->commit); } } else if (new_branch_info->path) { /* Switch branches. */ - if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", new_branch_info->path, msg.buf) < 0) + if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", new_branch_info->path, 0, msg.buf) < 0) die(_("unable to update HEAD")); if (!opts->quiet) { if (old_branch_info->path && !strcmp(new_branch_info->path, old_branch_info->path)) { @@ -1475,7 +1475,7 @@ static int switch_unborn_to_new_branch(const struct checkout_opts *opts) die(_("You are on a branch yet to be born")); strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch); status = refs_update_symref(get_main_ref_store(the_repository), - "HEAD", branch_ref.buf, "checkout -b"); + "HEAD", branch_ref.buf, 0, "checkout -b"); strbuf_release(&branch_ref); if (!opts->quiet) fprintf(stderr, _("Switched to a new branch '%s'\n"), diff --git a/builtin/clone.c b/builtin/clone.c index 269b6e18a4..43b7878a79 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -659,7 +659,7 @@ static void update_remote_refs(const struct ref *refs, strbuf_addstr(&head_ref, branch_top); strbuf_addstr(&head_ref, "HEAD"); if (refs_update_symref(get_main_ref_store(the_repository), head_ref.buf, - remote_head_points_at->peer_ref->name, + remote_head_points_at->peer_ref->name, 0, msg) < 0) die(_("unable to update %s"), head_ref.buf); strbuf_release(&head_ref); @@ -672,7 +672,7 @@ static void update_head(const struct ref *our, const struct ref *remote, const char *head; if (our && skip_prefix(our->name, "refs/heads/", &head)) { /* Local default branch link */ - if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", our->name, NULL) < 0) + if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", our->name, 0, NULL) < 0) die(_("unable to update HEAD")); if (!option_bare) { refs_update_ref(get_main_ref_store(the_repository), @@ -701,7 +701,7 @@ static void update_head(const struct ref *our, const struct ref *remote, * Unborn head from remote; same as "our" case above except * that we have no ref to update. */ - if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", unborn, NULL) < 0) + if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", unborn, 0, NULL) < 0) die(_("unable to update HEAD")); if (!option_bare) install_branch_config(0, head, remote_name, unborn); diff --git a/builtin/notes.c b/builtin/notes.c index 04f9dfb7fb..6b42d1139f 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -978,7 +978,7 @@ static int merge(int argc, const char **argv, const char *prefix) die(_("a notes merge into %s is already in-progress at %s"), default_notes_ref(), wt->path); free_worktrees(worktrees); - if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", default_notes_ref(), NULL)) + if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", default_notes_ref(), 0, NULL)) die(_("failed to store link to current notes ref (%s)"), default_notes_ref()); fprintf(stderr, _("Automatic notes merge failed. Fix conflicts in %s " diff --git a/builtin/remote.c b/builtin/remote.c index 0acc547d69..d28c65599d 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -243,7 +243,7 @@ static int add(int argc, const char **argv, const char *prefix) strbuf_reset(&buf2); strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master); - if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add")) + if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, 0, "remote add")) result = error(_("Could not setup master '%s'"), master); } @@ -863,7 +863,7 @@ static int mv(int argc, const char **argv, const char *prefix) strbuf_reset(&buf3); strbuf_addf(&buf3, "remote: renamed %s to %s", item->string, buf.buf); - if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf)) + if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, 0, buf3.buf)) die(_("creating '%s' failed"), buf.buf); display_progress(progress, ++refs_renamed_nr); } @@ -1443,7 +1443,7 @@ static int set_head(int argc, const char **argv, const char *prefix) /* make sure it's valid */ if (!refs_ref_exists(get_main_ref_store(the_repository), buf2.buf)) result |= error(_("Not a valid ref: %s"), buf2.buf); - else if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote set-head")) + else if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, 0, "remote set-head")) result |= error(_("Could not setup %s"), buf.buf); else if (opt_a) printf("%s/HEAD set to %s\n", argv[0], head_name); diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c index 81abdd170f..52de3e02af 100644 --- a/builtin/symbolic-ref.c +++ b/builtin/symbolic-ref.c @@ -84,7 +84,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) if (check_refname_format(argv[1], REFNAME_ALLOW_ONELEVEL) < 0) die("Refusing to set '%s' to invalid ref '%s'", argv[0], argv[1]); ret = !!refs_update_symref(get_main_ref_store(the_repository), - argv[0], argv[1], msg); + argv[0], argv[1], 0, msg); break; default: usage_with_options(git_symbolic_ref_usage, options); diff --git a/builtin/worktree.c b/builtin/worktree.c index 41e7f6a327..71434737e8 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -517,7 +517,7 @@ static int add_worktree(const char *path, const char *refname, ret = refs_update_ref(wt_refs, NULL, "HEAD", &commit->object.oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR); else - ret = refs_update_symref(wt_refs, "HEAD", symref.buf, NULL); + ret = refs_update_symref(wt_refs, "HEAD", symref.buf, 0, NULL); if (ret) goto done; diff --git a/refs.c b/refs.c index ceb72d4bd7..7afe46cadc 100644 --- a/refs.c +++ b/refs.c @@ -2085,8 +2085,9 @@ int peel_iterated_oid(struct repository *r, const struct object_id *base, struct return peel_object(r, base, peeled) ? -1 : 0; } + int refs_update_symref(struct ref_store *refs, const char *ref, - const char *target, const char *logmsg) + const char *target, const unsigned int extra_flags, const char *logmsg) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; @@ -2095,7 +2096,7 @@ int refs_update_symref(struct ref_store *refs, const char *ref, transaction = ref_store_transaction_begin(refs, &err); if (!transaction || ref_transaction_update(transaction, ref, NULL, NULL, - target, NULL, REF_NO_DEREF, + target, NULL, REF_NO_DEREF | extra_flags, logmsg, &err) || ref_transaction_commit(transaction, &err)) { ret = error("%s", err.buf); @@ -2920,4 +2921,3 @@ int ref_update_expects_existing_old_ref(struct ref_update *update) return (update->flags & REF_HAVE_OLD) && (!is_null_oid(&update->old_oid) || update->old_target); } - diff --git a/refs.h b/refs.h index f8b919a138..d907451d13 100644 --- a/refs.h +++ b/refs.h @@ -569,7 +569,7 @@ int refs_copy_existing_ref(struct ref_store *refs, const char *oldref, const char *newref, const char *logmsg); int refs_update_symref(struct ref_store *refs, const char *refname, - const char *target, const char *logmsg); + const char *target, const unsigned int extra_flags, const char *logmsg); enum action_on_err { UPDATE_REFS_MSG_ON_ERR, @@ -672,13 +672,21 @@ struct ref_transaction *ref_store_transaction_begin(struct ref_store *refs, */ #define REF_SKIP_CREATE_REFLOG (1 << 12) +/* + * If the reference has already been created do not touch it. + */ + +#define REF_CREATE_ONLY (1 << 13) + + /* * Bitmask of all of the flags that are allowed to be passed in to * ref_transaction_update() and friends: */ #define REF_TRANSACTION_UPDATE_ALLOWED_FLAGS \ (REF_NO_DEREF | REF_FORCE_CREATE_REFLOG | REF_SKIP_OID_VERIFICATION | \ - REF_SKIP_REFNAME_VERIFICATION | REF_SKIP_CREATE_REFLOG) + REF_SKIP_REFNAME_VERIFICATION | REF_SKIP_CREATE_REFLOG | \ + REF_CREATE_ONLY) /* * Add a reference update to transaction. `new_oid` is the value that diff --git a/refs/files-backend.c b/refs/files-backend.c index c7f3f4e591..1440b69b87 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -2993,6 +2993,8 @@ static int files_transaction_finish(struct ref_store *ref_store, struct ref_update *update = transaction->updates[i]; struct ref_lock *lock = update->backend_data; + if (update->flags & REF_CREATE_ONLY && refs_ref_exists(ref_store, update->refname)) + continue; if (update->flags & REF_NEEDS_COMMIT || update->flags & REF_LOG_ONLY) { if (parse_and_write_reflog(refs, update, lock, err)) { @@ -3031,6 +3033,8 @@ static int files_transaction_finish(struct ref_store *ref_store, */ for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; + if (update->flags & REF_CREATE_ONLY && refs_ref_exists(ref_store, update->refname)) + continue; if (update->flags & REF_DELETING && !(update->flags & REF_LOG_ONLY) && !(update->flags & REF_IS_PRUNING)) { @@ -3061,6 +3065,8 @@ static int files_transaction_finish(struct ref_store *ref_store, for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; struct ref_lock *lock = update->backend_data; + if (update->flags & REF_CREATE_ONLY && refs_ref_exists(ref_store, update->refname)) + continue; if (update->flags & REF_DELETING && !(update->flags & REF_LOG_ONLY)) { @@ -3085,6 +3091,8 @@ static int files_transaction_finish(struct ref_store *ref_store, for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; + if (update->flags & REF_CREATE_ONLY && refs_ref_exists(ref_store, update->refname)) + continue; if (update->flags & REF_DELETED_RMDIR) { /* diff --git a/reset.c b/reset.c index b22b1be792..8dce5f2133 100644 --- a/reset.c +++ b/reset.c @@ -75,7 +75,7 @@ static int update_refs(const struct reset_head_opts *opts, UPDATE_REFS_MSG_ON_ERR); if (!ret) ret = refs_update_symref(get_main_ref_store(the_repository), - "HEAD", switch_to_branch, + "HEAD", switch_to_branch, 0, reflog_head); } if (!ret && run_hook) diff --git a/sequencer.c b/sequencer.c index 8d01cd50ac..924a78dab8 100644 --- a/sequencer.c +++ b/sequencer.c @@ -5107,7 +5107,7 @@ static int pick_commits(struct repository *r, } msg = reflog_message(opts, "finish", "returning to %s", head_ref.buf); - if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", head_ref.buf, msg)) { + if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", head_ref.buf, 0, msg)) { res = error(_("could not update HEAD to %s"), head_ref.buf); goto cleanup_head_ref; diff --git a/setup.c b/setup.c index 29f8673921..6a1fdef2c3 100644 --- a/setup.c +++ b/setup.c @@ -2169,7 +2169,7 @@ void create_reference_database(enum ref_storage_format ref_storage_format, die(_("invalid initial branch name: '%s'"), initial_branch); - if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", ref, NULL) < 0) + if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", ref, 0, NULL) < 0) exit(1); free(ref); } diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c index 65346dee55..90af41edce 100644 --- a/t/helper/test-ref-store.c +++ b/t/helper/test-ref-store.c @@ -120,7 +120,7 @@ static int cmd_create_symref(struct ref_store *refs, const char **argv) const char *target = notnull(*argv++, "target"); const char *logmsg = *argv++; - return refs_update_symref(refs, refname, target, logmsg); + return refs_update_symref(refs, refname, target, 0, logmsg); } static struct flag_definition transaction_flags[] = { From patchwork Thu Sep 19 12:13:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bence Ferdinandy X-Patchwork-Id: 13807669 Received: from aib29agh125.zrh1.oracleemaildelivery.com (aib29agh125.zrh1.oracleemaildelivery.com [192.29.178.125]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AA331198E99 for ; Thu, 19 Sep 2024 12:15:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.29.178.125 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726748147; cv=none; b=AskBQGpfuPXqYr6fPjhMr5pG8zbOSSJXlSoPsfs3rHzARL7bmY6KvsjCoEhbAGv4iPq/2BApd0JjUcYQ3iK7rFVt2qNYrVCgpFap+e0pTBQ26pNnj44B40YIgvg6L3+uEYy7xUx5r6bLdq9qir86Qy1u+4hk06q9pV2wugV7GKk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1726748147; c=relaxed/simple; bh=lpmkYl36M/BhiLKMTnZ35nYtiyeYceuERQptkGzkCLI=; h=From:To:Cc:Subject:Date:Message-id:In-reply-to:References: MIME-version; b=R4oeQib8jtJP/sXxOVNnb3wk/lpraNFLdjz15r0c24sAGFWgmGE1AM7NUlM713yHsWu6FSFZI8ckKIgYnzD+j36TQXhzb+BBze0n/ZnktiQyywikZ/VeNi/ahe3qOV7QUd3e2px4rnSCBsRBx0vfRuS2jkp6wZ6BmeuYNbu7rgs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=ferdinandy.com; spf=pass smtp.mailfrom=zrh1.rp.oracleemaildelivery.com; dkim=pass (2048-bit key) header.d=zrh1.rp.oracleemaildelivery.com header.i=@zrh1.rp.oracleemaildelivery.com header.b=gL2ULyA0; arc=none smtp.client-ip=192.29.178.125 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=ferdinandy.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zrh1.rp.oracleemaildelivery.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=zrh1.rp.oracleemaildelivery.com header.i=@zrh1.rp.oracleemaildelivery.com header.b="gL2ULyA0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; s=prod-zrh-20200406; d=zrh1.rp.oracleemaildelivery.com; h=Date:To:From:Subject:Message-Id:MIME-Version:Sender:List-Unsubscribe:List-Unsubscribe-Post; bh=1jztEWprNOLqjnyIyE1SXtLsdgMY9G6H9HHzQzyiI/E=; b=gL2ULyA01AUd20eJsc218wQJ3MiSsuVG56Gmzgb8HNfDIVM3kUGdhcEBdnjRTDfcknUiscos2Int cu8f4hk3RptMDqHGCYHbvlVPQG8l+goDY5sguzQFYOkcOxQGLmVbawJKkRIPhKDQIFXWrYUCNxJB MVqwJ/l3WrigerGXQge4bxr+fLrYajc5bxOHO3mE5KqyYn6bCOXfcokp0qhi0hN5AIjr6rml1UdS +7szRF/hy8BNchX06asVb16y+eKuRZ64749khbZKkf0VdMPDKc8vYSrVgJQJSS9bcsSBI/BzRjTz xfs/K/kkCOkmqaoVIIh21GuXXkorz0iZsaBqSw== Received: by omta-ad1-fd2-402-eu-zurich-1.omtaad1.vcndpzrh.oraclevcn.com (Oracle Communications Messaging Server 8.1.0.1.20240709 64bit (built Jul 9 2024)) with ESMTPS id <0SK200EMD7E29570@omta-ad1-fd2-402-eu-zurich-1.omtaad1.vcndpzrh.oraclevcn.com> for git@vger.kernel.org; Thu, 19 Sep 2024 12:15:38 +0000 (GMT) List-Unsubscribe-Post: List-Unsubscribe=One-Click From: Bence Ferdinandy To: git@vger.kernel.org Cc: Junio C Hamano , Taylor Blau , Patrick Steinhardt , =?utf-8?q?Ren=C3=A9_Scharfe?= , Johannes Schindelin , Bence Ferdinandy Subject: [PATCH v3 2/2] fetch: set remote/HEAD if it does not exist Date: Thu, 19 Sep 2024 14:13:26 +0200 Message-id: <20240919121335.298856-3-bence@ferdinandy.com> In-reply-to: <20240919121335.298856-1-bence@ferdinandy.com> References: <20240919121335.298856-1-bence@ferdinandy.com> Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-version: 1.0 Content-transfer-encoding: 8bit Reporting-Meta: AAG9xX/D4s8daHljmGGnp1CSyZk/gLIAnMTOmriCmosDcY56TjqKtj4i+RHVW197 KJNxTvsFHA5dJAucBoNDoCNy0kBC6M5vrP0T17a/EVqRZ7/flEhDNNHfSnt1SIkA jEgffzE73N/zWB6SWfQh4rBTlQQ3tDClHUU2vOoJxcfVcPd9UD2EiDOqvXg2tTtU pjP3nsGr9V3TcUb5pPFqYrbhEN+LRUosjiq2Ek19CzED0HijP19weUimd/Wwu4cn xp4ZZq6TiJLvtFvkWyBFnvTkWpSFt3oqcEoGodEnQ491W9pPXMYYEC+WHZXUoeFG ByjGJBII5Uc/8p0FMeEZ3FfkhcooVAOg0356Hi1Zs8CVEbfIRs3ws0qJPTI9BzGw LXtcX9E7TvGspVlRCSB8zRldJOgXzjCB0DCzx6yWVkO9R8RBzKag6eCaa3kK85J7 xhfYk5FpTgPu2F2GcgIMfdZ/Mv3ukhoOyBWnvR9O+gtkFiF9HHIT575g If the user has remote/HEAD set already and it looks like it has changed on the server, then print a message, otherwise set it if we can. Signed-off-by: Bence Ferdinandy --- Notes: v3: - does not rely on remote set-head anymore so it only authenticates once - uses the new REF_CREATE_ONLY to atomically check if the ref exists and only write it if it doesn't - in all other cases the maximum it does is print a warning builtin/fetch.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/builtin/fetch.c b/builtin/fetch.c index 55f97134aa..2746d40bb5 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1577,6 +1577,70 @@ static int backfill_tags(struct display_state *display_state, return retcode; } +static const char *abbrev_ref(const char *name, const char *prefix) +{ + skip_prefix(name, prefix, &name); + return name; +} +#define abbrev_branch(name) abbrev_ref((name), "refs/heads/") + +static inline int set_head(const struct ref *remote_refs) +{ + int result, ref_changed = 0; + struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT, b_local_head = STRBUF_INIT, b_prefix = STRBUF_INIT; + const char *remote = gtransport->remote->name; + char * head_name = NULL; + struct ref *ref, *matches; + struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; + struct refspec_item refspec = { + .force = 0, + .pattern = 1, + .src = (char *) "refs/heads/*", + .dst = (char *) "refs/heads/*", + }; + struct string_list heads = STRING_LIST_INIT_DUP; + + get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); + matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), + fetch_map, 1); + for (ref = matches; ref; ref = ref->next) + string_list_append(&heads, abbrev_branch(ref->name)); + + + if (!heads.nr) + result = 1; + else if (heads.nr > 1) { + result = 1; + } else + head_name = xstrdup(heads.items[0].string); + if (head_name) { + strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote); + strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name); + strbuf_addf(&b_prefix, "refs/remotes/%s/", remote); + if (!refs_read_symbolic_ref(get_main_ref_store(the_repository),b_head.buf,&b_local_head)) { + ref_changed = strcmp(b_remote_head.buf,b_local_head.buf); + if (heads.nr == 1 && ref_changed) { + printf("The ref \'%s/HEAD\' has changed from the locally recorded " + "\'%s\' to \'%s\'.\n",remote, abbrev_ref(b_local_head.buf,b_prefix.buf), head_name); + printf("Run \'git remote set-head -a %s\' to set it automatically.\n", remote); + } + } + /* make sure it's valid */ + if (!refs_ref_exists(get_main_ref_store(the_repository), b_remote_head.buf)) + result = 1; + else if (refs_update_symref(get_main_ref_store(the_repository), b_head.buf, + b_remote_head.buf, REF_CREATE_ONLY, "fetch")) + result = 1; + free(head_name); + } + + strbuf_release(&b_head); + strbuf_release(&b_local_head); + strbuf_release(&b_remote_head); + strbuf_release(&b_prefix); + return result; +} + static int do_fetch(struct transport *transport, struct refspec *rs, const struct fetch_config *config) @@ -1646,6 +1710,8 @@ static int do_fetch(struct transport *transport, "refs/tags/"); } + strvec_push(&transport_ls_refs_options.ref_prefixes,"HEAD"); + if (must_list_refs) { trace2_region_enter("fetch", "remote_refs", the_repository); remote_refs = transport_get_remote_refs(transport, @@ -1790,6 +1856,10 @@ static int do_fetch(struct transport *transport, "you need to specify exactly one branch with the --set-upstream option")); } } + if (!set_head(remote_refs)) + printf("Ran into issues with \'%s/HEAD\',\n" + "use \'git remote set-head -a %s\' to investigate", + gtransport->remote->name,gtransport->remote->name); cleanup: if (retcode) { @@ -2020,6 +2090,7 @@ static int fetch_multiple(struct string_list *list, int max_children, return !!result; } + /* * Fetching from the promisor remote should use the given filter-spec * or inherit the default filter-spec from the config.