#define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by 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;
static int progress = -1;
static int enable_auto_gc = 1;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
static int fetch_write_commit_graph = -1;
+static int stdin_refspecs = 0;
static int git_fetch_config(const char *k, const char *v, void *cb)
{
PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
OPT_BOOL(0, "dry-run", &dry_run,
N_("dry run")),
+ OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
+ N_("write fetched references to the FETCH_HEAD file")),
OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
OPT_BOOL('u', "update-head-ok", &update_head_ok,
N_("allow updating of HEAD ref")),
N_("check for forced-updates on all updated branches")),
OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
N_("write the commit-graph after fetching")),
+ OPT_BOOL(0, "stdin", &stdin_refspecs,
+ N_("accept refspecs from stdin")),
OPT_END()
};
struct ref *orefs = NULL, **oref_tail = &orefs;
struct hashmap existing_refs;
+ int existing_refs_populated = 0;
if (rs->nr) {
struct refspec *fetch_refspec;
ref_map = ref_remove_duplicates(ref_map);
- refname_hash_init(&existing_refs);
- for_each_ref(add_one_refname, &existing_refs);
-
for (rm = ref_map; rm; rm = rm->next) {
if (rm->peer_ref) {
const char *refname = rm->peer_ref->name;
struct refname_hash_entry *peer_item;
unsigned int hash = strhash(refname);
+ if (!existing_refs_populated) {
+ refname_hash_init(&existing_refs);
+ for_each_ref(add_one_refname, &existing_refs);
+ existing_refs_populated = 1;
+ }
+
peer_item = hashmap_get_entry_from_hash(&existing_refs,
hash, refname,
struct refname_hash_entry, ent);
}
}
}
- hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
+ if (existing_refs_populated)
+ hashmap_free_entries(&existing_refs, struct refname_hash_entry, ent);
return ref_map;
}
struct ref *rm;
const char *format = "full";
- git_config_get_string_const("fetch.output", &format);
+ git_config_get_string_tmp("fetch.output", &format);
if (!strcasecmp(format, "full"))
compact_format = 0;
else if (!strcasecmp(format, "compact"))
const char *what, *kind;
struct ref *rm;
char *url;
- const char *filename = dry_run ? "/dev/null" : git_path_fetch_head(the_repository);
+ const char *filename = (!write_fetch_head
+ ? "/dev/null"
+ : git_path_fetch_head(the_repository));
int want_status;
int summary_width = transport_summary_width(ref_map);
rc |= update_local_ref(ref, what, rm, ¬e,
summary_width);
free(ref);
- } else
+ } else if (write_fetch_head || dry_run) {
+ /*
+ * Display fetches written to FETCH_HEAD (or
+ * would be written to FETCH_HEAD, if --dry-run
+ * is set).
+ */
format_display(¬e, '*',
*kind ? kind : "branch", NULL,
*what ? what : "HEAD",
"FETCH_HEAD", summary_width);
+ }
if (note.len) {
if (verbosity >= 0 && !shown_url) {
fprintf(stderr, _("From %.*s\n"),
}
/* if not appending, truncate FETCH_HEAD */
- if (!append && !dry_run) {
+ if (!append && write_fetch_head) {
retcode = truncate_fetch_head();
if (retcode)
goto cleanup;
int i, result = 0;
struct strvec argv = STRVEC_INIT;
- if (!append && !dry_run) {
+ if (!append && write_fetch_head) {
int errcode = truncate_fetch_head();
if (errcode)
return errcode;
return;
}
-static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
+static int fetch_one(struct remote *remote, int argc, const char **argv,
+ int prune_tags_ok, int use_stdin_refspecs)
{
struct refspec rs = REFSPEC_INIT_FETCH;
int i;
for (i = 0; i < argc; i++) {
if (!strcmp(argv[i], "tag")) {
- char *tag;
i++;
if (i >= argc)
die(_("You need to specify a tag name."));
- tag = xstrfmt("refs/tags/%s:refs/tags/%s",
- argv[i], argv[i]);
- refspec_append(&rs, tag);
- free(tag);
+ refspec_appendf(&rs, "refs/tags/%s:refs/tags/%s",
+ argv[i], argv[i]);
} else {
refspec_append(&rs, argv[i]);
}
}
+ if (use_stdin_refspecs) {
+ struct strbuf line = STRBUF_INIT;
+ while (strbuf_getline_lf(&line, stdin) != EOF)
+ refspec_append(&rs, line.buf);
+ strbuf_release(&line);
+ }
+
if (server_options.nr)
gtransport->server_options = &server_options;
free(anon);
}
- fetch_config_from_gitmodules(&submodule_fetch_jobs_config,
- &recurse_submodules);
git_config(git_fetch_config, NULL);
argc = parse_options(argc, argv, prefix,
builtin_fetch_options, builtin_fetch_usage, 0);
+ if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
+ int *sfjc = submodule_fetch_jobs_config == -1
+ ? &submodule_fetch_jobs_config : NULL;
+ int *rs = recurse_submodules == RECURSE_SUBMODULES_DEFAULT
+ ? &recurse_submodules : NULL;
+
+ fetch_config_from_gitmodules(sfjc, rs);
+ }
if (deepen_relative) {
if (deepen_relative < 0)
if (depth || deepen_since || deepen_not.nr)
deepen = 1;
+ /* FETCH_HEAD never gets updated in --dry-run mode */
+ if (dry_run)
+ write_fetch_head = 0;
+
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
if (remote) {
if (filter_options.choice || has_promisor_remote())
fetch_one_setup_partial(remote);
- result = fetch_one(remote, argc, argv, prune_tags_ok);
+ result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs);
} else {
int max_children = max_jobs;
die(_("--filter can only be used with the remote "
"configured in extensions.partialclone"));
+ if (stdin_refspecs)
+ die(_("--stdin can only be used when fetching "
+ "from one remote"));
+
if (max_children < 0)
max_children = fetch_parallel_config;