aboutsummaryrefslogtreecommitdiffstats
path: root/builtin/fetch.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2021-12-21 15:03:16 -0800
committerJunio C Hamano <gitster@pobox.com>2021-12-21 15:03:16 -0800
commit13fa77b6899d0068303761c449d9a7e01dd85eb8 (patch)
treeb15e735aa90f701444aaa66ab080695f10a85549 /builtin/fetch.c
parentee1dc493d10d814ceba1a551d9a185b9da627ad8 (diff)
parent593a2a5d0639b4b4f91ff6e6ffb64e72020f8fd8 (diff)
downloadgit-13fa77b6899d0068303761c449d9a7e01dd85eb8.tar.gz
Merge branch 'ak/protect-any-current-branch'
"git fetch" without the "--update-head-ok" option ought to protect a checked out branch from getting updated, to prevent the working tree that checks it out to go out of sync. The code was written before the use of "git worktree" got widespread, and only checked the branch that was checked out in the current worktree, which has been updated. (originally called ak/fetch-not-overwrite-any-current-branch) * ak/protect-any-current-branch: branch: protect branches checked out in all worktrees receive-pack: protect current branch for bare repository worktree receive-pack: clean dead code from update_worktree() fetch: protect branches checked out in all worktrees worktree: simplify find_shared_symref() memory ownership model branch: lowercase error messages receive-pack: lowercase error messages fetch: lowercase error messages
Diffstat (limited to 'builtin/fetch.c')
-rw-r--r--builtin/fetch.c119
1 files changed, 63 insertions, 56 deletions
diff --git a/builtin/fetch.c b/builtin/fetch.c
index f7abbc31ff..e45185cf9c 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -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)
@@ -552,7 +553,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);
@@ -583,7 +584,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;
}
@@ -848,13 +849,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;
@@ -868,16 +868,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;
}
@@ -1067,16 +1068,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;
@@ -1205,7 +1207,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) {
/*
@@ -1298,7 +1301,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;
@@ -1319,10 +1324,8 @@ 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:
@@ -1385,18 +1388,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)
@@ -1414,10 +1417,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);
}
@@ -1451,7 +1454,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;
@@ -1489,12 +1492,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;
@@ -1515,7 +1519,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);
@@ -1533,6 +1537,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)
@@ -1588,7 +1593,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");
@@ -1606,7 +1611,7 @@ static int do_fetch(struct transport *transport,
transport->url);
}
}
- 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;
@@ -1651,11 +1656,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
@@ -1665,11 +1670,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;
}
@@ -1790,7 +1796,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;
}
@@ -1845,7 +1851,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);
@@ -1906,8 +1912,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);
@@ -1942,7 +1948,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]);
@@ -2010,7 +2016,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
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"));
depth = xstrfmt("%d", deepen_relative);
@@ -2047,14 +2053,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]);
@@ -2075,7 +2082,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"));
return 1;
}
if (server_options.nr)