summaryrefslogtreecommitdiff
path: root/builtin/fetch.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/fetch.c')
-rw-r--r--builtin/fetch.c359
1 files changed, 205 insertions, 154 deletions
diff --git a/builtin/fetch.c b/builtin/fetch.c
index a0fca93bb6..4d7c289752 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -2,12 +2,18 @@
* "git fetch"
*/
#include "cache.h"
+#include "advice.h"
#include "config.h"
+#include "gettext.h"
+#include "environment.h"
+#include "hex.h"
#include "repository.h"
#include "refs.h"
#include "refspec.h"
+#include "object-name.h"
#include "object-store.h"
#include "oidset.h"
+#include "oid-array.h"
#include "commit.h"
#include "builtin.h"
#include "string-list.h"
@@ -22,13 +28,18 @@
#include "strvec.h"
#include "utf8.h"
#include "packfile.h"
+#include "pager.h"
+#include "pkt-line.h"
#include "list-objects-filter-options.h"
#include "commit-reach.h"
#include "branch.h"
#include "promisor-remote.h"
#include "commit-graph.h"
#include "shallow.h"
+#include "trace.h"
+#include "trace2.h"
#include "worktree.h"
+#include "bundle-uri.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -46,6 +57,16 @@ enum {
TAGS_SET = 2
};
+struct display_state {
+ struct strbuf buf;
+
+ int refcol_width;
+ int compact_format;
+
+ char *url;
+ int url_len, shown_url;
+};
+
static int fetch_prune_config = -1; /* unspecified */
static int fetch_show_forced_updates = 1;
static uint64_t forced_updates_ms = 0;
@@ -78,7 +99,6 @@ static const char *submodule_prefix = "";
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
-static int shown_url = 0;
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
static struct string_list server_options = STRING_LIST_INIT_DUP;
@@ -122,6 +142,8 @@ static int git_fetch_config(const char *k, const char *v, void *cb)
fetch_parallel_config = git_config_int(k, v);
if (fetch_parallel_config < 0)
die(_("fetch.parallel cannot be negative"));
+ if (!fetch_parallel_config)
+ fetch_parallel_config = online_cpus();
return 0;
}
@@ -404,9 +426,9 @@ static void find_non_local_tags(const struct ref *refs,
*/
if (ends_with(ref->name, "^{}")) {
if (item &&
- !has_object_file_with_flags(&ref->old_oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &ref->old_oid, quick_flags) &&
!oidset_contains(&fetch_oids, &ref->old_oid) &&
- !has_object_file_with_flags(&item->oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
item = NULL;
@@ -420,7 +442,7 @@ static void find_non_local_tags(const struct ref *refs,
* fetch.
*/
if (item &&
- !has_object_file_with_flags(&item->oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
@@ -441,7 +463,7 @@ static void find_non_local_tags(const struct ref *refs,
* checked to see if it needs fetching.
*/
if (item &&
- !has_object_file_with_flags(&item->oid, quick_flags) &&
+ !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
!oidset_contains(&fetch_oids, &item->oid))
clear_item(item);
@@ -738,16 +760,13 @@ out:
return ret;
}
-static int refcol_width = 10;
-static int compact_format;
-
-static void adjust_refcol_width(const struct ref *ref)
+static int refcol_width(const struct ref *ref, int compact_format)
{
int max, rlen, llen, len;
/* uptodate lines are only shown on high verbosity level */
if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
- return;
+ return 0;
max = term_columns();
rlen = utf8_strwidth(prettify_refname(ref->name));
@@ -766,48 +785,78 @@ static void adjust_refcol_width(const struct ref *ref)
}
len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
if (len >= max)
- return;
+ return 0;
- /*
- * Not precise calculation for compact mode because '*' can
- * appear on the left hand side of '->' and shrink the column
- * back.
- */
- if (refcol_width < rlen)
- refcol_width = rlen;
+ return rlen;
}
-static void prepare_format_display(struct ref *ref_map)
+static void display_state_init(struct display_state *display_state, struct ref *ref_map,
+ const char *raw_url)
{
struct ref *rm;
const char *format = "full";
+ int i;
+
+ memset(display_state, 0, sizeof(*display_state));
+
+ strbuf_init(&display_state->buf, 0);
+
+ if (raw_url)
+ display_state->url = transport_anonymize_url(raw_url);
+ else
+ display_state->url = xstrdup("foreign");
+
+ display_state->url_len = strlen(display_state->url);
+ for (i = display_state->url_len - 1; display_state->url[i] == '/' && 0 <= i; i--)
+ ;
+ display_state->url_len = i + 1;
+ if (4 < i && !strncmp(".git", display_state->url + i - 3, 4))
+ display_state->url_len = i - 3;
if (verbosity < 0)
return;
git_config_get_string_tmp("fetch.output", &format);
if (!strcasecmp(format, "full"))
- compact_format = 0;
+ display_state->compact_format = 0;
else if (!strcasecmp(format, "compact"))
- compact_format = 1;
+ display_state->compact_format = 1;
else
die(_("invalid value for '%s': '%s'"),
"fetch.output", format);
+ display_state->refcol_width = 10;
for (rm = ref_map; rm; rm = rm->next) {
+ int width;
+
if (rm->status == REF_STATUS_REJECT_SHALLOW ||
!rm->peer_ref ||
!strcmp(rm->name, "HEAD"))
continue;
- adjust_refcol_width(rm);
+ width = refcol_width(rm, display_state->compact_format);
+
+ /*
+ * Not precise calculation for compact mode because '*' can
+ * appear on the left hand side of '->' and shrink the column
+ * back.
+ */
+ if (display_state->refcol_width < width)
+ display_state->refcol_width = width;
}
}
-static void print_remote_to_local(struct strbuf *display,
+static void display_state_release(struct display_state *display_state)
+{
+ strbuf_release(&display_state->buf);
+ free(display_state->url);
+}
+
+static void print_remote_to_local(struct display_state *display_state,
const char *remote, const char *local)
{
- strbuf_addf(display, "%-*s -> %s", refcol_width, remote, local);
+ strbuf_addf(&display_state->buf, "%-*s -> %s",
+ display_state->refcol_width, remote, local);
}
static int find_and_replace(struct strbuf *haystack,
@@ -837,14 +886,14 @@ static int find_and_replace(struct strbuf *haystack,
return 1;
}
-static void print_compact(struct strbuf *display,
+static void print_compact(struct display_state *display_state,
const char *remote, const char *local)
{
struct strbuf r = STRBUF_INIT;
struct strbuf l = STRBUF_INIT;
if (!strcmp(remote, local)) {
- strbuf_addf(display, "%-*s -> *", refcol_width, remote);
+ strbuf_addf(&display_state->buf, "%-*s -> *", display_state->refcol_width, remote);
return;
}
@@ -853,40 +902,51 @@ static void print_compact(struct strbuf *display,
if (!find_and_replace(&r, local, "*"))
find_and_replace(&l, remote, "*");
- print_remote_to_local(display, r.buf, l.buf);
+ print_remote_to_local(display_state, r.buf, l.buf);
strbuf_release(&r);
strbuf_release(&l);
}
-static void format_display(struct strbuf *display, char code,
- const char *summary, const char *error,
- const char *remote, const char *local,
- int summary_width)
+static void display_ref_update(struct display_state *display_state, char code,
+ const char *summary, const char *error,
+ const char *remote, const char *local,
+ int summary_width)
{
int width;
if (verbosity < 0)
return;
+ strbuf_reset(&display_state->buf);
+
+ if (!display_state->shown_url) {
+ strbuf_addf(&display_state->buf, _("From %.*s\n"),
+ display_state->url_len, display_state->url);
+ display_state->shown_url = 1;
+ }
+
width = (summary_width + strlen(summary) - gettext_width(summary));
- strbuf_addf(display, "%c %-*s ", code, width, summary);
- if (!compact_format)
- print_remote_to_local(display, remote, local);
+ strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary);
+ if (!display_state->compact_format)
+ print_remote_to_local(display_state, remote, prettify_refname(local));
else
- print_compact(display, remote, local);
+ print_compact(display_state, remote, prettify_refname(local));
if (error)
- strbuf_addf(display, " (%s)", error);
+ strbuf_addf(&display_state->buf, " (%s)", error);
+ strbuf_addch(&display_state->buf, '\n');
+
+ fputs(display_state->buf.buf, stderr);
}
static int update_local_ref(struct ref *ref,
struct ref_transaction *transaction,
+ struct display_state *display_state,
const char *remote, const struct ref *remote_ref,
- struct strbuf *display, int summary_width)
+ int summary_width)
{
struct commit *current = NULL, *updated;
- const char *pretty_ref = prettify_refname(ref->name);
int fast_forward = 0;
if (!repo_has_object_file(the_repository, &ref->new_oid))
@@ -894,8 +954,8 @@ static int update_local_ref(struct ref *ref,
if (oideq(&ref->old_oid, &ref->new_oid)) {
if (verbosity > 0)
- format_display(display, '=', _("[up to date]"), NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '=', _("[up to date]"), NULL,
+ remote, ref->name, summary_width);
return 0;
}
@@ -906,9 +966,9 @@ static int update_local_ref(struct ref *ref,
* 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 into checked-out branch"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '!', _("[rejected]"),
+ _("can't fetch into checked-out branch"),
+ remote, ref->name, summary_width);
return 1;
}
@@ -917,13 +977,14 @@ static int update_local_ref(struct ref *ref,
if (force || ref->force) {
int r;
r = s_update_ref("updating tag", ref, transaction, 0);
- format_display(display, r ? '!' : 't', _("[tag update]"),
- r ? _("unable to update local ref") : NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : 't', _("[tag update]"),
+ r ? _("unable to update local ref") : NULL,
+ remote, ref->name, summary_width);
return r;
} else {
- format_display(display, '!', _("[rejected]"), _("would clobber existing tag"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '!', _("[rejected]"),
+ _("would clobber existing tag"),
+ remote, ref->name, summary_width);
return 1;
}
}
@@ -954,15 +1015,16 @@ static int update_local_ref(struct ref *ref,
}
r = s_update_ref(msg, ref, transaction, 0);
- format_display(display, r ? '!' : '*', what,
- r ? _("unable to update local ref") : NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : '*', what,
+ r ? _("unable to update local ref") : NULL,
+ remote, ref->name, summary_width);
return r;
}
if (fetch_show_forced_updates) {
uint64_t t_before = getnanotime();
- fast_forward = in_merge_bases(current, updated);
+ fast_forward = repo_in_merge_bases(the_repository, current,
+ updated);
forced_updates_ms += (getnanotime() - t_before) / 1000000;
} else {
fast_forward = 1;
@@ -976,9 +1038,9 @@ static int update_local_ref(struct ref *ref,
strbuf_addstr(&quickref, "..");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
r = s_update_ref("fast-forward", ref, transaction, 1);
- format_display(display, r ? '!' : ' ', quickref.buf,
- r ? _("unable to update local ref") : NULL,
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : ' ', quickref.buf,
+ r ? _("unable to update local ref") : NULL,
+ remote, ref->name, summary_width);
strbuf_release(&quickref);
return r;
} else if (force || ref->force) {
@@ -988,14 +1050,14 @@ static int update_local_ref(struct ref *ref,
strbuf_addstr(&quickref, "...");
strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
r = s_update_ref("forced-update", ref, transaction, 1);
- format_display(display, r ? '!' : '+', quickref.buf,
- r ? _("unable to update local ref") : _("forced update"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, r ? '!' : '+', quickref.buf,
+ r ? _("unable to update local ref") : _("forced update"),
+ remote, ref->name, summary_width);
strbuf_release(&quickref);
return r;
} else {
- format_display(display, '!', _("[rejected]"), _("non-fast-forward"),
- remote, pretty_ref, summary_width);
+ display_ref_update(display_state, '!', _("[rejected]"), _("non-fast-forward"),
+ remote, ref->name, summary_width);
return 1;
}
}
@@ -1105,39 +1167,34 @@ 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");
-static int store_updated_refs(const char *raw_url, const char *remote_name,
+static int store_updated_refs(struct display_state *display_state,
+ const char *remote_name,
int connectivity_checked,
struct ref_transaction *transaction, struct ref *ref_map,
struct fetch_head *fetch_head)
{
- int url_len, i, rc = 0;
+ int rc = 0;
struct strbuf note = STRBUF_INIT;
const char *what, *kind;
struct ref *rm;
- char *url;
int want_status;
int summary_width = 0;
if (verbosity >= 0)
summary_width = transport_summary_width(ref_map);
- if (raw_url)
- url = transport_anonymize_url(raw_url);
- else
- url = xstrdup("foreign");
-
if (!connectivity_checked) {
struct check_connected_options opt = CHECK_CONNECTED_INIT;
+ opt.exclude_hidden_refs_section = "fetch";
rm = ref_map;
if (check_connected(iterate_ref_map, &rm, &opt)) {
- rc = error(_("%s did not send all necessary objects\n"), url);
+ rc = error(_("%s did not send all necessary objects\n"),
+ display_state->url);
goto abort;
}
}
- prepare_format_display(ref_map);
-
/*
* We do a pass for each fetch_head_status type in their enum order, so
* merged entries are written before not-for-merge. That lets readers
@@ -1217,13 +1274,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
what = rm->name;
}
- url_len = strlen(url);
- for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
- ;
- url_len = i + 1;
- if (4 < i && !strncmp(".git", url + i - 3, 4))
- url_len = i - 3;
-
strbuf_reset(&note);
if (*what) {
if (*kind)
@@ -1233,12 +1283,12 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
append_fetch_head(fetch_head, &rm->old_oid,
rm->fetch_head_status,
- note.buf, url, url_len);
+ note.buf, display_state->url,
+ display_state->url_len);
- strbuf_reset(&note);
if (ref) {
- rc |= update_local_ref(ref, transaction, what,
- rm, &note, summary_width);
+ rc |= update_local_ref(ref, transaction, display_state, what,
+ rm, summary_width);
free(ref);
} else if (write_fetch_head || dry_run) {
/*
@@ -1246,18 +1296,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
* would be written to FETCH_HEAD, if --dry-run
* is set).
*/
- format_display(&note, '*',
- *kind ? kind : "branch", NULL,
- *what ? what : "HEAD",
- "FETCH_HEAD", summary_width);
- }
- if (note.len) {
- if (!shown_url) {
- fprintf(stderr, _("From %.*s\n"),
- url_len, url);
- shown_url = 1;
- }
- fprintf(stderr, " %s\n", note.buf);
+ display_ref_update(display_state, '*',
+ *kind ? kind : "branch", NULL,
+ *what ? what : "HEAD",
+ "FETCH_HEAD", summary_width);
}
}
}
@@ -1278,7 +1320,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
abort:
strbuf_release(&note);
- free(url);
return rc;
}
@@ -1316,16 +1357,18 @@ static int check_exist_and_connected(struct ref *ref_map)
* we need all direct targets to exist.
*/
for (r = rm; r; r = r->next) {
- if (!has_object_file_with_flags(&r->old_oid,
- OBJECT_INFO_SKIP_FETCH_OBJECT))
+ if (!repo_has_object_file_with_flags(the_repository, &r->old_oid,
+ OBJECT_INFO_SKIP_FETCH_OBJECT))
return -1;
}
opt.quiet = 1;
+ opt.exclude_hidden_refs_section = "fetch";
return check_connected(iterate_ref_map, &rm, &opt);
}
-static int fetch_and_consume_refs(struct transport *transport,
+static int fetch_and_consume_refs(struct display_state *display_state,
+ struct transport *transport,
struct ref_transaction *transaction,
struct ref *ref_map,
struct fetch_head *fetch_head)
@@ -1349,7 +1392,7 @@ static int fetch_and_consume_refs(struct transport *transport,
}
trace2_region_enter("fetch", "consume_refs", the_repository);
- ret = store_updated_refs(transport->url, transport->remote->name,
+ ret = store_updated_refs(display_state, transport->remote->name,
connectivity_checked, transaction, ref_map,
fetch_head);
trace2_region_leave("fetch", "consume_refs", the_repository);
@@ -1359,32 +1402,18 @@ out:
return ret;
}
-static int prune_refs(struct refspec *rs,
+static int prune_refs(struct display_state *display_state,
+ struct refspec *rs,
struct ref_transaction *transaction,
- struct ref *ref_map,
- const char *raw_url)
+ struct ref *ref_map)
{
- int url_len, i, result = 0;
+ int result = 0;
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
struct strbuf err = STRBUF_INIT;
- char *url;
const char *dangling_msg = dry_run
? _(" (%s will become dangling)")
: _(" (%s has become dangling)");
- if (raw_url)
- url = transport_anonymize_url(raw_url);
- else
- url = xstrdup("foreign");
-
- url_len = strlen(url);
- for (i = url_len - 1; url[i] == '/' && 0 <= i; i--)
- ;
-
- url_len = i + 1;
- if (4 < i && !strncmp(".git", url + i - 3, 4))
- url_len = i - 3;
-
if (!dry_run) {
if (transaction) {
for (ref = stale_refs; ref; ref = ref->next) {
@@ -1408,23 +1437,15 @@ static int prune_refs(struct refspec *rs,
int summary_width = transport_summary_width(stale_refs);
for (ref = stale_refs; ref; ref = ref->next) {
- struct strbuf sb = STRBUF_INIT;
- if (!shown_url) {
- fprintf(stderr, _("From %.*s\n"), url_len, url);
- shown_url = 1;
- }
- format_display(&sb, '-', _("[deleted]"), NULL,
- _("(none)"), prettify_refname(ref->name),
- summary_width);
- fprintf(stderr, " %s\n",sb.buf);
- strbuf_release(&sb);
+ display_ref_update(display_state, '-', _("[deleted]"), NULL,
+ _("(none)"), ref->name,
+ summary_width);
warn_dangling_symref(stderr, dangling_msg, ref->name);
}
}
cleanup:
strbuf_release(&err);
- free(url);
free_refs(stale_refs);
return result;
}
@@ -1484,7 +1505,7 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
int old_nr;
if (!has_glob_specials(s)) {
struct object_id oid;
- if (get_oid(s, &oid))
+ if (repo_get_oid(the_repository, s, &oid))
die(_("%s is not a valid object"), s);
if (!has_object(the_repository, &oid, 0))
die(_("the object %s does not exist"), s);
@@ -1539,7 +1560,8 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
return transport;
}
-static int backfill_tags(struct transport *transport,
+static int backfill_tags(struct display_state *display_state,
+ struct transport *transport,
struct ref_transaction *transaction,
struct ref *ref_map,
struct fetch_head *fetch_head)
@@ -1563,7 +1585,7 @@ static int backfill_tags(struct transport *transport,
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);
- retcode = fetch_and_consume_refs(transport, transaction, ref_map, fetch_head);
+ retcode = fetch_and_consume_refs(display_state, transport, transaction, ref_map, fetch_head);
if (gsecondary) {
transport_disconnect(gsecondary);
@@ -1578,6 +1600,7 @@ static int do_fetch(struct transport *transport,
{
struct ref_transaction *transaction = NULL;
struct ref *ref_map = NULL;
+ struct display_state display_state = { 0 };
int autotags = (transport->remote->fetch_tags == 1);
int retcode = 0;
const struct ref *remote_refs;
@@ -1659,6 +1682,8 @@ static int do_fetch(struct transport *transport,
if (retcode)
goto cleanup;
+ display_state_init(&display_state, ref_map, transport->url);
+
if (atomic_fetch) {
transaction = ref_transaction_begin(&err);
if (!transaction) {
@@ -1676,17 +1701,16 @@ static int do_fetch(struct transport *transport,
* don't care whether --tags was specified.
*/
if (rs->nr) {
- retcode = prune_refs(rs, transaction, ref_map, transport->url);
+ retcode = prune_refs(&display_state, rs, transaction, ref_map);
} else {
- retcode = prune_refs(&transport->remote->fetch,
- transaction, ref_map,
- transport->url);
+ retcode = prune_refs(&display_state, &transport->remote->fetch,
+ transaction, ref_map);
}
if (retcode != 0)
retcode = 1;
}
- if (fetch_and_consume_refs(transport, transaction, ref_map, &fetch_head)) {
+ if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map, &fetch_head)) {
retcode = 1;
goto cleanup;
}
@@ -1708,7 +1732,7 @@ static int do_fetch(struct transport *transport,
* when `--atomic` is passed: in that case we'll abort
* the transaction and don't commit anything.
*/
- if (backfill_tags(transport, transaction, tags_ref_map,
+ if (backfill_tags(&display_state, transport, transaction, tags_ref_map,
&fetch_head))
retcode = 1;
}
@@ -1791,6 +1815,7 @@ cleanup:
error("%s", err.buf);
}
+ display_state_release(&display_state);
close_fetch_head(&fetch_head);
strbuf_release(&err);
free_refs(ref_map);
@@ -1877,6 +1902,8 @@ static void add_options_to_argv(struct strvec *argv)
strvec_push(argv, "--ipv4");
else if (family == TRANSPORT_FAMILY_IPV6)
strvec_push(argv, "--ipv6");
+ if (!write_fetch_head)
+ strvec_push(argv, "--no-write-fetch-head");
}
/* Fetch multiple remotes in parallel */
@@ -1887,7 +1914,8 @@ struct parallel_fetch_state {
int next, result;
};
-static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
+static int fetch_next_remote(struct child_process *cp,
+ struct strbuf *out UNUSED,
void *cb, void **task_cb)
{
struct parallel_fetch_state *state = cb;
@@ -1909,7 +1937,8 @@ static int fetch_next_remote(struct child_process *cp, struct strbuf *out,
return 1;
}
-static int fetch_failed_to_start(struct strbuf *out, void *cb, void *task_cb)
+static int fetch_failed_to_start(struct strbuf *out UNUSED,
+ void *cb, void *task_cb)
{
struct parallel_fetch_state *state = cb;
const char *remote = task_cb;
@@ -1945,34 +1974,47 @@ static int fetch_multiple(struct string_list *list, int max_children)
return errcode;
}
- strvec_pushl(&argv, "fetch", "--append", "--no-auto-gc",
+ /*
+ * Cancel out the fetch.bundleURI config when running subprocesses,
+ * to avoid fetching from the same bundle list multiple times.
+ */
+ strvec_pushl(&argv, "-c", "fetch.bundleURI=",
+ "fetch", "--append", "--no-auto-gc",
"--no-write-commit-graph", NULL);
add_options_to_argv(&argv);
if (max_children != 1 && list->nr != 1) {
struct parallel_fetch_state state = { argv.v, list, 0, 0 };
+ const struct run_process_parallel_opts opts = {
+ .tr2_category = "fetch",
+ .tr2_label = "parallel/fetch",
+
+ .processes = max_children,
+
+ .get_next_task = &fetch_next_remote,
+ .start_failure = &fetch_failed_to_start,
+ .task_finished = &fetch_finished,
+ .data = &state,
+ };
strvec_push(&argv, "--end-of-options");
- result = run_processes_parallel_tr2(max_children,
- &fetch_next_remote,
- &fetch_failed_to_start,
- &fetch_finished,
- &state,
- "fetch", "parallel/fetch");
-
- if (!result)
- result = state.result;
+
+ run_processes_parallel(&opts);
+ result = state.result;
} else
for (i = 0; i < list->nr; i++) {
const char *name = list->items[i].string;
- strvec_push(&argv, name);
+ struct child_process cmd = CHILD_PROCESS_INIT;
+
+ strvec_pushv(&cmd.args, argv.v);
+ strvec_push(&cmd.args, name);
if (verbosity >= 0)
printf(_("Fetching %s\n"), name);
- if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
+ cmd.git_cmd = 1;
+ if (run_command(&cmd)) {
error(_("could not fetch %s"), name);
result = 1;
}
- strvec_pop(&argv);
}
strvec_clear(&argv);
@@ -1996,7 +2038,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)
* If no prior partial clone/fetch and the current fetch DID NOT
* request a partial-fetch, do a normal fetch.
*/
- if (!has_promisor_remote() && !filter_options.choice)
+ if (!repo_has_promisor_remote(the_repository) && !filter_options.choice)
return;
/*
@@ -2099,6 +2141,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
int cmd_fetch(int argc, const char **argv, const char *prefix)
{
int i;
+ const char *bundle_uri;
struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote = NULL;
int result = 0;
@@ -2184,6 +2227,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (dry_run)
write_fetch_head = 0;
+ if (!max_jobs)
+ max_jobs = online_cpus();
+
+ if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri) &&
+ fetch_bundle_uri(the_repository, bundle_uri, NULL))
+ warning(_("failed to fetch bundles from '%s'"), bundle_uri);
+
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
@@ -2218,6 +2268,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
argv++;
}
}
+ string_list_remove_duplicates(&list, 0);
if (negotiate_only) {
struct oidset acked_commits = OIDSET_INIT;
@@ -2243,7 +2294,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
printf("%s\n", oid_to_hex(oid));
oidset_clear(&acked_commits);
} else if (remote) {
- if (filter_options.choice || has_promisor_remote())
+ if (filter_options.choice || repo_has_promisor_remote(the_repository))
fetch_one_setup_partial(remote);
result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs);
} else {