]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/fetch.c
Merge branch 'en/fetch-negotiation-default-fix'
[thirdparty/git.git] / builtin / fetch.c
index 5c329f98358759a0b9a552d528f1f437d6c0087f..6f5e157863923da28c6394cc86f359abb97f9e01 100644 (file)
@@ -28,6 +28,7 @@
 #include "promisor-remote.h"
 #include "commit-graph.h"
 #include "shallow.h"
+#include "worktree.h"
 
 #define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
 
@@ -223,17 +224,22 @@ static struct option builtin_fetch_options[] = {
        OPT_END()
 };
 
-static void unlock_pack(void)
+static void unlock_pack(unsigned int flags)
 {
        if (gtransport)
-               transport_unlock_pack(gtransport);
+               transport_unlock_pack(gtransport, flags);
        if (gsecondary)
-               transport_unlock_pack(gsecondary);
+               transport_unlock_pack(gsecondary, flags);
+}
+
+static void unlock_pack_atexit(void)
+{
+       unlock_pack(0);
 }
 
 static void unlock_pack_on_signal(int signo)
 {
-       unlock_pack();
+       unlock_pack(TRANSPORT_UNLOCK_PACK_IN_SIGNAL_HANDLER);
        sigchain_pop(signo);
        raise(signo);
 }
@@ -553,7 +559,7 @@ static struct ref *get_ref_map(struct remote *remote,
                for (i = 0; i < fetch_refspec->nr; i++)
                        get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
        } else if (refmap.nr) {
-               die("--refmap option is only meaningful with command-line refspec(s).");
+               die("--refmap option is only meaningful with command-line refspec(s)");
        } else {
                /* Use the defaults */
                struct branch *branch = branch_get(NULL);
@@ -584,7 +590,7 @@ static struct ref *get_ref_map(struct remote *remote,
                } else if (!prefetch) {
                        ref_map = get_remote_ref(remote_refs, "HEAD");
                        if (!ref_map)
-                               die(_("Couldn't find remote ref HEAD"));
+                               die(_("couldn't find remote ref HEAD"));
                        ref_map->fetch_head_status = FETCH_HEAD_MERGE;
                        tail = &ref_map->next;
                }
@@ -849,13 +855,12 @@ static void format_display(struct strbuf *display, char code,
 
 static int update_local_ref(struct ref *ref,
                            struct ref_transaction *transaction,
-                           const char *remote,
-                           const struct ref *remote_ref,
-                           struct strbuf *display,
-                           int summary_width)
+                           const char *remote, const struct ref *remote_ref,
+                           struct strbuf *display, int summary_width,
+                           struct worktree **worktrees)
 {
        struct commit *current = NULL, *updated;
-       struct branch *current_branch = branch_get(NULL);
+       const struct worktree *wt;
        const char *pretty_ref = prettify_refname(ref->name);
        int fast_forward = 0;
 
@@ -869,16 +874,17 @@ static int update_local_ref(struct ref *ref,
                return 0;
        }
 
-       if (current_branch &&
-           !strcmp(ref->name, current_branch->name) &&
-           !(update_head_ok || is_bare_repository()) &&
-           !is_null_oid(&ref->old_oid)) {
+       if (!update_head_ok &&
+           (wt = find_shared_symref(worktrees, "HEAD", ref->name)) &&
+           !wt->is_bare && !is_null_oid(&ref->old_oid)) {
                /*
                 * If this is the head, and it's not okay to update
                 * the head, and the old value of the head isn't empty...
                 */
                format_display(display, '!', _("[rejected]"),
-                              _("can't fetch in current branch"),
+                              wt->is_current ?
+                                      _("can't fetch in current branch") :
+                                      _("checked out in another worktree"),
                               remote, pretty_ref, summary_width);
                return 1;
        }
@@ -996,7 +1002,7 @@ static int open_fetch_head(struct fetch_head *fetch_head)
        if (write_fetch_head) {
                fetch_head->fp = fopen(filename, "a");
                if (!fetch_head->fp)
-                       return error_errno(_("cannot open %s"), filename);
+                       return error_errno(_("cannot open '%s'"), filename);
                strbuf_init(&fetch_head->buf, 0);
        } else {
                fetch_head->fp = NULL;
@@ -1068,16 +1074,17 @@ static void close_fetch_head(struct fetch_head *fetch_head)
 }
 
 static const char warn_show_forced_updates[] =
-N_("Fetch normally indicates which branches had a forced update,\n"
-   "but that check has been disabled. To re-enable, use '--show-forced-updates'\n"
-   "flag or run 'git config fetch.showForcedUpdates true'.");
+N_("fetch normally indicates which branches had a forced update,\n"
+   "but that check has been disabled; to re-enable, use '--show-forced-updates'\n"
+   "flag or run 'git config fetch.showForcedUpdates true'");
 static const char warn_time_show_forced_updates[] =
-N_("It took %.2f seconds to check forced updates. You can use\n"
+N_("it took %.2f seconds to check forced updates; you can use\n"
    "'--no-show-forced-updates' or run 'git config fetch.showForcedUpdates false'\n"
-   " to avoid this check.\n");
+   "to avoid this check\n");
 
 static int store_updated_refs(const char *raw_url, const char *remote_name,
-                             int connectivity_checked, struct ref *ref_map)
+                             int connectivity_checked, struct ref *ref_map,
+                             struct worktree **worktrees)
 {
        struct fetch_head fetch_head;
        int url_len, i, rc = 0;
@@ -1206,7 +1213,8 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
                        strbuf_reset(&note);
                        if (ref) {
                                rc |= update_local_ref(ref, transaction, what,
-                                                      rm, &note, summary_width);
+                                                      rm, &note, summary_width,
+                                                      worktrees);
                                free(ref);
                        } else if (write_fetch_head || dry_run) {
                                /*
@@ -1299,7 +1307,9 @@ static int check_exist_and_connected(struct ref *ref_map)
        return check_connected(iterate_ref_map, &rm, &opt);
 }
 
-static int fetch_and_consume_refs(struct transport *transport, struct ref *ref_map)
+static int fetch_and_consume_refs(struct transport *transport,
+                                 struct ref *ref_map,
+                                 struct worktree **worktrees)
 {
        int connectivity_checked = 1;
        int ret;
@@ -1320,14 +1330,12 @@ static int fetch_and_consume_refs(struct transport *transport, struct ref *ref_m
        }
 
        trace2_region_enter("fetch", "consume_refs", the_repository);
-       ret = store_updated_refs(transport->url,
-                                transport->remote->name,
-                                connectivity_checked,
-                                ref_map);
+       ret = store_updated_refs(transport->url, transport->remote->name,
+                                connectivity_checked, ref_map, worktrees);
        trace2_region_leave("fetch", "consume_refs", the_repository);
 
 out:
-       transport_unlock_pack(transport);
+       transport_unlock_pack(transport, 0);
        return ret;
 }
 
@@ -1386,18 +1394,18 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
        return result;
 }
 
-static void check_not_current_branch(struct ref *ref_map)
+static void check_not_current_branch(struct ref *ref_map,
+                                    struct worktree **worktrees)
 {
-       struct branch *current_branch = branch_get(NULL);
-
-       if (is_bare_repository() || !current_branch)
-               return;
-
+       const struct worktree *wt;
        for (; ref_map; ref_map = ref_map->next)
-               if (ref_map->peer_ref && !strcmp(current_branch->refname,
-                                       ref_map->peer_ref->name))
-                       die(_("Refusing to fetch into current branch %s "
-                           "of non-bare repository"), current_branch->refname);
+               if (ref_map->peer_ref &&
+                   (wt = find_shared_symref(worktrees, "HEAD",
+                                            ref_map->peer_ref->name)) &&
+                   !wt->is_bare)
+                       die(_("refusing to fetch into branch '%s' "
+                             "checked out at '%s'"),
+                           ref_map->peer_ref->name, wt->path);
 }
 
 static int truncate_fetch_head(void)
@@ -1406,7 +1414,7 @@ static int truncate_fetch_head(void)
        FILE *fp = fopen_for_writing(filename);
 
        if (!fp)
-               return error_errno(_("cannot open %s"), filename);
+               return error_errno(_("cannot open '%s'"), filename);
        fclose(fp);
        return 0;
 }
@@ -1415,10 +1423,10 @@ static void set_option(struct transport *transport, const char *name, const char
 {
        int r = transport_set_option(transport, name, value);
        if (r < 0)
-               die(_("Option \"%s\" value \"%s\" is not valid for %s"),
+               die(_("option \"%s\" value \"%s\" is not valid for %s"),
                    name, value, transport->url);
        if (r > 0)
-               warning(_("Option \"%s\" is ignored for %s\n"),
+               warning(_("option \"%s\" is ignored for %s\n"),
                        name, transport->url);
 }
 
@@ -1452,7 +1460,7 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
                old_nr = oids->nr;
                for_each_glob_ref(add_oid, s, oids);
                if (old_nr == oids->nr)
-                       warning("Ignoring --negotiation-tip=%s because it does not match any refs",
+                       warning("ignoring --negotiation-tip=%s because it does not match any refs",
                                s);
        }
        smart_options->negotiation_tips = oids;
@@ -1490,12 +1498,13 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
                if (transport->smart_options)
                        add_negotiation_tips(transport->smart_options);
                else
-                       warning("Ignoring --negotiation-tip because the protocol does not support it.");
+                       warning("ignoring --negotiation-tip because the protocol does not support it");
        }
        return transport;
 }
 
-static void backfill_tags(struct transport *transport, struct ref *ref_map)
+static void backfill_tags(struct transport *transport, struct ref *ref_map,
+                         struct worktree **worktrees)
 {
        int cannot_reuse;
 
@@ -1516,7 +1525,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
        transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
        transport_set_option(transport, TRANS_OPT_DEPTH, "0");
        transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
-       fetch_and_consume_refs(transport, ref_map);
+       fetch_and_consume_refs(transport, ref_map, worktrees);
 
        if (gsecondary) {
                transport_disconnect(gsecondary);
@@ -1534,6 +1543,7 @@ static int do_fetch(struct transport *transport,
        struct transport_ls_refs_options transport_ls_refs_options =
                TRANSPORT_LS_REFS_OPTIONS_INIT;
        int must_list_refs = 1;
+       struct worktree **worktrees = get_worktrees();
 
        if (tags == TAGS_DEFAULT) {
                if (transport->remote->fetch_tags == 2)
@@ -1589,7 +1599,7 @@ static int do_fetch(struct transport *transport,
        ref_map = get_ref_map(transport->remote, remote_refs, rs,
                              tags, &autotags);
        if (!update_head_ok)
-               check_not_current_branch(ref_map);
+               check_not_current_branch(ref_map, worktrees);
 
        if (tags == TAGS_DEFAULT && autotags)
                transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
@@ -1600,14 +1610,16 @@ static int do_fetch(struct transport *transport,
                 * don't care whether --tags was specified.
                 */
                if (rs->nr) {
-                       prune_refs(rs, ref_map, transport->url);
+                       retcode = prune_refs(rs, ref_map, transport->url);
                } else {
-                       prune_refs(&transport->remote->fetch,
-                                  ref_map,
-                                  transport->url);
+                       retcode = prune_refs(&transport->remote->fetch,
+                                            ref_map,
+                                            transport->url);
                }
+               if (retcode != 0)
+                       retcode = 1;
        }
-       if (fetch_and_consume_refs(transport, ref_map)) {
+       if (fetch_and_consume_refs(transport, ref_map, worktrees)) {
                free_refs(ref_map);
                retcode = 1;
                goto cleanup;
@@ -1639,6 +1651,16 @@ static int do_fetch(struct transport *transport,
                        }
                }
                if (source_ref) {
+                       if (!branch) {
+                               const char *shortname = source_ref->name;
+                               skip_prefix(shortname, "refs/heads/", &shortname);
+
+                               warning(_("could not set upstream of HEAD to '%s' from '%s' when "
+                                         "it does not point to any branch."),
+                                       shortname, transport->remote->name);
+                               goto skip;
+                       }
+
                        if (!strcmp(source_ref->name, "HEAD") ||
                            starts_with(source_ref->name, "refs/heads/"))
                                install_branch_config(0,
@@ -1652,11 +1674,11 @@ static int do_fetch(struct transport *transport,
                        else
                                warning(_("unknown branch type"));
                } else {
-                       warning(_("no source branch found.\n"
-                               "you need to specify exactly one branch with the --set-upstream option."));
+                       warning(_("no source branch found;\n"
+                                 "you need to specify exactly one branch with the --set-upstream option"));
                }
        }
- skip:
+skip:
        free_refs(ref_map);
 
        /* if neither --no-tags nor --tags was specified, do automated tag
@@ -1666,11 +1688,12 @@ static int do_fetch(struct transport *transport,
                ref_map = NULL;
                find_non_local_tags(remote_refs, &ref_map, &tail);
                if (ref_map)
-                       backfill_tags(transport, ref_map);
+                       backfill_tags(transport, ref_map, worktrees);
                free_refs(ref_map);
        }
 
- cleanup:
+cleanup:
+       free_worktrees(worktrees);
        return retcode;
 }
 
@@ -1791,7 +1814,7 @@ static int fetch_failed_to_start(struct strbuf *out, void *cb, void *task_cb)
        struct parallel_fetch_state *state = cb;
        const char *remote = task_cb;
 
-       state->result = error(_("Could not fetch %s"), remote);
+       state->result = error(_("could not fetch %s"), remote);
 
        return 0;
 }
@@ -1846,7 +1869,7 @@ static int fetch_multiple(struct string_list *list, int max_children)
                        if (verbosity >= 0)
                                printf(_("Fetching %s\n"), name);
                        if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
-                               error(_("Could not fetch %s"), name);
+                               error(_("could not fetch %s"), name);
                                result = 1;
                        }
                        strvec_pop(&argv);
@@ -1907,8 +1930,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
        int remote_via_config = remote_is_configured(remote, 0);
 
        if (!remote)
-               die(_("No remote repository specified.  Please, specify either a URL or a\n"
-                   "remote name from which new revisions should be fetched."));
+               die(_("no remote repository specified; please specify either a URL or a\n"
+                     "remote name from which new revisions should be fetched"));
 
        gtransport = prepare_transport(remote, 1);
 
@@ -1943,7 +1966,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
                if (!strcmp(argv[i], "tag")) {
                        i++;
                        if (i >= argc)
-                               die(_("You need to specify a tag name."));
+                               die(_("you need to specify a tag name"));
 
                        refspec_appendf(&rs, "refs/tags/%s:refs/tags/%s",
                                        argv[i], argv[i]);
@@ -1963,7 +1986,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
                gtransport->server_options = &server_options;
 
        sigchain_push_common(unlock_pack_on_signal);
-       atexit(unlock_pack);
+       atexit(unlock_pack_atexit);
        sigchain_push(SIGPIPE, SIG_IGN);
        exit_code = do_fetch(gtransport, &rs);
        sigchain_pop(SIGPIPE);
@@ -1994,6 +2017,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        }
 
        git_config(git_fetch_config, NULL);
+       prepare_repo_settings(the_repository);
+       the_repository->settings.command_requires_full_index = 0;
 
        argc = parse_options(argc, argv, prefix,
                             builtin_fetch_options, builtin_fetch_usage, 0);
@@ -2029,18 +2054,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        }
 
        if (negotiate_only && !negotiation_tip.nr)
-               die(_("--negotiate-only needs one or more --negotiate-tip=*"));
+               die(_("--negotiate-only needs one or more --negotiation-tip=*"));
 
        if (deepen_relative) {
                if (deepen_relative < 0)
-                       die(_("Negative depth in --deepen is not supported"));
+                       die(_("negative depth in --deepen is not supported"));
                if (depth)
-                       die(_("--deepen and --depth are mutually exclusive"));
+                       die(_("options '%s' and '%s' cannot be used together"), "--deepen", "--depth");
                depth = xstrfmt("%d", deepen_relative);
        }
        if (unshallow) {
                if (depth)
-                       die(_("--depth and --unshallow cannot be used together"));
+                       die(_("options '%s' and '%s' cannot be used together"), "--depth", "--unshallow");
                else if (!is_repository_shallow(the_repository))
                        die(_("--unshallow on a complete repository does not make sense"));
                else
@@ -2070,14 +2095,15 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                /* All arguments are assumed to be remotes or groups */
                for (i = 0; i < argc; i++)
                        if (!add_remote_or_group(argv[i], &list))
-                               die(_("No such remote or remote group: %s"), argv[i]);
+                               die(_("no such remote or remote group: %s"),
+                                   argv[i]);
        } else {
                /* Single remote or group */
                (void) add_remote_or_group(argv[0], &list);
                if (list.nr > 1) {
                        /* More than one remote */
                        if (argc > 1)
-                               die(_("Fetching a group and specifying refspecs does not make sense"));
+                               die(_("fetching a group and specifying refspecs does not make sense"));
                } else {
                        /* Zero or one remotes */
                        remote = remote_get(argv[0]);
@@ -2098,7 +2124,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                if (gtransport->smart_options) {
                        gtransport->smart_options->acked_commits = &acked_commits;
                } else {
-                       warning(_("Protocol does not support --negotiate-only, exiting."));
+                       warning(_("protocol does not support --negotiate-only, exiting"));
                        result = 1;
                        goto cleanup;
                }