From 2b713c272cd8f9dc70ad746e8ba01a93d8baa023 Mon Sep 17 00:00:00 2001 From: Jonathan Tan Date: Mon, 17 Aug 2020 21:01:32 -0700 Subject: fetch: allow refspecs specified through stdin In a subsequent patch, partial clones will be taught to fetch missing objects using a "git fetch" subprocess. Because the number of objects fetched may be too numerous to fit on the command line, teach "fetch" to accept refspecs passed through stdin. Signed-off-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/fetch.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'builtin/fetch.c') diff --git a/builtin/fetch.c b/builtin/fetch.c index 2eb8d6a5a5..9fca92b509 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -80,6 +80,7 @@ static struct list_objects_filter_options filter_options; 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) { @@ -205,6 +206,8 @@ static struct option builtin_fetch_options[] = { 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() }; @@ -1680,7 +1683,8 @@ static inline void fetch_one_setup_partial(struct remote *remote) 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; @@ -1737,6 +1741,13 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru } } + 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; @@ -1837,7 +1848,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) 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; @@ -1845,6 +1856,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) 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; -- cgit v1.2.3 From e5b942136ec1af98551b259997872e9849b2766c Mon Sep 17 00:00:00 2001 From: Jonathan Tan Date: Mon, 17 Aug 2020 21:01:33 -0700 Subject: fetch: avoid reading submodule config until needed In "fetch", there are two parameters submodule_fetch_jobs_config and recurse_submodules that can be set in a variety of ways: through .gitmodules, through .git/config, and through the command line. Currently "fetch" handles this by first reading .gitmodules, then reading .git/config (allowing it to overwrite existing values), then reading the command line (allowing it to overwrite existing values). Notice that we can avoid reading .gitmodules if .git/config and/or the command line already provides us with what we need. In addition, if recurse_submodules is found to be "no", we do not need the value of submodule_fetch_jobs_config. Avoiding reading .gitmodules is especially important when we use "git fetch" to perform lazy fetches in a partial clone because the .gitmodules file itself might need to be lazy fetched (and otherwise causing an infinite loop). In light of all this, avoid reading .gitmodules until necessary. When reading it, we may only need one of the two parameters it provides, so teach fetch_config_from_gitmodules() to support NULL arguments. With this patch, users (including Git itself when invoking "git fetch" to lazy-fetch) will be able to guarantee avoiding reading .gitmodules by passing --recurse-submodules=no. Signed-off-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/fetch.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'builtin/fetch.c') diff --git a/builtin/fetch.c b/builtin/fetch.c index 9fca92b509..ecd041ee04 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1782,12 +1782,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) 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) -- cgit v1.2.3 From abcb7eeb31d0267ada469646be993ad25e127d0d Mon Sep 17 00:00:00 2001 From: Jonathan Tan Date: Mon, 17 Aug 2020 21:01:34 -0700 Subject: fetch: only populate existing_refs if needed In "fetch", get_ref_map() iterates over all refs to populate "existing_refs" in order to populate peer_ref->old_oid in the returned refmap, even if the refmap has no peer_ref set - which is the case when only literal hashes (i.e. no refs by name) are fetched. Iterating over refs causes the targets of those refs to be checked for existence. Avoiding this is especially important when we use "git fetch" to perform lazy fetches in a partial clone because a target of such a ref may need to be itself lazy-fetched (and otherwise causing an infinite loop). Therefore, avoid populating "existing_refs" until necessary. With this patch, because Git lazy-fetches objects by literal hashes (to be done in a subsequent commit), it will then be able to guarantee avoiding reading targets of refs. Signed-off-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/fetch.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'builtin/fetch.c') diff --git a/builtin/fetch.c b/builtin/fetch.c index ecd041ee04..320ba9471d 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -445,6 +445,7 @@ static struct ref *get_ref_map(struct remote *remote, struct ref *orefs = NULL, **oref_tail = &orefs; struct hashmap existing_refs; + int existing_refs_populated = 0; if (rs->nr) { struct refspec *fetch_refspec; @@ -538,15 +539,18 @@ static struct ref *get_ref_map(struct remote *remote, 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); @@ -556,7 +560,8 @@ static struct ref *get_ref_map(struct remote *remote, } } } - 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; } -- cgit v1.2.3 From db3c293ecded67128b74a03f01e65c6799ff1116 Mon Sep 17 00:00:00 2001 From: Jonathan Tan Date: Wed, 2 Sep 2020 14:05:39 -0700 Subject: fetch: no FETCH_HEAD display if --no-write-fetch-head 887952b8c6 ("fetch: optionally allow disabling FETCH_HEAD update", 2020-08-18) introduced the ability to disable writing to FETCH_HEAD during fetch, but did not suppress the " -> FETCH_HEAD" message when this ability is used. This message is misleading in this case, because FETCH_HEAD is not written. Also, because "fetch" is used to lazy-fetch missing objects in a partial clone, this significantly clutters up the output in that case since the objects to be fetched are potentially numerous. Therefore, suppress this message when --no-write-fetch-head is passed (but not when --dry-run is set). Signed-off-by: Jonathan Tan Signed-off-by: Junio C Hamano --- builtin/fetch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'builtin/fetch.c') diff --git a/builtin/fetch.c b/builtin/fetch.c index 320ba9471d..c6c4689250 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -1023,11 +1023,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, 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"), -- cgit v1.2.3