From patchwork Wed Apr 5 01:27:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Felipe Contreras X-Patchwork-Id: 13201105 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 19C1DC6FD1D for ; Wed, 5 Apr 2023 01:27:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236489AbjDEB1t (ORCPT ); Tue, 4 Apr 2023 21:27:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47688 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235732AbjDEB1r (ORCPT ); Tue, 4 Apr 2023 21:27:47 -0400 Received: from mail-oa1-x2d.google.com (mail-oa1-x2d.google.com [IPv6:2001:4860:4864:20::2d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6D9312D43 for ; Tue, 4 Apr 2023 18:27:46 -0700 (PDT) Received: by mail-oa1-x2d.google.com with SMTP id 586e51a60fabf-17ab3a48158so36774987fac.1 for ; Tue, 04 Apr 2023 18:27:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1680658065; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RWarBsVSAlDOB+MYOtvedgeEbXNfbHAixWBFDrblzKE=; b=fvM2LJga5qpCUTBAG+hGtEbHFNUFb2c11JbMrH1Qudfn3+D5cg5jJjgOZnAii4N114 PV9y3qd0xRbbrb22iDtrl2wzHOyP6GjV+IbIi70eidPJyvSdp0U42rBHa3tyHtNm0rRh W0WogznzbfIlMT6NBg42FYEJOiBjO577MN+2WORqn/543pK6iEKo7hLXjc+24KCyKdxw oZl6rzdbAeb5JrSEyq09pOuAvDQ8KYJbKrMwrD02Svi92NKdOyt572WtxIfghDKv43aG eHNiwNAPv9LaBaXPEsWNhhNA5GDMClf2Adq199Kq29Dn7rIrprpQm2KeVpG8drVYbE9l cI/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680658065; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RWarBsVSAlDOB+MYOtvedgeEbXNfbHAixWBFDrblzKE=; b=5I400xaKwUd482bw0YTSW1dQVzQnCrnxjQ341LBvUFGghZPd0+n3CmG3Im9sPYgpR3 fGJ1j3jG5UxB3K8snyYLAWqcdZbTCVMF2Nza21tq0NdAnvnavMPaAxZb7X8p1OUYfKvB XADZiuII5G5tC9lV5TCH6s4tRuS/YYW95xKigRHX5iXvH618WBJ6PU2lMGVkCP/da5nb RVcKZTnUxqUQXJzLYsiJ9guYf0NRcgbqGDySe5bF/OXi9aAysuZyjhtv0RSLP9YITKgk TkBldZgmOY31fvy31+JsFJ3xcRvJYs1fZNh7SjOeiaOrejNORKMnRGTt74Laa9iRcCXJ MErA== X-Gm-Message-State: AAQBX9fk031KSnb1ZaKI3rpoftvLgBsM3N72+5eLgbq1+XHHxWCl28jL r8oEw1/CpBlZV2UCQYUTkrzDcXuJfA8= X-Google-Smtp-Source: AKy350bWNBdN2b7foNi/+qVogXCo1J3KzZrSOSSll263+CR9R1MP6+SKW4jSCxN4xlXNaTKQPTz+2w== X-Received: by 2002:a05:6870:e751:b0:177:b62d:cc1c with SMTP id t17-20020a056870e75100b00177b62dcc1cmr3144582oak.0.1680658065369; Tue, 04 Apr 2023 18:27:45 -0700 (PDT) Received: from localhost ([2806:2f0:4060:fff1:4ae7:daff:fe31:3285]) by smtp.gmail.com with ESMTPSA id b39-20020a056870392700b001765b2f6c53sm5485390oap.9.2023.04.04.18.27.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Apr 2023 18:27:44 -0700 (PDT) From: Felipe Contreras To: git@vger.kernel.org Cc: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= , Jeff King , Patrick Steinhardt , Jonathan Nieder , =?utf-8?q?Daniel_Mart=C3=AD?= , Felipe Contreras Subject: [PATCH 1/2] Add fetch.updateHead option Date: Tue, 4 Apr 2023 19:27:41 -0600 Message-Id: <20230405012742.2452208-2-felipe.contreras@gmail.com> X-Mailer: git-send-email 2.40.0+fc1 In-Reply-To: <20230405012742.2452208-1-felipe.contreras@gmail.com> References: <20230405012742.2452208-1-felipe.contreras@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Users might change the behavior when running "git fetch" so that the remote's HEAD symbolic ref is updated at certain point. For example after running "git remote add" the remote HEAD is not set like it is with "git clone". Setting "fetch.updatehead = missing" would probably be a sensible default that everyone would want, but for now the default behavior is to never update HEAD, so there shouldn't be any functional changes. For the next major version of Git, we might want to change this default. Signed-off-by: Felipe Contreras --- Documentation/config/fetch.txt | 4 +++ Documentation/config/remote.txt | 3 ++ builtin/fetch.c | 64 ++++++++++++++++++++++++++++++++- remote.c | 21 +++++++++++ remote.h | 11 ++++++ t/t5510-fetch.sh | 31 ++++++++++++++++ 6 files changed, 133 insertions(+), 1 deletion(-) diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt index 568f0f75b3..dc147ffb35 100644 --- a/Documentation/config/fetch.txt +++ b/Documentation/config/fetch.txt @@ -120,3 +120,7 @@ fetch.bundleCreationToken:: The creation token values are chosen by the provider serving the specific bundle URI. If you modify the URI at `fetch.bundleURI`, then be sure to remove the value for the `fetch.bundleCreationToken` value before fetching. + +fetch.updateHead:: + Defines when to update the remote HEAD symbolic ref. Values are 'never', + 'missing' (update only when HEAD is missing), and 'always'. diff --git a/Documentation/config/remote.txt b/Documentation/config/remote.txt index 0678b4bcfe..9d739d2ed4 100644 --- a/Documentation/config/remote.txt +++ b/Documentation/config/remote.txt @@ -86,3 +86,6 @@ remote..partialclonefilter:: Changing or clearing this value will only affect fetches for new commits. To fetch associated objects for commits already present in the local object database, use the `--refetch` option of linkgit:git-fetch[1]. + +remote..updateHead:: + Defines when to update the remote HEAD symbolic ref. See `fetch.updateHead`. diff --git a/builtin/fetch.c b/builtin/fetch.c index 7221e57f35..7e93a1aa46 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -59,6 +59,8 @@ static int fetch_prune_tags_config = -1; /* unspecified */ static int prune_tags = -1; /* unspecified */ #define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */ +static int fetch_update_head = FETCH_UPDATE_HEAD_DEFAULT; + static int all, append, dry_run, force, keep, multiple, update_head_ok; static int write_fetch_head = 1; static int verbosity, deepen_relative, set_upstream, refetch; @@ -129,6 +131,9 @@ static int git_fetch_config(const char *k, const char *v, void *cb) return 0; } + if (!strcmp(k, "fetch.updatehead")) + return parse_update_head(&fetch_update_head, k, v); + return git_default_config(k, v, cb); } @@ -1579,6 +1584,47 @@ static int backfill_tags(struct transport *transport, return retcode; } +static void update_head(int config, const struct ref *head, const struct remote *remote) +{ + char *ref, *target; + const char *r; + int flags; + + if (!head || !head->symref || !remote) + return; + + ref = apply_refspecs((struct refspec *)&remote->fetch, "refs/heads/HEAD"); + target = apply_refspecs((struct refspec *)&remote->fetch, head->symref); + + if (!ref || !target) { + warning(_("could not update remote head")); + return; + } + + r = resolve_ref_unsafe(ref, 0, NULL, &flags); + + if (r) { + if (config == FETCH_UPDATE_HEAD_MISSING) { + if (flags & REF_ISSYMREF) + /* already present */ + return; + } else if (config == FETCH_UPDATE_HEAD_ALWAYS) { + if (!strcmp(r, target)) + /* already up-to-date */ + return; + } else + /* should never happen */ + return; + } + + if (!create_symref(ref, target, "remote update head")) { + if (verbosity >= 0) + printf(_("Updated remote '%s' HEAD\n"), remote->name); + } else { + warning(_("could not update remote head")); + } +} + static int do_fetch(struct transport *transport, struct refspec *rs) { @@ -1592,6 +1638,7 @@ static int do_fetch(struct transport *transport, int must_list_refs = 1; struct fetch_head fetch_head = { 0 }; struct strbuf err = STRBUF_INIT; + int need_update_head = 0, update_head_config = 0; if (tags == TAGS_DEFAULT) { if (transport->remote->fetch_tags == 2) @@ -1626,9 +1673,21 @@ static int do_fetch(struct transport *transport, } else { struct branch *branch = branch_get(NULL); - if (transport->remote->fetch.nr) + if (transport->remote->fetch.nr) { + + if (transport->remote->update_head) + update_head_config = transport->remote->update_head; + else + update_head_config = fetch_update_head; + + need_update_head = update_head_config && update_head_config != FETCH_UPDATE_HEAD_NEVER; + + if (need_update_head) + strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD"); refspec_ref_prefixes(&transport->remote->fetch, &transport_ls_refs_options.ref_prefixes); + } + if (branch_has_merge_config(branch) && !strcmp(branch->remote_name, transport->remote->name)) { int i; @@ -1737,6 +1796,9 @@ static int do_fetch(struct transport *transport, commit_fetch_head(&fetch_head); + if (need_update_head) + update_head(update_head_config, find_ref_by_name(remote_refs, "HEAD"), transport->remote); + if (set_upstream) { struct branch *branch = branch_get("HEAD"); struct ref *rm; diff --git a/remote.c b/remote.c index 641b083d90..5f3a9aa53e 100644 --- a/remote.c +++ b/remote.c @@ -344,6 +344,25 @@ static void read_branches_file(struct remote_state *remote_state, remote->fetch_tags = 1; /* always auto-follow */ } +int parse_update_head(int *r, const char *var, const char *value) +{ + if (!r) + return -1; + else if (!value) + return config_error_nonbool(var); + else if (!strcmp(value, "never")) + *r = FETCH_UPDATE_HEAD_NEVER; + else if (!strcmp(value, "missing")) + *r = FETCH_UPDATE_HEAD_MISSING; + else if (!strcmp(value, "always")) + *r = FETCH_UPDATE_HEAD_ALWAYS; + else { + error(_("malformed value for %s: %s"), var, value); + return error(_("must be one of never, missing, or always")); + } + return 0; +} + static int handle_config(const char *key, const char *value, void *cb) { const char *name; @@ -473,6 +492,8 @@ static int handle_config(const char *key, const char *value, void *cb) key, value); } else if (!strcmp(subkey, "vcs")) { return git_config_string(&remote->foreign_vcs, key, value); + } else if (!strcmp(subkey, "updatehead")) { + return parse_update_head(&remote->update_head, key, value); } return 0; } diff --git a/remote.h b/remote.h index 73638cefeb..9dce42d65d 100644 --- a/remote.h +++ b/remote.h @@ -22,6 +22,13 @@ enum { REMOTE_BRANCHES }; +enum { + FETCH_UPDATE_HEAD_DEFAULT = 0, + FETCH_UPDATE_HEAD_NEVER, + FETCH_UPDATE_HEAD_MISSING, + FETCH_UPDATE_HEAD_ALWAYS, +}; + struct rewrite { const char *base; size_t baselen; @@ -97,6 +104,8 @@ struct remote { int prune; int prune_tags; + int update_head; + /** * The configured helper programs to run on the remote side, for * Git-native protocols. @@ -449,4 +458,6 @@ void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); char *relative_url(const char *remote_url, const char *url, const char *up_path); +int parse_update_head(int *r, const char *var, const char *value); + #endif diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index dc44da9c79..dbeb2928ae 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -814,6 +814,37 @@ test_expect_success 'fetch from multiple configured URLs in single remote' ' git fetch multipleurls ' +test_cmp_symbolic_ref () { + git symbolic-ref "$1" >actual && + echo "$2" >expected && + test_cmp expected actual +} + +test_expect_success 'updatehead' ' + test_when_finished "rm -rf updatehead" && + + git init updatehead && + ( + cd updatehead && + + git config fetch.updateHead never && + git remote add origin .. && + git fetch && + test_must_fail git rev-parse --verify refs/remotes/origin/HEAD && + + git config fetch.updateHead missing && + git fetch && + test_cmp_symbolic_ref refs/remotes/origin/HEAD refs/remotes/origin/main && + git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/side && + git fetch && + test_cmp_symbolic_ref refs/remotes/origin/HEAD refs/remotes/origin/side && + + git config fetch.updateHead always && + git fetch && + test_cmp_symbolic_ref refs/remotes/origin/HEAD refs/remotes/origin/main + ) +' + # configured prune tests set_config_tristate () { From patchwork Wed Apr 5 01:27:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Felipe Contreras X-Patchwork-Id: 13201106 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C2B8DC76188 for ; Wed, 5 Apr 2023 01:28:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236534AbjDEB1u (ORCPT ); Tue, 4 Apr 2023 21:27:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47712 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236362AbjDEB1s (ORCPT ); Tue, 4 Apr 2023 21:27:48 -0400 Received: from mail-ot1-x332.google.com (mail-ot1-x332.google.com [IPv6:2607:f8b0:4864:20::332]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B52FA30F8 for ; Tue, 4 Apr 2023 18:27:47 -0700 (PDT) Received: by mail-ot1-x332.google.com with SMTP id d22-20020a9d5e16000000b0069b5252ced7so18320194oti.13 for ; Tue, 04 Apr 2023 18:27:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1680658067; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Zjs0Eyk2JJATu++uEBzMxyKzsqLBqt5SMaD17Naw2Vg=; b=VuQVaQrS+dtedQYEleiVVku7+/yzBLhitHfGhIb9G7WmtnB3DZqaiEWPjUBlnm9N8t fQlCxeTSxCyABZi6xm9qeIOpHuZ6lrXacfrHPYaw+kBVgIBUBWsttrK8jiiuE8/8zY/D 2OgPXQ7TCPXXN3O0ykSuQjEGPucqzOEZw9LE4V7H2hyPLWQ3t7355hqUW+/7ZO6m+icO D2h6p75Hk4VxVmBus3ERwCPzRU4ESxPajtnDoVdmh7dUPXCvQuMoQAbPqZb5VUfBhXgB CO50ZOyEUuxgE0L+VgpSQ53TrzRimgPYzRWfzpxG7xLzAN6EXjzLi+rSMwLH01pSCVvC /kjw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680658067; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Zjs0Eyk2JJATu++uEBzMxyKzsqLBqt5SMaD17Naw2Vg=; b=Sl2qq+mhsYk9fkeaZfngEReCFRpZhujl6zKaNV1m2SLcNn2FB3/XnInCf9wNB+TaGl sg5NvaLyD/0fnG9I+I853hiIsD8mdidmcpIn+1SgT8jPOg0FmD19h7OhRm9oeddc/+R4 j8JTfDtWhbVabcZuCW8vjhFgVW9nAr9a+A2L9UAAloUm2sMN/IRewObeKnv515djmp98 NYcxUhjSh4vl+vYi/YXD0TYoNNLdiXb2A26eSLVj6/f8/3qT8flOKrN7GJ3Kpc0730em q58QXbNKQLV0hnaycplpduM30QXw+zD8LkVGVD25/asPtwcanIws4MEITfwglkmqgfyh VTXw== X-Gm-Message-State: AAQBX9cx4O8RehYrIMNjBrl/dLgSG9y8eaiYSqFcTOJWJpW2BOfFIM0Z vb63EnLJNhQb5l+hEChsDPn7DYScyxE= X-Google-Smtp-Source: AKy350btRbaP6wLh3ZhyAD3TddNMeIXb0oRiPWsYPnYgIFjqAn1ZFBH1tdFTg7QtFIue20Ip6Qyq+Q== X-Received: by 2002:a9d:73cd:0:b0:694:4f92:e7db with SMTP id m13-20020a9d73cd000000b006944f92e7dbmr2199749otk.13.1680658066686; Tue, 04 Apr 2023 18:27:46 -0700 (PDT) Received: from localhost ([2806:2f0:4060:fff1:4ae7:daff:fe31:3285]) by smtp.gmail.com with ESMTPSA id z1-20020a9d7a41000000b006a144b97e73sm6212387otm.74.2023.04.04.18.27.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Apr 2023 18:27:46 -0700 (PDT) From: Felipe Contreras To: git@vger.kernel.org Cc: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= , Jeff King , Patrick Steinhardt , Jonathan Nieder , =?utf-8?q?Daniel_Mart=C3=AD?= , Felipe Contreras Subject: [PATCH 2/2] fetch: add support for HEAD update on mirrors Date: Tue, 4 Apr 2023 19:27:42 -0600 Message-Id: <20230405012742.2452208-3-felipe.contreras@gmail.com> X-Mailer: git-send-email 2.40.0+fc1 In-Reply-To: <20230405012742.2452208-1-felipe.contreras@gmail.com> References: <20230405012742.2452208-1-felipe.contreras@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Signed-off-by: Felipe Contreras --- builtin/fetch.c | 15 ++++++++++----- t/t5510-fetch.sh | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/builtin/fetch.c b/builtin/fetch.c index 7e93a1aa46..6bf147b012 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1593,12 +1593,17 @@ static void update_head(int config, const struct ref *head, const struct remote if (!head || !head->symref || !remote) return; - ref = apply_refspecs((struct refspec *)&remote->fetch, "refs/heads/HEAD"); - target = apply_refspecs((struct refspec *)&remote->fetch, head->symref); + if (!remote->mirror) { + ref = apply_refspecs((struct refspec *)&remote->fetch, "refs/heads/HEAD"); + target = apply_refspecs((struct refspec *)&remote->fetch, head->symref); - if (!ref || !target) { - warning(_("could not update remote head")); - return; + if (!ref || !target) { + warning(_("could not update remote head")); + return; + } + } else { + ref = "HEAD"; + target = head->symref; } r = resolve_ref_unsafe(ref, 0, NULL, &flags); diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index dbeb2928ae..d3f3b24378 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -845,6 +845,24 @@ test_expect_success 'updatehead' ' ) ' +test_expect_success 'updatehead mirror' ' + test_when_finished "rm -rf updatehead" && + + git clone --mirror . updatehead && + ( + cd updatehead && + + git config fetch.updateHead missing && + git symbolic-ref HEAD refs/heads/side && + git fetch && + test_cmp_symbolic_ref HEAD refs/heads/side && + + git config fetch.updateHead always && + git fetch && + test_cmp_symbolic_ref HEAD refs/heads/main + ) +' + # configured prune tests set_config_tristate () {