diff --git a/builtin/fetch.c b/builtin/fetch.c
index 6cbb5f69ecf0946f4028b88563347332d54f65bc..91731b909aeb22bf8d4e366b8b92281ac0f9ac0c 100644 (file)
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
#include "sigchain.h"
#include "transport.h"
#include "submodule.h"
#include "sigchain.h"
#include "transport.h"
#include "submodule.h"
+#include "connected.h"
static const char * const builtin_fetch_usage[] = {
"git fetch [<options>] [<repository> [<refspec>...]]",
static const char * const builtin_fetch_usage[] = {
"git fetch [<options>] [<repository> [<refspec>...]]",
TAGS_SET = 2
};
TAGS_SET = 2
};
-enum {
- RECURSE_SUBMODULES_OFF = 0,
- RECURSE_SUBMODULES_DEFAULT = 1,
- RECURSE_SUBMODULES_ON = 2
-};
-
static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
static int progress, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int tags = TAGS_DEFAULT;
static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
static int progress, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int tags = TAGS_DEFAULT;
static struct strbuf default_rla = STRBUF_INIT;
static struct transport *transport;
static const char *submodule_prefix = "";
static struct strbuf default_rla = STRBUF_INIT;
static struct transport *transport;
static const char *submodule_prefix = "";
+static const char *recurse_submodules_default;
+
+static int option_parse_recurse_submodules(const struct option *opt,
+ const char *arg, int unset)
+{
+ if (unset) {
+ recurse_submodules = RECURSE_SUBMODULES_OFF;
+ } else {
+ if (arg)
+ recurse_submodules = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
+ else
+ recurse_submodules = RECURSE_SUBMODULES_ON;
+ }
+ return 0;
+}
static struct option builtin_fetch_options[] = {
OPT__VERBOSITY(&verbosity),
static struct option builtin_fetch_options[] = {
OPT__VERBOSITY(&verbosity),
"do not fetch all tags (--no-tags)", TAGS_UNSET),
OPT_BOOLEAN('p', "prune", &prune,
"prune remote-tracking branches no longer on remote"),
"do not fetch all tags (--no-tags)", TAGS_UNSET),
OPT_BOOLEAN('p', "prune", &prune,
"prune remote-tracking branches no longer on remote"),
- OPT_SET_INT(0, "recurse-submodules", &recurse_submodules,
+ { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "on-demand",
"control recursive fetching of submodules",
"control recursive fetching of submodules",
- RECURSE_SUBMODULES_ON),
+ PARSE_OPT_OPTARG, option_parse_recurse_submodules },
OPT_BOOLEAN(0, "dry-run", &dry_run,
"dry run"),
OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
OPT_BOOLEAN(0, "dry-run", &dry_run,
"dry run"),
OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
"deepen history of shallow clone"),
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir",
"prepend this to submodule path output", PARSE_OPT_HIDDEN },
"deepen history of shallow clone"),
{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir",
"prepend this to submodule path output", PARSE_OPT_HIDDEN },
+ { OPTION_STRING, 0, "recurse-submodules-default",
+ &recurse_submodules_default, NULL,
+ "default mode for recursion", PARSE_OPT_HIDDEN },
OPT_END()
};
OPT_END()
};
else {
msg = "storing head";
what = _("[new branch]");
else {
msg = "storing head";
what = _("[new branch]");
+ if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
+ (recurse_submodules != RECURSE_SUBMODULES_ON))
+ check_for_new_submodule_commits(ref->new_sha1);
}
r = s_update_ref(msg, ref, 0);
}
r = s_update_ref(msg, ref, 0);
strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
strcat(quickref, "..");
strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
strcat(quickref, "..");
strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
+ if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
+ (recurse_submodules != RECURSE_SUBMODULES_ON))
+ check_for_new_submodule_commits(ref->new_sha1);
r = s_update_ref("fast-forward", ref, 1);
sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ',
TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
r = s_update_ref("fast-forward", ref, 1);
sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ',
TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
strcat(quickref, "...");
strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
strcat(quickref, "...");
strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
+ if ((recurse_submodules != RECURSE_SUBMODULES_OFF) &&
+ (recurse_submodules != RECURSE_SUBMODULES_ON))
+ check_for_new_submodule_commits(ref->new_sha1);
r = s_update_ref("forced-update", ref, 1);
sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+',
TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
r = s_update_ref("forced-update", ref, 1);
sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+',
TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote,
}
}
}
}
+static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+{
+ struct ref **rm = cb_data;
+ struct ref *ref = *rm;
+
+ if (!ref)
+ return -1; /* end of the list */
+ *rm = ref->next;
+ hashcpy(sha1, ref->old_sha1);
+ return 0;
+}
+
static int store_updated_refs(const char *raw_url, const char *remote_name,
struct ref *ref_map)
{
static int store_updated_refs(const char *raw_url, const char *remote_name,
struct ref *ref_map)
{
url = transport_anonymize_url(raw_url);
else
url = xstrdup("foreign");
url = transport_anonymize_url(raw_url);
else
url = xstrdup("foreign");
+
+ rm = ref_map;
+ if (check_everything_connected(iterate_ref_map, 0, &rm)) {
+ rc = error(_("%s did not send all necessary objects\n"), url);
+ goto abort;
+ }
+
for (rm = ref_map; rm; rm = rm->next) {
struct ref *ref = NULL;
for (rm = ref_map; rm; rm = rm->next) {
struct ref *ref = NULL;
fprintf(stderr, " %s\n", note);
}
}
fprintf(stderr, " %s\n", note);
}
}
- free(url);
- fclose(fp);
+
if (rc & STORE_REF_ERROR_DF_CONFLICT)
error(_("some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting "
"branches"), remote_name);
if (rc & STORE_REF_ERROR_DF_CONFLICT)
error(_("some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting "
"branches"), remote_name);
+
+ abort:
+ free(url);
+ fclose(fp);
return rc;
}
return rc;
}
* We would want to bypass the object transfer altogether if
* everything we are going to fetch already exists and is connected
* locally.
* We would want to bypass the object transfer altogether if
* everything we are going to fetch already exists and is connected
* locally.
- *
- * The refs we are going to fetch are in ref_map. If running
- *
- * $ git rev-list --objects --stdin --not --all
- *
- * (feeding all the refs in ref_map on its standard input)
- * does not error out, that means everything reachable from the
- * refs we are going to fetch exists and is connected to some of
- * our existing refs.
*/
static int quickfetch(struct ref *ref_map)
{
*/
static int quickfetch(struct ref *ref_map)
{
- struct child_process revlist;
- struct ref *ref;
- int err;
- const char *argv[] = {"rev-list",
- "--quiet", "--objects", "--stdin", "--not", "--all", NULL};
+ struct ref *rm = ref_map;
/*
* If we are deepening a shallow clone we already have these
/*
* If we are deepening a shallow clone we already have these
*/
if (depth)
return -1;
*/
if (depth)
return -1;
-
- if (!ref_map)
- return 0;
-
- memset(&revlist, 0, sizeof(revlist));
- revlist.argv = argv;
- revlist.git_cmd = 1;
- revlist.no_stdout = 1;
- revlist.no_stderr = 1;
- revlist.in = -1;
-
- err = start_command(&revlist);
- if (err) {
- error(_("could not run rev-list"));
- return err;
- }
-
- /*
- * If rev-list --stdin encounters an unknown commit, it terminates,
- * which will cause SIGPIPE in the write loop below.
- */
- sigchain_push(SIGPIPE, SIG_IGN);
-
- for (ref = ref_map; ref; ref = ref->next) {
- if (write_in_full(revlist.in, sha1_to_hex(ref->old_sha1), 40) < 0 ||
- write_str_in_full(revlist.in, "\n") < 0) {
- if (errno != EPIPE && errno != EINVAL)
- error(_("failed write to rev-list: %s"), strerror(errno));
- err = -1;
- break;
- }
- }
-
- if (close(revlist.in)) {
- error(_("failed to close rev-list's stdin: %s"), strerror(errno));
- err = -1;
- }
-
- sigchain_pop(SIGPIPE);
-
- return finish_command(&revlist) || err;
+ return check_everything_connected(iterate_ref_map, 1, &rm);
}
static int fetch_refs(struct transport *transport, struct ref *ref_map)
}
static int fetch_refs(struct transport *transport, struct ref *ref_map)
return ret;
}
return ret;
}
-static int prune_refs(struct transport *transport, struct ref *ref_map)
+static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map)
{
int result = 0;
{
int result = 0;
- struct ref *ref, *stale_refs = get_stale_heads(transport->remote, ref_map);
+ struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
const char *dangling_msg = dry_run
? _(" (%s will become dangling)\n")
: _(" (%s has become dangling)\n");
const char *dangling_msg = dry_run
? _(" (%s will become dangling)\n")
: _(" (%s has become dangling)\n");
free_refs(ref_map);
return 1;
}
free_refs(ref_map);
return 1;
}
- if (prune)
- prune_refs(transport, ref_map);
+ if (prune) {
+ /* If --tags was specified, pretend the user gave us the canonical tags refspec */
+ if (tags == TAGS_SET) {
+ const char *tags_str = "refs/tags/*:refs/tags/*";
+ struct refspec *tags_refspec, *refspec;
+
+ /* Copy the refspec and add the tags to it */
+ refspec = xcalloc(ref_count + 1, sizeof(struct refspec));
+ tags_refspec = parse_fetch_refspec(1, &tags_str);
+ memcpy(refspec, refs, ref_count * sizeof(struct refspec));
+ memcpy(&refspec[ref_count], tags_refspec, sizeof(struct refspec));
+ ref_count++;
+
+ prune_refs(refspec, ref_count, ref_map);
+
+ ref_count--;
+ /* The rest of the strings belong to fetch_one */
+ free_refspec(1, tags_refspec);
+ free(refspec);
+ } else if (ref_count) {
+ prune_refs(refs, ref_count, ref_map);
+ } else {
+ prune_refs(transport->remote->fetch, transport->remote->fetch_refspec_nr, ref_map);
+ }
+ }
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
argv[(*argc)++] = "--keep";
if (recurse_submodules == RECURSE_SUBMODULES_ON)
argv[(*argc)++] = "--recurse-submodules";
argv[(*argc)++] = "--keep";
if (recurse_submodules == RECURSE_SUBMODULES_ON)
argv[(*argc)++] = "--recurse-submodules";
+ else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
+ argv[(*argc)++] = "--recurse-submodules=on-demand";
if (verbosity >= 2)
argv[(*argc)++] = "-v";
if (verbosity >= 1)
if (verbosity >= 2)
argv[(*argc)++] = "-v";
if (verbosity >= 1)
{
int i;
static const char **refs = NULL;
{
int i;
static const char **refs = NULL;
+ struct refspec *refspec;
int ref_nr = 0;
int exit_code;
int ref_nr = 0;
int exit_code;
sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack);
sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack);
- exit_code = do_fetch(transport,
- parse_fetch_refspec(ref_nr, refs), ref_nr);
+ refspec = parse_fetch_refspec(ref_nr, refs);
+ exit_code = do_fetch(transport, refspec, ref_nr);
+ free_refspec(ref_nr, refspec);
transport_disconnect(transport);
transport = NULL;
return exit_code;
transport_disconnect(transport);
transport = NULL;
return exit_code;
argc = parse_options(argc, argv, prefix,
builtin_fetch_options, builtin_fetch_usage, 0);
argc = parse_options(argc, argv, prefix,
builtin_fetch_options, builtin_fetch_usage, 0);
+ if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
+ if (recurse_submodules_default) {
+ int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default);
+ set_config_fetch_recurse_submodules(arg);
+ }
+ gitmodules_config();
+ git_config(submodule_config, NULL);
+ }
+
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
const char *options[10];
int num_options = 0;
if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
const char *options[10];
int num_options = 0;
- /* Set recursion as default when we already are recursing */
- if (submodule_prefix[0])
- set_config_fetch_recurse_submodules(1);
- gitmodules_config();
- git_config(submodule_config, NULL);
add_options_to_argv(&num_options, options);
result = fetch_populated_submodules(num_options, options,
submodule_prefix,
add_options_to_argv(&num_options, options);
result = fetch_populated_submodules(num_options, options,
submodule_prefix,
- recurse_submodules == RECURSE_SUBMODULES_ON,
+ recurse_submodules,
verbosity < 0);
}
verbosity < 0);
}