From b888d61c8308027433df9c243fa551f42db1c76a Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 10 Sep 2007 23:03:25 -0400 Subject: Make fetch a builtin Thanks to Johannes Schindelin for review and fixes, and Julian Phillips for the original C translation. This changes a few small bits of behavior: branch..merge is parsed as if it were the lhs of a fetch refspec, and does not have to exactly match the actual lhs of a refspec, so long as it is a valid abbreviation for the same ref. branch..merge is no longer ignored if the remote is configured with a branches/* file. Neither behavior is useful, because there can only be one ref that gets fetched, but this is more consistant. Also, fetch prints different information to standard out. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 552 insertions(+) create mode 100644 builtin-fetch.c (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c new file mode 100644 index 0000000000..64392f317d --- /dev/null +++ b/builtin-fetch.c @@ -0,0 +1,552 @@ +/* + * "git fetch" + */ +#include "cache.h" +#include "refs.h" +#include "commit.h" +#include "builtin.h" +#include "path-list.h" +#include "remote.h" +#include "transport.h" + +static const char fetch_usage[] = "git-fetch [-a | --append] [--upload-pack ] [-f | --force] [--no-tags] [-t | --tags] [-k | --keep] [-u | --update-head-ok] [--depth ] [-v | --verbose] [ ...]"; + +static int append, force, tags, no_tags, update_head_ok, verbose, quiet; + +static int unpacklimit; + +static char *default_rla = NULL; + +static void find_merge_config(struct ref *ref_map, struct remote *remote) +{ + struct ref *rm = ref_map; + struct branch *branch = branch_get(NULL); + + for (rm = ref_map; rm; rm = rm->next) { + if (!branch_has_merge_config(branch)) { + if (remote && remote->fetch && + !strcmp(remote->fetch[0].src, rm->name)) + rm->merge = 1; + } else { + if (branch_merges(branch, rm->name)) + rm->merge = 1; + } + } +} + +static struct ref *get_ref_map(struct transport *transport, + struct refspec *refs, int ref_count, int tags, + int *autotags) +{ + int i; + struct ref *rm; + struct ref *ref_map = NULL; + struct ref **tail = &ref_map; + + struct ref *remote_refs = transport_get_remote_refs(transport); + + if (ref_count || tags) { + for (i = 0; i < ref_count; i++) { + get_fetch_map(remote_refs, &refs[i], &tail); + if (refs[i].dst && refs[i].dst[0]) + *autotags = 1; + } + /* Merge everything on the command line, but not --tags */ + for (rm = ref_map; rm; rm = rm->next) + rm->merge = 1; + if (tags) { + struct refspec refspec; + refspec.src = "refs/tags/"; + refspec.dst = "refs/tags/"; + refspec.pattern = 1; + refspec.force = 0; + get_fetch_map(remote_refs, &refspec, &tail); + } + } else { + /* Use the defaults */ + struct remote *remote = transport->remote; + if (remote->fetch_refspec_nr) { + for (i = 0; i < remote->fetch_refspec_nr; i++) { + get_fetch_map(remote_refs, &remote->fetch[i], &tail); + if (remote->fetch[i].dst && + remote->fetch[i].dst[0]) + *autotags = 1; + } + find_merge_config(ref_map, remote); + } else { + ref_map = get_remote_ref(remote_refs, "HEAD"); + + ref_map->merge = 1; + } + } + + return ref_map; +} + +static void show_new(enum object_type type, unsigned char *sha1_new) +{ + fprintf(stderr, " %s: %s\n", typename(type), + find_unique_abbrev(sha1_new, DEFAULT_ABBREV)); +} + +static int s_update_ref(const char *action, + struct ref *ref, + int check_old) +{ + char msg[1024]; + char *rla = getenv("GIT_REFLOG_ACTION"); + static struct ref_lock *lock; + + if (!rla) + rla = default_rla; + snprintf(msg, sizeof(msg), "%s: %s", rla, action); + lock = lock_any_ref_for_update(ref->name, + check_old ? ref->old_sha1 : NULL, 0); + if (!lock) + return 1; + if (write_ref_sha1(lock, ref->new_sha1, msg) < 0) + return 1; + return 0; +} + +static int update_local_ref(struct ref *ref, + const char *note, + int verbose) +{ + char oldh[41], newh[41]; + struct commit *current = NULL, *updated; + enum object_type type; + struct branch *current_branch = branch_get(NULL); + + type = sha1_object_info(ref->new_sha1, NULL); + if (type < 0) + die("object %s not found", sha1_to_hex(ref->new_sha1)); + + if (!*ref->name) { + /* Not storing */ + if (verbose) { + fprintf(stderr, "* fetched %s\n", note); + show_new(type, ref->new_sha1); + } + return 0; + } + + if (!hashcmp(ref->old_sha1, ref->new_sha1)) { + if (verbose) { + fprintf(stderr, "* %s: same as %s\n", + ref->name, note); + show_new(type, ref->new_sha1); + } + return 0; + } + + if (!strcmp(ref->name, current_branch->name) && + !(update_head_ok || is_bare_repository()) && + !is_null_sha1(ref->old_sha1)) { + /* + * If this is the head, and it's not okay to update + * the head, and the old value of the head isn't empty... + */ + fprintf(stderr, + " * %s: Cannot fetch into the current branch.\n", + ref->name); + return 1; + } + + if (!is_null_sha1(ref->old_sha1) && + !prefixcmp(ref->name, "refs/tags/")) { + fprintf(stderr, "* %s: updating with %s\n", + ref->name, note); + show_new(type, ref->new_sha1); + return s_update_ref("updating tag", ref, 0); + } + + current = lookup_commit_reference(ref->old_sha1); + updated = lookup_commit_reference(ref->new_sha1); + if (!current || !updated) { + char *msg; + if (!strncmp(ref->name, "refs/tags/", 10)) + msg = "storing tag"; + else + msg = "storing head"; + fprintf(stderr, "* %s: storing %s\n", + ref->name, note); + show_new(type, ref->new_sha1); + return s_update_ref(msg, ref, 0); + } + + strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); + strcpy(newh, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); + + if (in_merge_bases(current, &updated, 1)) { + fprintf(stderr, "* %s: fast forward to %s\n", + ref->name, note); + fprintf(stderr, " old..new: %s..%s\n", oldh, newh); + return s_update_ref("fast forward", ref, 1); + } + if (!force && !ref->force) { + fprintf(stderr, + "* %s: not updating to non-fast forward %s\n", + ref->name, note); + fprintf(stderr, + " old...new: %s...%s\n", oldh, newh); + return 1; + } + fprintf(stderr, + "* %s: forcing update to non-fast forward %s\n", + ref->name, note); + fprintf(stderr, " old...new: %s...%s\n", oldh, newh); + return s_update_ref("forced-update", ref, 1); +} + +static void store_updated_refs(const char *url, struct ref *ref_map) +{ + FILE *fp; + struct commit *commit; + int url_len, i, note_len; + char note[1024]; + const char *what, *kind; + struct ref *rm; + + fp = fopen(git_path("FETCH_HEAD"), "a"); + for (rm = ref_map; rm; rm = rm->next) { + struct ref *ref = NULL; + + if (rm->peer_ref) { + ref = xcalloc(1, sizeof(*ref) + strlen(rm->peer_ref->name) + 1); + strcpy(ref->name, rm->peer_ref->name); + hashcpy(ref->old_sha1, rm->peer_ref->old_sha1); + hashcpy(ref->new_sha1, rm->old_sha1); + ref->force = rm->force; + } + + commit = lookup_commit_reference(rm->old_sha1); + if (!commit) + rm->merge = 0; + + if (!strcmp(rm->name, "HEAD")) { + kind = ""; + what = ""; + } + else if (!prefixcmp(rm->name, "refs/heads/")) { + kind = "branch"; + what = rm->name + 11; + } + else if (!prefixcmp(rm->name, "refs/tags/")) { + kind = "tag"; + what = rm->name + 10; + } + else if (!prefixcmp(rm->name, "refs/remotes/")) { + kind = "remote branch"; + what = rm->name + 13; + } + else { + kind = ""; + 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; + + note_len = 0; + if (*what) { + if (*kind) + note_len += sprintf(note + note_len, "%s ", + kind); + note_len += sprintf(note + note_len, "'%s' of ", what); + } + note_len += sprintf(note + note_len, "%.*s", url_len, url); + fprintf(fp, "%s\t%s\t%s\n", + sha1_to_hex(commit ? commit->object.sha1 : + rm->old_sha1), + rm->merge ? "" : "not-for-merge", + note); + + if (ref) + update_local_ref(ref, note, verbose); + } + fclose(fp); +} + +static int fetch_refs(struct transport *transport, struct ref *ref_map) +{ + int ret = transport_fetch_refs(transport, ref_map); + if (!ret) + store_updated_refs(transport->url, ref_map); + return ret; +} + +static int add_existing(const char *refname, const unsigned char *sha1, + int flag, void *cbdata) +{ + struct path_list *list = (struct path_list *)cbdata; + path_list_insert(refname, list); + return 0; +} + +static struct ref *find_non_local_tags(struct transport *transport, + struct ref *fetch_map) +{ + static struct path_list existing_refs = { NULL, 0, 0, 0 }; + struct path_list new_refs = { NULL, 0, 0, 1 }; + char *ref_name; + int ref_name_len; + unsigned char *ref_sha1; + struct ref *tag_ref; + struct ref *rm = NULL; + struct ref *ref_map = NULL; + struct ref **tail = &ref_map; + struct ref *ref; + + for_each_ref(add_existing, &existing_refs); + for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) { + if (prefixcmp(ref->name, "refs/tags")) + continue; + + ref_name = xstrdup(ref->name); + ref_name_len = strlen(ref_name); + ref_sha1 = ref->old_sha1; + + if (!strcmp(ref_name + ref_name_len - 3, "^{}")) { + ref_name[ref_name_len - 3] = 0; + tag_ref = transport_get_remote_refs(transport); + while (tag_ref) { + if (!strcmp(tag_ref->name, ref_name)) { + ref_sha1 = tag_ref->old_sha1; + break; + } + tag_ref = tag_ref->next; + } + } + + if (!path_list_has_path(&existing_refs, ref_name) && + !path_list_has_path(&new_refs, ref_name) && + lookup_object(ref->old_sha1)) { + fprintf(stderr, "Auto-following %s\n", + ref_name); + + path_list_insert(ref_name, &new_refs); + + rm = alloc_ref(strlen(ref_name) + 1); + strcpy(rm->name, ref_name); + rm->peer_ref = alloc_ref(strlen(ref_name) + 1); + strcpy(rm->peer_ref->name, ref_name); + hashcpy(rm->old_sha1, ref_sha1); + + *tail = rm; + tail = &rm->next; + } + free(ref_name); + } + + return ref_map; +} + +static int do_fetch(struct transport *transport, + struct refspec *refs, int ref_count) +{ + struct ref *ref_map, *fetch_map; + struct ref *rm; + int autotags = (transport->remote->fetch_tags == 1); + if (transport->remote->fetch_tags == 2 && !no_tags) + tags = 1; + if (transport->remote->fetch_tags == -1) + no_tags = 1; + + if (!transport->ops || !transport->ops->get_refs_list || + !(transport->ops->fetch_refs || transport->ops->fetch_objs)) + die("Don't know how to fetch from %s", transport->url); + + /* if not appending, truncate FETCH_HEAD */ + if (!append) + fclose(fopen(git_path("FETCH_HEAD"), "w")); + + ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags); + + for (rm = ref_map; rm; rm = rm->next) { + if (rm->peer_ref) + read_ref(rm->peer_ref->name, rm->peer_ref->old_sha1); + + printf("%s : %s\n", rm->name, rm->peer_ref ? rm->peer_ref->name : NULL); + printf(" < %s\n", sha1_to_hex(rm->old_sha1)); + if (rm->peer_ref) + printf(" > %s\n", sha1_to_hex(rm->peer_ref->old_sha1)); + if (!rm->peer_ref || + hashcmp(rm->old_sha1, rm->peer_ref->old_sha1)) { + printf("%s needs update.\n", rm->name); + } + } + + if (fetch_refs(transport, ref_map)) { + free_refs(ref_map); + return 1; + } + + fetch_map = ref_map; + + /* if neither --no-tags nor --tags was specified, do automated tag + * following ... */ + if (!(tags || no_tags) && autotags) { + ref_map = find_non_local_tags(transport, fetch_map); + if (ref_map) { + transport_set_option(transport, TRANS_OPT_DEPTH, "0"); + fetch_refs(transport, ref_map); + } + free_refs(ref_map); + } + + free_refs(fetch_map); + + return 0; +} + +static int fetch_config(const char *var, const char *value) +{ + if (strcmp(var, "fetch.unpacklimit") == 0) { + unpacklimit = git_config_int(var, value); + return 0; + } + + if (strcmp(var, "transfer.unpacklimit") == 0) { + unpacklimit = git_config_int(var, value); + return 0; + } + + return git_default_config(var, value); +} + +int cmd_fetch(int argc, const char **argv, const char *prefix) +{ + struct remote *remote; + struct transport *transport; + int i, j, rla_offset; + static const char **refs = NULL; + int ref_nr = 0; + int cmd_len = 0; + const char *depth = NULL, *upload_pack = NULL; + int keep = 0; + + git_config(fetch_config); + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + cmd_len += strlen(arg); + + if (arg[0] != '-') + break; + if (!strcmp(arg, "--append") || !strcmp(arg, "-a")) { + append = 1; + continue; + } + if (!prefixcmp(arg, "--upload-pack=")) { + upload_pack = arg + 14; + continue; + } + if (!strcmp(arg, "--upload-pack")) { + i++; + if (i == argc) + usage(fetch_usage); + upload_pack = argv[i]; + continue; + } + if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) { + force = 1; + continue; + } + if (!strcmp(arg, "--no-tags")) { + no_tags = 1; + continue; + } + if (!strcmp(arg, "--tags") || !strcmp(arg, "-t")) { + tags = 1; + continue; + } + if (!strcmp(arg, "--keep") || !strcmp(arg, "-k")) { + keep = 1; + continue; + } + if (!strcmp(arg, "--update-head-ok") || !strcmp(arg, "-u")) { + update_head_ok = 1; + continue; + } + if (!prefixcmp(arg, "--depth=")) { + depth = arg + 8; + continue; + } + if (!strcmp(arg, "--depth")) { + i++; + if (i == argc) + usage(fetch_usage); + depth = argv[i]; + continue; + } + if (!strcmp(arg, "--quiet")) { + quiet = 1; + continue; + } + if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { + verbose++; + continue; + } + usage(fetch_usage); + } + + for (j = i; j < argc; j++) + cmd_len += strlen(argv[j]); + + default_rla = xmalloc(cmd_len + 5 + argc + 1); + sprintf(default_rla, "fetch"); + rla_offset = strlen(default_rla); + for (j = 1; j < argc; j++) { + sprintf(default_rla + rla_offset, " %s", argv[j]); + rla_offset += strlen(argv[j]); + } + + if (i == argc) + remote = remote_get(NULL); + else + remote = remote_get(argv[i++]); + + transport = transport_get(remote, remote->uri[0], 1); + if (verbose >= 2) + transport->verbose = 1; + if (quiet) + transport->verbose = 0; + if (upload_pack) + transport_set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack); + if (keep) + transport_set_option(transport, TRANS_OPT_KEEP, "yes"); + transport_set_option(transport, TRANS_OPT_DEPTH, depth); + + if (!transport->url) + die("Where do you want to fetch from today?"); + + if (i < argc) { + int j = 0; + refs = xcalloc(argc - i + 1, sizeof(const char *)); + while (i < argc) { + if (!strcmp(argv[i], "tag")) { + char *ref; + i++; + ref = xmalloc(strlen(argv[i]) * 2 + 22); + strcpy(ref, "refs/tags/"); + strcat(ref, argv[i]); + strcat(ref, ":refs/tags/"); + strcat(ref, argv[i]); + refs[j++] = ref; + } else + refs[j++] = argv[i]; + i++; + } + refs[j] = NULL; + ref_nr = j; + for (j = 0; refs[j]; j++) + printf("ref: %s\n", refs[j]); + } + + return do_fetch(transport, parse_ref_spec(ref_nr, refs), ref_nr); +} -- cgit v1.2.1 From 1aad91f5a715af92892aea7764beb829938ab111 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 14 Sep 2007 03:31:07 -0400 Subject: Correct builtin-fetch to handle + in refspecs If we are fetching to a local reference (the so called peer_ref) and the refspec that created this ref/peer_ref association had started with '+' we are supposed to allow a non-fast-forward update during fetch, even if --force was not supplied on the command line. The builtin-fetch implementation was not honoring this setting as it was copied from the wrong struct ref instance. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 64392f317d..c8c24d28a2 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -217,7 +217,7 @@ static void store_updated_refs(const char *url, struct ref *ref_map) strcpy(ref->name, rm->peer_ref->name); hashcpy(ref->old_sha1, rm->peer_ref->old_sha1); hashcpy(ref->new_sha1, rm->old_sha1); - ref->force = rm->force; + ref->force = rm->peer_ref->force; } commit = lookup_commit_reference(rm->old_sha1); -- cgit v1.2.1 From 4ad1eada9774a1f340beb4fdf78f1735534741bb Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 14 Sep 2007 03:31:09 -0400 Subject: Fix off by one bug in reflog messages written by builtin-fetch We are adding a space between each argument in the sprintf above so we must account for this as we update our position within the reflog message and append in any remaining arguments. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index c8c24d28a2..016c6e43ec 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -503,7 +503,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) rla_offset = strlen(default_rla); for (j = 1; j < argc; j++) { sprintf(default_rla + rla_offset, " %s", argv[j]); - rla_offset += strlen(argv[j]); + rla_offset += strlen(argv[j]) + 1; } if (i == argc) -- cgit v1.2.1 From 133296f00cd441b5525ccc3e82ee13cbfc62d246 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 14 Sep 2007 03:31:11 -0400 Subject: Remove unnecessary debugging from builtin-fetch The older git-fetch client did not produce all of this debugging information to stdout. Most end-users and Porcelain (e.g. StGIT, git-gui, qgit) do not want to see these low-level details on the console so they should be removed. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 016c6e43ec..33b740cd10 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -370,15 +370,6 @@ static int do_fetch(struct transport *transport, for (rm = ref_map; rm; rm = rm->next) { if (rm->peer_ref) read_ref(rm->peer_ref->name, rm->peer_ref->old_sha1); - - printf("%s : %s\n", rm->name, rm->peer_ref ? rm->peer_ref->name : NULL); - printf(" < %s\n", sha1_to_hex(rm->old_sha1)); - if (rm->peer_ref) - printf(" > %s\n", sha1_to_hex(rm->peer_ref->old_sha1)); - if (!rm->peer_ref || - hashcmp(rm->old_sha1, rm->peer_ref->old_sha1)) { - printf("%s needs update.\n", rm->name); - } } if (fetch_refs(transport, ref_map)) { -- cgit v1.2.1 From f1ae391e17be638a14c7505598b73430dbf328f1 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 14 Sep 2007 03:31:13 -0400 Subject: Remove unused unpacklimit variable from builtin-fetch Never referenced. This should actually be handled down inside of builtin-fetch-pack, not up here in the generic user frontend. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 33b740cd10..a041df9faf 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -12,9 +12,6 @@ static const char fetch_usage[] = "git-fetch [-a | --append] [--upload-pack ] [-f | --force] [--no-tags] [-t | --tags] [-k | --keep] [-u | --update-head-ok] [--depth ] [-v | --verbose] [ ...]"; static int append, force, tags, no_tags, update_head_ok, verbose, quiet; - -static int unpacklimit; - static char *default_rla = NULL; static void find_merge_config(struct ref *ref_map, struct remote *remote) @@ -395,21 +392,6 @@ static int do_fetch(struct transport *transport, return 0; } -static int fetch_config(const char *var, const char *value) -{ - if (strcmp(var, "fetch.unpacklimit") == 0) { - unpacklimit = git_config_int(var, value); - return 0; - } - - if (strcmp(var, "transfer.unpacklimit") == 0) { - unpacklimit = git_config_int(var, value); - return 0; - } - - return git_default_config(var, value); -} - int cmd_fetch(int argc, const char **argv, const char *prefix) { struct remote *remote; @@ -421,8 +403,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) const char *depth = NULL, *upload_pack = NULL; int keep = 0; - git_config(fetch_config); - for (i = 1; i < argc; i++) { const char *arg = argv[i]; cmd_len += strlen(arg); -- cgit v1.2.1 From 425b1393139d99d89c7a95906686d9b041f2ee3d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 14 Sep 2007 03:31:21 -0400 Subject: Simplify fetch transport API to just one function Commit walkers need to know the SHA-1 name of any objects they have been asked to fetch while the native pack transport only wants to know the names of the remote refs as the remote side must do the name->SHA-1 translation. Since we only have three fetch implementations and one of them (bundle) doesn't even need the name information we can reduce the code required to perform a fetch by having just one function and passing of the filtered list of refs to be fetched. Each transport can then obtain the information it needs from that ref array to construct its own internal operation state. Signed-off-by: Shawn O. Pearce Conflicts: transport.c Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index a041df9faf..f5a2718acc 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -355,7 +355,7 @@ static int do_fetch(struct transport *transport, no_tags = 1; if (!transport->ops || !transport->ops->get_refs_list || - !(transport->ops->fetch_refs || transport->ops->fetch_objs)) + !transport->ops->fetch) die("Don't know how to fetch from %s", transport->url); /* if not appending, truncate FETCH_HEAD */ -- cgit v1.2.1 From 1788c39cd0742439b9bedc28bc10bc4d105b6c0f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 14 Sep 2007 03:31:23 -0400 Subject: Remove pack.keep after ref updates in git-fetch If we are using a native packfile to perform a git-fetch invocation and the received packfile contained more than the configured limits of fetch.unpackLimit/transfer.unpackLimit then index-pack will output a single line saying "keep\t$sha1\n" to stdout. This line needs to be captured and retained so we can delete the corresponding .keep file ("$GIT_DIR/objects/pack/pack-$sha1.keep") once all refs have been safely updated. This trick has long been in use with git-fetch.sh and its lower level helper git-fetch--tool as a way to allow index-pack to save the new packfile before the refs have been updated and yet avoid a race with any concurrently running git-repack process. It was unfortunately lost when git-fetch.sh was converted to pure C and fetch--tool was no longer being invoked. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index f5a2718acc..8e433d1bf2 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -274,6 +274,7 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) int ret = transport_fetch_refs(transport, ref_map); if (!ret) store_updated_refs(transport->url, ref_map); + transport_unlock_pack(transport); return ret; } -- cgit v1.2.1 From e4022ed2c85825f238661e3e532b0bb108b5e318 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 14 Sep 2007 03:31:25 -0400 Subject: Always ensure the pack.keep file is removed by git-fetch If we are using a native transport and the transport chose to save the packfile it may have created a .keep file to protect the packfile from a concurrently running git-repack process. In such a case the git-fetch process should make sure it will unlink the .keep file even if it fails to update any refs as otherwise the newly downloaded packfile's diskspace will never be reclaimed if the objects are not actually referenced. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 8e433d1bf2..8b0fdbe905 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -13,6 +13,20 @@ static const char fetch_usage[] = "git-fetch [-a | --append] [--upload-pack Date: Sat, 15 Sep 2007 03:23:14 -0400 Subject: Remove unnecessary 'fetch' argument from transport_get API We don't actually need to know at the time of transport_get if the caller wants to fetch, push, or do both on the returned object. It is easier to just delay the initialization of the HTTP walker until we know we will need it by providing a CURL specific fetch function in the curl_transport that makes sure the walker instance is initialized before use. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 8b0fdbe905..300d5635b0 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -496,7 +496,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) else remote = remote_get(argv[i++]); - transport = transport_get(remote, remote->uri[0], 1); + transport = transport_get(remote, remote->uri[0]); if (verbose >= 2) transport->verbose = 1; if (quiet) -- cgit v1.2.1 From b3abdd9d216c578383b66bb10b95edb3380640e7 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 16 Sep 2007 02:31:26 -0400 Subject: Allow builtin-fetch to work on a detached HEAD If we are running fetch in a repository that has a detached HEAD then there is no current_branch available. In such a case any ref that the fetch might update by definition cannot also be the current branch so we should always bypass the "don't update HEAD" test. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 300d5635b0..d9272edae9 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -151,7 +151,8 @@ static int update_local_ref(struct ref *ref, return 0; } - if (!strcmp(ref->name, current_branch->name) && + if (current_branch && + !strcmp(ref->name, current_branch->name) && !(update_head_ok || is_bare_repository()) && !is_null_sha1(ref->old_sha1)) { /* -- cgit v1.2.1 From f38395905b3d49bd68e0c01ca2310bf3387e1063 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 16 Sep 2007 02:32:17 -0400 Subject: Remove more debugging from builtin-fetch Older git-fetch.sh doesn't print "ref: X" when invoked as `git fetch $url X" so we shouldn't do that now in the new builtin version. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index d9272edae9..20926e0543 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -530,8 +530,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) } refs[j] = NULL; ref_nr = j; - for (j = 0; refs[j]; j++) - printf("ref: %s\n", refs[j]); } signal(SIGINT, unlock_pack_on_signal); -- cgit v1.2.1 From 85682c1903a4ae776b0bf2d30d9ecd1e19689131 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 18 Sep 2007 04:54:53 -0400 Subject: Correct handling of branch.$name.merge in builtin-fetch My prior bug fix for git-push titled "Don't configure remote "." to fetch everything to itself" actually broke t5520 as we were unable to evaluate a branch configuration of: [branch "copy"] remote = . merge = refs/heads/master as remote "." did not have a "remote...fetch" configuration entry to offer up refs/heads/master as a possible candidate available to be fetched and merged. In shell script git-fetch and prior to the above mentioned commit this was hardcoded for a url of "." to be the set of local branches. Chasing down this bug led me to the conclusion that our prior behavior with regards to branch.$name.merge was incorrect. In the shell script based git-fetch implementation we only fetched and merged a branch if it appeared both in branch.$name.merge *and* in remote.$r.fetch, where $r = branch.$name.remote. In other words in the following config file: [remote "origin"] url = git://git.kernel.org/pub/scm/git/git.git fetch = refs/heads/master:refs/remotes/origin/master [branch "master"] remote = origin merge = refs/heads/master [branch "pu"] remote = origin merge = refs/heads/pu Attempting to run `git pull` while on branch "pu" would always give the user "Already up-to-date" as git-fetch did not fetch pu and thus did not mark it for merge in .git/FETCH_HEAD. The configured merge would always be ignored and the user would be left scratching her confused head wondering why merge did not work on "pu" but worked fine on "master". If we are using the "default fetch" specification for the current branch and the current branch has a branch.$name.merge configured we now union it with the list of refs in remote.$r.fetch. This way the above configuration does what the user expects it to do, which is to fetch only "master" by default but when on "pu" to fetch both "master" and "pu". This uncovered some breakage in the test suite where old-style Cogito branches (.git/branches/$r) did not fetch the branches listed in .git/config for merging and thus did not actually merge them if the user tried to use `git pull` on that branch. Junio and I discussed it on list and felt that the union approach here makes more sense to DWIM for the end-user than silently ignoring their configured request so the test vectors for t5515 have been updated to include for-merge lines in .git/FETCH_HEAD where they have been configured for-merge in .git/config. Since we are now performing a union of the fetch specification and the merge specification and we cannot allow a branch to be listed twice (otherwise it comes out twice in .git/FETCH_HEAD) we need to perform a double loop here over all of the branch.$name.merge lines and try to set their merge flag if we have already schedule that branch for fetching by remote.$r.fetch. If no match is found then we must add new specifications to fetch the branch but not store it as no local tracking branch has been designated. Signed-off-by: Shawn O. Pearce --- builtin-fetch.c | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 20926e0543..670af0b53f 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -28,20 +28,37 @@ static void unlock_pack_on_signal(int signo) raise(signo); } -static void find_merge_config(struct ref *ref_map, struct remote *remote) +static void add_merge_config(struct ref **head, + struct ref *remote_refs, + struct branch *branch, + struct ref ***tail) { - struct ref *rm = ref_map; - struct branch *branch = branch_get(NULL); + int i; - for (rm = ref_map; rm; rm = rm->next) { - if (!branch_has_merge_config(branch)) { - if (remote && remote->fetch && - !strcmp(remote->fetch[0].src, rm->name)) - rm->merge = 1; - } else { - if (branch_merges(branch, rm->name)) + for (i = 0; i < branch->merge_nr; i++) { + struct ref *rm, **old_tail = *tail; + struct refspec refspec; + + for (rm = *head; rm; rm = rm->next) { + if (branch_merge_matches(branch, i, rm->name)) { rm->merge = 1; + break; + } } + if (rm) + continue; + + /* Not fetched to a tracking branch? We need to fetch + * it anyway to allow this branch's "branch.$name.merge" + * to be honored by git-pull. + */ + refspec.src = branch->merge[i]->src; + refspec.dst = NULL; + refspec.pattern = 0; + refspec.force = 0; + get_fetch_map(remote_refs, &refspec, tail); + for (rm = *old_tail; rm; rm = rm->next) + rm->merge = 1; } } @@ -76,17 +93,22 @@ static struct ref *get_ref_map(struct transport *transport, } else { /* Use the defaults */ struct remote *remote = transport->remote; - if (remote->fetch_refspec_nr) { + struct branch *branch = branch_get(NULL); + int has_merge = branch_has_merge_config(branch); + if (remote && (remote->fetch_refspec_nr || has_merge)) { for (i = 0; i < remote->fetch_refspec_nr; i++) { get_fetch_map(remote_refs, &remote->fetch[i], &tail); if (remote->fetch[i].dst && remote->fetch[i].dst[0]) *autotags = 1; + if (!i && !has_merge && ref_map && + !strcmp(remote->fetch[0].src, ref_map->name)) + ref_map->merge = 1; } - find_merge_config(ref_map, remote); + if (has_merge) + add_merge_config(&ref_map, remote_refs, branch, &tail); } else { ref_map = get_remote_ref(remote_refs, "HEAD"); - ref_map->merge = 1; } } -- cgit v1.2.1 From ab865e6eec1f40938604b1c28a32525c1fdc7227 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 18 Sep 2007 04:54:57 -0400 Subject: Avoid printing unnecessary warnings during fetch and push If a transport doesn't support an option we already are telling the higher level application (fetch or push) that the option is not valid by sending back a >0 return value from transport_set_option so there's not a strong motivation to have the function perform the output itself. Instead we should let the higher level application do the output if it is necessary. This avoids always telling the user that depth isn't supported on HTTP urls even when they did not pass a --depth option to git-fetch. If the user passes an option and the option value is invalid we now properly die in git-fetch instead of just spitting out a message and running anyway. This mimics prior behavior better where incorrect/malformed options are not accepted by the process. Signed-off-by: Shawn O. Pearce --- builtin-fetch.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 670af0b53f..b9722e5fbd 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -430,6 +430,17 @@ static int do_fetch(struct transport *transport, return 0; } +static void set_option(const char *name, const char *value) +{ + int r = transport_set_option(transport, name, value); + if (r < 0) + die("Option \"%s\" value \"%s\" is not valid for %s\n", + name, value, transport->url); + if (r > 0) + warning("Option \"%s\" is ignored for %s\n", + name, transport->url); +} + int cmd_fetch(int argc, const char **argv, const char *prefix) { struct remote *remote; @@ -525,10 +536,11 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (quiet) transport->verbose = 0; if (upload_pack) - transport_set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack); + set_option(TRANS_OPT_UPLOADPACK, upload_pack); if (keep) - transport_set_option(transport, TRANS_OPT_KEEP, "yes"); - transport_set_option(transport, TRANS_OPT_DEPTH, depth); + set_option(TRANS_OPT_KEEP, "yes"); + if (depth) + set_option(TRANS_OPT_DEPTH, depth); if (!transport->url) die("Where do you want to fetch from today?"); -- cgit v1.2.1 From 28b91f8ad9e4791b5c35ca6bffbb78725b4e5bbf Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 19 Sep 2007 00:49:27 -0400 Subject: Rename remote.uri to remote.url within remote handling internals Anyplace we talk about the address of a remote repository we always refer to it as a URL, especially in the configuration file and .git/remotes where we call it "remote.$n.url" or start the first line with "URL:". Calling this value a uri within the internal C code just doesn't jive well with our commonly accepted terms. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index b9722e5fbd..997a8ff954 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -530,7 +530,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) else remote = remote_get(argv[i++]); - transport = transport_get(remote, remote->uri[0]); + transport = transport_get(remote, remote->url[0]); if (verbose >= 2) transport->verbose = 1; if (quiet) -- cgit v1.2.1 From 824d5776c3f275c644c71b8c7e254bd2d7b08071 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 19 Sep 2007 00:49:31 -0400 Subject: Refactor struct transport_ops inlined into struct transport Aside from reducing the code by 20 lines this refactoring removes a level of indirection when trying to access the operations of a given transport "instance", making the code clearer and easier to follow. It also has the nice effect of giving us the benefits of C99 style struct initialization (namely ".fetch = X") without requiring that level of language support from our compiler. We don't need to worry about new operation methods being added as they will now be NULL'd out automatically by the xcalloc() we use to create the new struct transport we supply to the caller. This pattern already exists in struct walker, so we already have a precedent for it in Git. We also don't really need to worry about any sort of performance decreases that may occur as a result of filling out 4-8 op pointers when we make a "struct transport". The extra few CPU cycles this requires over filling in the "struct transport_ops" is killed by the time it will take Git to actually *use* one of those functions, as most transport operations are going over the wire or will be copying object data locally between two directories. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 997a8ff954..2f639ccef2 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -392,8 +392,7 @@ static int do_fetch(struct transport *transport, if (transport->remote->fetch_tags == -1) no_tags = 1; - if (!transport->ops || !transport->ops->get_refs_list || - !transport->ops->fetch) + if (!transport->get_refs_list || !transport->fetch) die("Don't know how to fetch from %s", transport->url); /* if not appending, truncate FETCH_HEAD */ -- cgit v1.2.1 From cfb8f898a883e2fb2fd5ecec0fe83662b64f1373 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Fri, 28 Sep 2007 19:34:17 -0400 Subject: Allow abbreviations in the first refspec to be merged The config item for a refspec side and the ref name that it matches aren't necessarily character-for-character identical. We actually want to merge a ref by default if: there is no per-branch config, it is the found result of looking for the match for the first refspec, and the first refspec is not a pattern. Beyond that, anything that get_fetch_map() thinks matches is fine. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 2f639ccef2..ac68ff592e 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -102,7 +102,7 @@ static struct ref *get_ref_map(struct transport *transport, remote->fetch[i].dst[0]) *autotags = 1; if (!i && !has_merge && ref_map && - !strcmp(remote->fetch[0].src, ref_map->name)) + !remote->fetch[0].pattern) ref_map->merge = 1; } if (has_merge) -- cgit v1.2.1 From 2b5a06edca8f7237aad6464b349b79772024d2a2 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Tue, 2 Oct 2007 22:49:15 -0400 Subject: Restore default verbosity for http fetches. This adds a verbosity level below 0 for suppressing default messages with --quiet, and makes the default for http be verbose instead of quiet. This matches the behavior of the shell script version of git-fetch. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index ac68ff592e..cf7498b15f 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -533,7 +533,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (verbose >= 2) transport->verbose = 1; if (quiet) - transport->verbose = 0; + transport->verbose = -1; if (upload_pack) set_option(TRANS_OPT_UPLOADPACK, upload_pack); if (keep) -- cgit v1.2.1 From 2467a4fa03ff849fcf2f6a93b89057aebd49c62b Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 8 Oct 2007 00:25:07 -0400 Subject: Remove duplicate ref matches in fetch If multiple refspecs matched the same ref, the update would be processed multiple times. Now having the same destination for the same source has no additional effect, and having the same destination for different sources is an error. Signed-off-by: Daniel Barkalow Signed-off-by: Lars Hjemli Signed-off-by: Shawn O. Pearce --- builtin-fetch.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index cf7498b15f..caaca63644 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -112,6 +112,7 @@ static struct ref *get_ref_map(struct transport *transport, ref_map->merge = 1; } } + ref_remove_duplicates(ref_map); return ref_map; } -- cgit v1.2.1 From da0204df587ae76cd291bc7e495fc60d873c2f20 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 11 Oct 2007 01:47:55 +0100 Subject: fetch: if not fetching from default remote, ignore default merge When doing "git fetch " on a remote that does not have the branch referenced in branch..merge, git fetch failed. It failed because it tried to add the "merge" ref to the refs to be fetched. Fix that. And add a test case. Incidentally, this unconvered a bug in our own test suite, where "git pull " was expected to merge the ref given in the defaults, even if not pulling from the default remote. Signed-off-by: Johannes Schindelin Signed-off-by: Lars Hjemli Signed-off-by: Shawn O. Pearce --- 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 caaca63644..3442f3d09e 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -105,7 +105,13 @@ static struct ref *get_ref_map(struct transport *transport, !remote->fetch[0].pattern) ref_map->merge = 1; } - if (has_merge) + /* + * if the remote we're fetching from is the same + * as given in branch..remote, we add the + * ref given in branch..merge, too. + */ + if (has_merge && !strcmp(branch->remote_name, + remote->name)) add_merge_config(&ref_map, remote_refs, branch, &tail); } else { ref_map = get_remote_ref(remote_refs, "HEAD"); -- cgit v1.2.1 From cfa5b2b7faa1a620ec6599a63fa5b9b45bd62b57 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 19 Oct 2007 00:54:59 -0400 Subject: Avoid scary errors about tagged trees/blobs during git-fetch This is the same bug as 42a32174b600f139b489341b1281fb1bfa14c252. The warning "Object $X is a tree, not a commit" is bogus and is not relevant here. If its not a commit we just need to make sure we don't mark it for merge as we fill out FETCH_HEAD. Signed-off-by: Shawn O. Pearce --- builtin-fetch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 3442f3d09e..b9d2b0c27e 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -202,8 +202,8 @@ static int update_local_ref(struct ref *ref, return s_update_ref("updating tag", ref, 0); } - current = lookup_commit_reference(ref->old_sha1); - updated = lookup_commit_reference(ref->new_sha1); + current = lookup_commit_reference_gently(ref->old_sha1, 1); + updated = lookup_commit_reference_gently(ref->new_sha1, 1); if (!current || !updated) { char *msg; if (!strncmp(ref->name, "refs/tags/", 10)) @@ -261,7 +261,7 @@ static void store_updated_refs(const char *url, struct ref *ref_map) ref->force = rm->peer_ref->force; } - commit = lookup_commit_reference(rm->old_sha1); + commit = lookup_commit_reference_gently(rm->old_sha1, 1); if (!commit) rm->merge = 0; -- cgit v1.2.1 From 9ad7c5ae8ae4625bfe32d910b0b480cfea9819e0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 26 Oct 2007 23:09:48 -0700 Subject: git-fetch: do not fail when remote branch disappears When the branch named with branch.$name.merge is not covered by the fetch configuration for the remote repository named with branch.$name.remote, we automatically add that branch to the set of branches to be fetched. However, if the remote repository does not have that branch (e.g. it used to exist, but got removed), this is not a reason to fail the git-fetch itself. The situation however will be noticed if git-fetch was called by git-pull, as the resulting FETCH_HEAD would not have any entry that is marked for merging. Acked-By: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index b9d2b0c27e..003ed76d16 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -48,15 +48,21 @@ static void add_merge_config(struct ref **head, if (rm) continue; - /* Not fetched to a tracking branch? We need to fetch + /* + * Not fetched to a tracking branch? We need to fetch * it anyway to allow this branch's "branch.$name.merge" - * to be honored by git-pull. + * to be honored by git-pull, but we do not have to + * fail if branch.$name.merge is misconfigured to point + * at a nonexisting branch. If we were indeed called by + * git-pull, it will notice the misconfiguration because + * there is no entry in the resulting FETCH_HEAD marked + * for merging. */ refspec.src = branch->merge[i]->src; refspec.dst = NULL; refspec.pattern = 0; refspec.force = 0; - get_fetch_map(remote_refs, &refspec, tail); + get_fetch_map(remote_refs, &refspec, tail, 1); for (rm = *old_tail; rm; rm = rm->next) rm->merge = 1; } @@ -75,7 +81,7 @@ static struct ref *get_ref_map(struct transport *transport, if (ref_count || tags) { for (i = 0; i < ref_count; i++) { - get_fetch_map(remote_refs, &refs[i], &tail); + get_fetch_map(remote_refs, &refs[i], &tail, 0); if (refs[i].dst && refs[i].dst[0]) *autotags = 1; } @@ -88,7 +94,7 @@ static struct ref *get_ref_map(struct transport *transport, refspec.dst = "refs/tags/"; refspec.pattern = 1; refspec.force = 0; - get_fetch_map(remote_refs, &refspec, &tail); + get_fetch_map(remote_refs, &refspec, &tail, 0); } } else { /* Use the defaults */ @@ -97,7 +103,7 @@ static struct ref *get_ref_map(struct transport *transport, int has_merge = branch_has_merge_config(branch); if (remote && (remote->fetch_refspec_nr || has_merge)) { for (i = 0; i < remote->fetch_refspec_nr; i++) { - get_fetch_map(remote_refs, &remote->fetch[i], &tail); + get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0); if (remote->fetch[i].dst && remote->fetch[i].dst[0]) *autotags = 1; @@ -110,11 +116,13 @@ static struct ref *get_ref_map(struct transport *transport, * as given in branch..remote, we add the * ref given in branch..merge, too. */ - if (has_merge && !strcmp(branch->remote_name, - remote->name)) + if (has_merge && + !strcmp(branch->remote_name, remote->name)) add_merge_config(&ref_map, remote_refs, branch, &tail); } else { ref_map = get_remote_ref(remote_refs, "HEAD"); + if (!ref_map) + die("Couldn't find remote ref HEAD"); ref_map->merge = 1; } } -- cgit v1.2.1 From 165f390250874b32ed8158150fe49d574297c9f9 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 3 Nov 2007 01:32:48 -0400 Subject: git-fetch: more terse fetch output This makes the fetch output much more terse and prettier on a 80 column display, based on a consensus reached on the mailing list. Here's an example output: Receiving objects: 100% (5439/5439), 1.60 MiB | 636 KiB/s, done. Resolving deltas: 100% (4604/4604), done. From git://git.kernel.org/pub/scm/git/git ! [rejected] html -> origin/html (non fast forward) 136e631..f45e867 maint -> origin/maint (fast forward) 9850e2e..44dd7e0 man -> origin/man (fast forward) 3e4bb08..e3d6d56 master -> origin/master (fast forward) fa3665c..536f64a next -> origin/next (fast forward) + 4f6d9d6...768326f pu -> origin/pu (forced update) * [new branch] todo -> origin/todo Some portions of this patch have been extracted from earlier proposals by Jeff King and Shawn Pearce. Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- builtin-fetch.c | 114 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 60 insertions(+), 54 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 003ed76d16..960b1dae89 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -131,12 +131,6 @@ static struct ref *get_ref_map(struct transport *transport, return ref_map; } -static void show_new(enum object_type type, unsigned char *sha1_new) -{ - fprintf(stderr, " %s: %s\n", typename(type), - find_unique_abbrev(sha1_new, DEFAULT_ABBREV)); -} - static int s_update_ref(const char *action, struct ref *ref, int check_old) @@ -157,34 +151,38 @@ static int s_update_ref(const char *action, return 0; } +#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) + static int update_local_ref(struct ref *ref, - const char *note, - int verbose) + const char *remote, + int verbose, + char *display) { - char oldh[41], newh[41]; struct commit *current = NULL, *updated; enum object_type type; struct branch *current_branch = branch_get(NULL); + const char *pretty_ref = ref->name + ( + !prefixcmp(ref->name, "refs/heads/") ? 11 : + !prefixcmp(ref->name, "refs/tags/") ? 10 : + !prefixcmp(ref->name, "refs/remotes/") ? 13 : + 0); + *display = 0; type = sha1_object_info(ref->new_sha1, NULL); if (type < 0) die("object %s not found", sha1_to_hex(ref->new_sha1)); if (!*ref->name) { /* Not storing */ - if (verbose) { - fprintf(stderr, "* fetched %s\n", note); - show_new(type, ref->new_sha1); - } + if (verbose) + sprintf(display, "* branch %s -> FETCH_HEAD", remote); return 0; } if (!hashcmp(ref->old_sha1, ref->new_sha1)) { - if (verbose) { - fprintf(stderr, "* %s: same as %s\n", - ref->name, note); - show_new(type, ref->new_sha1); - } + if (verbose) + sprintf(display, "= %-*s %s -> %s", SUMMARY_WIDTH, + "[up to date]", remote, pretty_ref); return 0; } @@ -196,63 +194,65 @@ 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... */ - fprintf(stderr, - " * %s: Cannot fetch into the current branch.\n", - ref->name); + sprintf(display, "! %-*s %s -> %s (can't fetch in current branch)", + SUMMARY_WIDTH, "[rejected]", remote, pretty_ref); return 1; } if (!is_null_sha1(ref->old_sha1) && !prefixcmp(ref->name, "refs/tags/")) { - fprintf(stderr, "* %s: updating with %s\n", - ref->name, note); - show_new(type, ref->new_sha1); + sprintf(display, "- %-*s %s -> %s", + SUMMARY_WIDTH, "[tag update]", remote, pretty_ref); return s_update_ref("updating tag", ref, 0); } current = lookup_commit_reference_gently(ref->old_sha1, 1); updated = lookup_commit_reference_gently(ref->new_sha1, 1); if (!current || !updated) { - char *msg; - if (!strncmp(ref->name, "refs/tags/", 10)) + const char *msg; + const char *what; + if (!strncmp(ref->name, "refs/tags/", 10)) { msg = "storing tag"; - else + what = "[new tag]"; + } + else { msg = "storing head"; - fprintf(stderr, "* %s: storing %s\n", - ref->name, note); - show_new(type, ref->new_sha1); + what = "[new branch]"; + } + + sprintf(display, "* %-*s %s -> %s", + SUMMARY_WIDTH, what, remote, pretty_ref); return s_update_ref(msg, ref, 0); } - strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); - strcpy(newh, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); - if (in_merge_bases(current, &updated, 1)) { - fprintf(stderr, "* %s: fast forward to %s\n", - ref->name, note); - fprintf(stderr, " old..new: %s..%s\n", oldh, newh); + char quickref[83]; + strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); + strcat(quickref, ".."); + strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); + sprintf(display, " %-*s %s -> %s (fast forward)", + SUMMARY_WIDTH, quickref, remote, pretty_ref); return s_update_ref("fast forward", ref, 1); - } - if (!force && !ref->force) { - fprintf(stderr, - "* %s: not updating to non-fast forward %s\n", - ref->name, note); - fprintf(stderr, - " old...new: %s...%s\n", oldh, newh); + } else if (force || ref->force) { + char quickref[84]; + strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); + strcat(quickref, "..."); + strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); + sprintf(display, "+ %-*s %s -> %s (forced update)", + SUMMARY_WIDTH, quickref, remote, pretty_ref); + return s_update_ref("forced-update", ref, 1); + } else { + sprintf(display, "! %-*s %s -> %s (non fast forward)", + SUMMARY_WIDTH, "[rejected]", remote, pretty_ref); return 1; } - fprintf(stderr, - "* %s: forcing update to non-fast forward %s\n", - ref->name, note); - fprintf(stderr, " old...new: %s...%s\n", oldh, newh); - return s_update_ref("forced-update", ref, 1); } static void store_updated_refs(const char *url, struct ref *ref_map) { FILE *fp; struct commit *commit; - int url_len, i, note_len; + int url_len, i, note_len, shown_url = 0; char note[1024]; const char *what, *kind; struct ref *rm; @@ -315,8 +315,17 @@ static void store_updated_refs(const char *url, struct ref *ref_map) rm->merge ? "" : "not-for-merge", note); - if (ref) - update_local_ref(ref, note, verbose); + if (ref) { + update_local_ref(ref, what, verbose, note); + if (*note) { + if (!shown_url) { + fprintf(stderr, "From %.*s\n", + url_len, url); + shown_url = 1; + } + fprintf(stderr, " %s\n", note); + } + } } fclose(fp); } @@ -376,9 +385,6 @@ static struct ref *find_non_local_tags(struct transport *transport, if (!path_list_has_path(&existing_refs, ref_name) && !path_list_has_path(&new_refs, ref_name) && lookup_object(ref->old_sha1)) { - fprintf(stderr, "Auto-following %s\n", - ref_name); - path_list_insert(ref_name, &new_refs); rm = alloc_ref(strlen(ref_name) + 1); -- cgit v1.2.1 From 4577370e9bfeca8652880b99b8499f76d18865ba Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 29 Oct 2007 21:05:40 -0400 Subject: Miscellaneous const changes and utilities The list of remote refs in struct transport should be const, because builtin-fetch will get confused if it changes. The url in git_connect should be const (and work on a copy) instead of requiring the caller to copy it. match_refs doesn't modify the refspecs it gets. get_fetch_map and get_remote_ref don't change the list they get. Allow transport get_refs_list methods to modify the struct transport. Add a function to copy a list of refs, when a function needs a mutable copy of a const list. Add a function to check the type of a ref, as per the code in connect.c Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 003ed76d16..fa0af170dd 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -29,7 +29,7 @@ static void unlock_pack_on_signal(int signo) } static void add_merge_config(struct ref **head, - struct ref *remote_refs, + const struct ref *remote_refs, struct branch *branch, struct ref ***tail) { @@ -77,7 +77,7 @@ static struct ref *get_ref_map(struct transport *transport, struct ref *ref_map = NULL; struct ref **tail = &ref_map; - struct ref *remote_refs = transport_get_remote_refs(transport); + const struct ref *remote_refs = transport_get_remote_refs(transport); if (ref_count || tags) { for (i = 0; i < ref_count; i++) { @@ -345,12 +345,12 @@ static struct ref *find_non_local_tags(struct transport *transport, struct path_list new_refs = { NULL, 0, 0, 1 }; char *ref_name; int ref_name_len; - unsigned char *ref_sha1; - struct ref *tag_ref; + const unsigned char *ref_sha1; + const struct ref *tag_ref; struct ref *rm = NULL; struct ref *ref_map = NULL; struct ref **tail = &ref_map; - struct ref *ref; + const struct ref *ref; for_each_ref(add_existing, &existing_refs); for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) { -- cgit v1.2.1 From 4b7bbdd14c6b926fbb0dbd203ce02e150b308694 Mon Sep 17 00:00:00 2001 From: Steven Grimm Date: Sat, 3 Nov 2007 19:26:54 -0700 Subject: builtin-fetch: Add "-q" as a synonym for "--quiet" "-q" is the very first option described in the git-fetch manpage, and it isn't supported. Signed-off-by: Steven Grimm Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 003ed76d16..8e790552cd 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -517,7 +517,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) depth = argv[i]; continue; } - if (!strcmp(arg, "--quiet")) { + if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) { quiet = 1; continue; } -- cgit v1.2.1 From 9ef4272bea94b022aa84372c06e211bccd5f8a54 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sun, 4 Nov 2007 15:05:45 -0800 Subject: git-fetch: be even quieter. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- builtin-fetch.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 5f5b59bfdb..e65690f25c 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -152,6 +152,7 @@ static int s_update_ref(const char *action, } #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) +#define REFCOL_WIDTH 10 static int update_local_ref(struct ref *ref, const char *remote, @@ -181,8 +182,9 @@ static int update_local_ref(struct ref *ref, if (!hashcmp(ref->old_sha1, ref->new_sha1)) { if (verbose) - sprintf(display, "= %-*s %s -> %s", SUMMARY_WIDTH, - "[up to date]", remote, pretty_ref); + sprintf(display, "= %-*s %-*s -> %s", SUMMARY_WIDTH, + "[up to date]", REFCOL_WIDTH, remote, + pretty_ref); return 0; } @@ -194,15 +196,17 @@ 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... */ - sprintf(display, "! %-*s %s -> %s (can't fetch in current branch)", - SUMMARY_WIDTH, "[rejected]", remote, pretty_ref); + sprintf(display, "! %-*s %-*s -> %s (can't fetch in current branch)", + SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, + pretty_ref); return 1; } if (!is_null_sha1(ref->old_sha1) && !prefixcmp(ref->name, "refs/tags/")) { - sprintf(display, "- %-*s %s -> %s", - SUMMARY_WIDTH, "[tag update]", remote, pretty_ref); + sprintf(display, "- %-*s %-*s -> %s", + SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote, + pretty_ref); return s_update_ref("updating tag", ref, 0); } @@ -220,8 +224,8 @@ static int update_local_ref(struct ref *ref, what = "[new branch]"; } - sprintf(display, "* %-*s %s -> %s", - SUMMARY_WIDTH, what, remote, pretty_ref); + sprintf(display, "* %-*s %-*s -> %s", SUMMARY_WIDTH, what, + REFCOL_WIDTH, remote, pretty_ref); return s_update_ref(msg, ref, 0); } @@ -230,20 +234,21 @@ static int update_local_ref(struct ref *ref, strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, ".."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); - sprintf(display, " %-*s %s -> %s (fast forward)", - SUMMARY_WIDTH, quickref, remote, pretty_ref); + sprintf(display, " %-*s %-*s -> %s", SUMMARY_WIDTH, quickref, + REFCOL_WIDTH, remote, pretty_ref); return s_update_ref("fast forward", ref, 1); } else if (force || ref->force) { char quickref[84]; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, "..."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); - sprintf(display, "+ %-*s %s -> %s (forced update)", - SUMMARY_WIDTH, quickref, remote, pretty_ref); + sprintf(display, "+ %-*s %-*s -> %s (forced update)", + SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref); return s_update_ref("forced-update", ref, 1); } else { - sprintf(display, "! %-*s %s -> %s (non fast forward)", - SUMMARY_WIDTH, "[rejected]", remote, pretty_ref); + sprintf(display, "! %-*s %-*s -> %s (non fast forward)", + SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, + pretty_ref); return 1; } } -- cgit v1.2.1 From a3b0079c6a2e6336b061465623b8f2db308a6978 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 11 Nov 2007 02:29:30 -0500 Subject: git-fetch: Always fetch tags if the object they reference exists Previously git-fetch.sh used `git cat-file -t` to determine if an object referenced by a tag exists, and if so fetch that tag locally. This was subtly broken during the port to C based builtin-fetch as lookup_object() only works to locate an object if it was previously accessed by the transport. Not all transports will access all objects in this way, so tags were not always being fetched. The rsync transport never loads objects into the internal object table so automated tag following didn't work if rsync was used. Automated tag following also didn't work on the native transport if the new tag was behind the common point(s) negotiated between the two ends of the connection as the tag's referrant would not be loaded into the internal object table. Further the automated tag following was broken with the HTTP commit walker if the new tag's referrant was behind an existing ref, as the walker would stop before loading the tag's referrant into the object table. Switching to has_sha1_file() restores the original behavior from the shell script by checking if the object exists in the ODB, without relying on the state left behind by a transport. Signed-off-by: Shawn O. Pearce --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 5f5b59bfdb..1cb30c52c1 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -384,7 +384,7 @@ static struct ref *find_non_local_tags(struct transport *transport, if (!path_list_has_path(&existing_refs, ref_name) && !path_list_has_path(&new_refs, ref_name) && - lookup_object(ref->old_sha1)) { + has_sha1_file(ref->old_sha1)) { path_list_insert(ref_name, &new_refs); rm = alloc_ref(strlen(ref_name) + 1); -- cgit v1.2.1 From 4191c35671f6392173221bea3994f8b305f4f3a8 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 11 Nov 2007 02:29:47 -0500 Subject: git-fetch: avoid local fetching from alternate (again) Back in e3c6f240fd9c5bdeb33f2d47adc859f37935e2df Junio taught git-fetch to avoid copying objects when we are fetching from a repository that is already registered as an alternate object database. In such a case there is no reason to copy any objects as we can already obtain them through the alternate. However we need to ensure the objects are all reachable, so we run `git rev-list --objects $theirs --not --all` to verify this. If any object is missing or unreadable then we need to fetch/copy the objects from the remote. When a missing object is detected the git-rev-list process will exit with a non-zero exit status, making this condition quite easy to detect. Although git-fetch is currently a builtin (and so is rev-list) we cannot invoke the traverse_objects() API at this point in the transport code. The object walker within traverse_objects() calls die() as soon as it finds an object it cannot read. If that happens we want to resume the fetch process by calling do_fetch_pack(). To get around this we spawn git-rev-list into a background process to prevent a die() from killing the foreground fetch process, thus allowing the fetch process to resume into do_fetch_pack() if copying is necessary. We aren't interested in the output of rev-list (a list of SHA-1 object names that are reachable) or its errors (a "spurious" error about an object not being found as we need to copy it) so we redirect both stdout and stderr to /dev/null. We run this git-rev-list based check before any fetch as we may already have the necessary objects local from a prior fetch. If we don't then its very likely the first $theirs object listed on the command line won't exist locally and git-rev-list will die very quickly, allowing us to start the network transfer. This test even on remote URLs may save bandwidth if someone runs `git pull origin`, sees a merge conflict, resets out, then redoes the same pull just a short time later. If the remote hasn't changed between the two pulls and the local repository hasn't had git-gc run in it then there is probably no need to perform network transfer as all of the objects are local. Documentation for the new quickfetch function was suggested and written by Junio, based on his original comment in git-fetch.sh. Signed-off-by: Shawn O. Pearce --- builtin-fetch.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 1cb30c52c1..c1930aaa0e 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -8,10 +8,12 @@ #include "path-list.h" #include "remote.h" #include "transport.h" +#include "run-command.h" static const char fetch_usage[] = "git-fetch [-a | --append] [--upload-pack ] [-f | --force] [--no-tags] [-t | --tags] [-k | --keep] [-u | --update-head-ok] [--depth ] [-v | --verbose] [ ...]"; static int append, force, tags, no_tags, update_head_ok, verbose, quiet; +static const char *depth; static char *default_rla = NULL; static struct transport *transport; @@ -330,9 +332,72 @@ static void store_updated_refs(const char *url, struct ref *ref_map) fclose(fp); } +/* + * We would want to bypass the object transfer altogether if + * everything we are going to fetch already exists and connected + * locally. + * + * The refs we are going to fetch are in to_fetch (nr_heads in + * total). If running + * + * $ git-rev-list --objects to_fetch[0] to_fetch[1] ... --not --all + * + * 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) +{ + struct child_process revlist; + struct ref *ref; + char **argv; + int i, err; + + /* + * If we are deepening a shallow clone we already have these + * objects reachable. Running rev-list here will return with + * a good (0) exit status and we'll bypass the fetch that we + * really need to perform. Claiming failure now will ensure + * we perform the network exchange to deepen our history. + */ + if (depth) + return -1; + + for (i = 0, ref = ref_map; ref; ref = ref->next) + i++; + if (!i) + return 0; + + argv = xmalloc(sizeof(*argv) * (i + 6)); + i = 0; + argv[i++] = xstrdup("rev-list"); + argv[i++] = xstrdup("--quiet"); + argv[i++] = xstrdup("--objects"); + for (ref = ref_map; ref; ref = ref->next) + argv[i++] = xstrdup(sha1_to_hex(ref->old_sha1)); + argv[i++] = xstrdup("--not"); + argv[i++] = xstrdup("--all"); + argv[i++] = NULL; + + memset(&revlist, 0, sizeof(revlist)); + revlist.argv = (const char**)argv; + revlist.git_cmd = 1; + revlist.no_stdin = 1; + revlist.no_stdout = 1; + revlist.no_stderr = 1; + err = run_command(&revlist); + + for (i = 0; argv[i]; i++) + free(argv[i]); + free(argv); + return err; +} + static int fetch_refs(struct transport *transport, struct ref *ref_map) { - int ret = transport_fetch_refs(transport, ref_map); + int ret = quickfetch(ref_map); + if (ret) + ret = transport_fetch_refs(transport, ref_map); if (!ret) store_updated_refs(transport->url, ref_map); transport_unlock_pack(transport); @@ -468,7 +533,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) static const char **refs = NULL; int ref_nr = 0; int cmd_len = 0; - const char *depth = NULL, *upload_pack = NULL; + const char *upload_pack = NULL; int keep = 0; for (i = 1; i < argc; i++) { -- cgit v1.2.1 From d6617c7cdebc20fe007e983f70b44a223dd52c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Goddard=20Rosa?= Date: Thu, 22 Nov 2007 20:22:23 -0200 Subject: Error out when user doesn't have access permission to the repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: André Goddard Rosa --- builtin-fetch.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 31e138eab8..de9947e7ac 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -255,7 +255,7 @@ static int update_local_ref(struct ref *ref, } } -static void store_updated_refs(const char *url, struct ref *ref_map) +static int store_updated_refs(const char *url, struct ref *ref_map) { FILE *fp; struct commit *commit; @@ -263,8 +263,11 @@ static void store_updated_refs(const char *url, struct ref *ref_map) char note[1024]; const char *what, *kind; struct ref *rm; + char *filename = git_path("FETCH_HEAD"); - fp = fopen(git_path("FETCH_HEAD"), "a"); + fp = fopen(filename, "a"); + if (!fp) + return error("cannot open %s: %s\n", filename, strerror(errno)); for (rm = ref_map; rm; rm = rm->next) { struct ref *ref = NULL; @@ -335,6 +338,7 @@ static void store_updated_refs(const char *url, struct ref *ref_map) } } fclose(fp); + return 0; } /* @@ -404,7 +408,7 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) if (ret) ret = transport_fetch_refs(transport, ref_map); if (!ret) - store_updated_refs(transport->url, ref_map); + ret |= store_updated_refs(transport->url, ref_map); transport_unlock_pack(transport); return ret; } @@ -487,8 +491,13 @@ static int do_fetch(struct transport *transport, die("Don't know how to fetch from %s", transport->url); /* if not appending, truncate FETCH_HEAD */ - if (!append) - fclose(fopen(git_path("FETCH_HEAD"), "w")); + if (!append) { + char *filename = git_path("FETCH_HEAD"); + FILE *fp = fopen(filename, "w"); + if (!fp) + return error("cannot open %s: %s\n", filename, strerror(errno)); + fclose(fp); + } ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags); -- cgit v1.2.1 From 2d324efad6a8f4808c5eec8fd299b79ab80a7ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 4 Dec 2007 02:25:46 -0500 Subject: Use a strbuf for copying the command line for the reflog. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- builtin-fetch.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index de9947e7ac..f6d16fe966 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -14,7 +14,7 @@ static const char fetch_usage[] = "git-fetch [-a | --append] [--upload-pack name, check_old ? ref->old_sha1 : NULL, 0); @@ -543,16 +543,19 @@ static void set_option(const char *name, const char *value) int cmd_fetch(int argc, const char **argv, const char *prefix) { struct remote *remote; - int i, j, rla_offset; + int i; static const char **refs = NULL; int ref_nr = 0; - int cmd_len = 0; const char *upload_pack = NULL; int keep = 0; + /* Record the command line for the reflog */ + strbuf_addstr(&default_rla, "fetch"); + for (i = 1; i < argc; i++) + strbuf_addf(&default_rla, " %s", argv[i]); + for (i = 1; i < argc; i++) { const char *arg = argv[i]; - cmd_len += strlen(arg); if (arg[0] != '-') break; @@ -613,17 +616,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) usage(fetch_usage); } - for (j = i; j < argc; j++) - cmd_len += strlen(argv[j]); - - default_rla = xmalloc(cmd_len + 5 + argc + 1); - sprintf(default_rla, "fetch"); - rla_offset = strlen(default_rla); - for (j = 1; j < argc; j++) { - sprintf(default_rla + rla_offset, " %s", argv[j]); - rla_offset += strlen(argv[j]) + 1; - } - if (i == argc) remote = remote_get(NULL); else -- cgit v1.2.1 From 83201998730ac5f0b95ac832f3b727da26ab0129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 4 Dec 2007 02:25:47 -0500 Subject: Rewrite builtin-fetch option parsing to use parse_options(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gets a little tricky because of the way --tags and --no-tags are handled, and the "tag " syntax needs a little hand-holding too. Signed-off-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- builtin-fetch.c | 123 +++++++++++++++++++++----------------------------------- 1 file changed, 46 insertions(+), 77 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index f6d16fe966..320e235682 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -9,14 +9,45 @@ #include "remote.h" #include "transport.h" #include "run-command.h" +#include "parse-options.h" -static const char fetch_usage[] = "git-fetch [-a | --append] [--upload-pack ] [-f | --force] [--no-tags] [-t | --tags] [-k | --keep] [-u | --update-head-ok] [--depth ] [-v | --verbose] [ ...]"; +static const char * const builtin_fetch_usage[] = { + "git-fetch [options] [ ...]", + NULL +}; -static int append, force, tags, no_tags, update_head_ok, verbose, quiet; +enum { + TAGS_UNSET = 0, + TAGS_DEFAULT = 1, + TAGS_SET = 2 +}; + +static int append, force, keep, update_head_ok, verbose, quiet; +static int tags = TAGS_DEFAULT; static const char *depth; +static const char *upload_pack; static struct strbuf default_rla = STRBUF_INIT; static struct transport *transport; +static struct option builtin_fetch_options[] = { + OPT__QUIET(&quiet), + OPT__VERBOSE(&verbose), + OPT_BOOLEAN('a', "append", &append, + "append to .git/FETCH_HEAD instead of overwriting"), + OPT_STRING(0, "upload-pack", &upload_pack, "PATH", + "path to upload pack on remote end"), + OPT_BOOLEAN('f', "force", &force, + "force overwrite of local branch"), + OPT_SET_INT('t', "tags", &tags, + "fetch all tags and associated objects", TAGS_SET), + OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"), + OPT_BOOLEAN('u', "update-head-ok", &update_head_ok, + "allow updating of HEAD ref"), + OPT_STRING(0, "depth", &depth, "DEPTH", + "deepen history of shallow clone"), + OPT_END() +}; + static void unlock_pack(void) { if (transport) @@ -81,7 +112,7 @@ static struct ref *get_ref_map(struct transport *transport, const struct ref *remote_refs = transport_get_remote_refs(transport); - if (ref_count || tags) { + if (ref_count || tags == TAGS_SET) { for (i = 0; i < ref_count; i++) { get_fetch_map(remote_refs, &refs[i], &tail, 0); if (refs[i].dst && refs[i].dst[0]) @@ -90,7 +121,7 @@ static struct ref *get_ref_map(struct transport *transport, /* Merge everything on the command line, but not --tags */ for (rm = ref_map; rm; rm = rm->next) rm->merge = 1; - if (tags) { + if (tags == TAGS_SET) { struct refspec refspec; refspec.src = "refs/tags/"; refspec.dst = "refs/tags/"; @@ -482,10 +513,10 @@ static int do_fetch(struct transport *transport, struct ref *ref_map, *fetch_map; struct ref *rm; int autotags = (transport->remote->fetch_tags == 1); - if (transport->remote->fetch_tags == 2 && !no_tags) - tags = 1; + if (transport->remote->fetch_tags == 2 && tags != TAGS_UNSET) + tags = TAGS_SET; if (transport->remote->fetch_tags == -1) - no_tags = 1; + tags = TAGS_UNSET; if (!transport->get_refs_list || !transport->fetch) die("Don't know how to fetch from %s", transport->url); @@ -515,7 +546,7 @@ static int do_fetch(struct transport *transport, /* if neither --no-tags nor --tags was specified, do automated tag * following ... */ - if (!(tags || no_tags) && autotags) { + if (tags == TAGS_DEFAULT && autotags) { ref_map = find_non_local_tags(transport, fetch_map); if (ref_map) { transport_set_option(transport, TRANS_OPT_DEPTH, "0"); @@ -546,80 +577,19 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) int i; static const char **refs = NULL; int ref_nr = 0; - const char *upload_pack = NULL; - int keep = 0; /* Record the command line for the reflog */ strbuf_addstr(&default_rla, "fetch"); for (i = 1; i < argc; i++) strbuf_addf(&default_rla, " %s", argv[i]); - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; - - if (arg[0] != '-') - break; - if (!strcmp(arg, "--append") || !strcmp(arg, "-a")) { - append = 1; - continue; - } - if (!prefixcmp(arg, "--upload-pack=")) { - upload_pack = arg + 14; - continue; - } - if (!strcmp(arg, "--upload-pack")) { - i++; - if (i == argc) - usage(fetch_usage); - upload_pack = argv[i]; - continue; - } - if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) { - force = 1; - continue; - } - if (!strcmp(arg, "--no-tags")) { - no_tags = 1; - continue; - } - if (!strcmp(arg, "--tags") || !strcmp(arg, "-t")) { - tags = 1; - continue; - } - if (!strcmp(arg, "--keep") || !strcmp(arg, "-k")) { - keep = 1; - continue; - } - if (!strcmp(arg, "--update-head-ok") || !strcmp(arg, "-u")) { - update_head_ok = 1; - continue; - } - if (!prefixcmp(arg, "--depth=")) { - depth = arg + 8; - continue; - } - if (!strcmp(arg, "--depth")) { - i++; - if (i == argc) - usage(fetch_usage); - depth = argv[i]; - continue; - } - if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) { - quiet = 1; - continue; - } - if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) { - verbose++; - continue; - } - usage(fetch_usage); - } + argc = parse_options(argc, argv, + builtin_fetch_options, builtin_fetch_usage, 0); - if (i == argc) + if (argc == 0) remote = remote_get(NULL); else - remote = remote_get(argv[i++]); + remote = remote_get(argv[0]); transport = transport_get(remote, remote->url[0]); if (verbose >= 2) @@ -636,10 +606,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (!transport->url) die("Where do you want to fetch from today?"); - if (i < argc) { + if (argc > 1) { int j = 0; - refs = xcalloc(argc - i + 1, sizeof(const char *)); - while (i < argc) { + refs = xcalloc(argc + 1, sizeof(const char *)); + for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "tag")) { char *ref; i++; @@ -651,7 +621,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) refs[j++] = ref; } else refs[j++] = argv[i]; - i++; } refs[j] = NULL; ref_nr = j; -- cgit v1.2.1 From ba227857d24029917f1e939647d826037f026205 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 4 Feb 2008 13:26:23 -0500 Subject: Reduce the number of connects when fetching This shares the connection between getting the remote ref list and getting objects in the first batch. (A second connection is still used to follow tags). When we do not fetch objects (i.e. either ls-remote disconnects after getting list of refs, or we decide we are already up-to-date), we clean up the connection properly; otherwise the connection is left open in need of cleaning up to avoid getting an error message from the remote end when ssh is used. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 320e235682..ac335f20fe 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -557,6 +557,8 @@ static int do_fetch(struct transport *transport, free_refs(fetch_map); + transport_disconnect(transport); + return 0; } -- cgit v1.2.1 From ff655a69df524c71464968f823a4826f2d43d7c6 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 2 Mar 2008 21:34:36 -0500 Subject: Remove unused variable in builtin-fetch find_non_local_tags Apparently fetch_map is passed through, but is not actually used. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index ac335f20fe..f8b9542ba6 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -452,8 +452,7 @@ static int add_existing(const char *refname, const unsigned char *sha1, return 0; } -static struct ref *find_non_local_tags(struct transport *transport, - struct ref *fetch_map) +static struct ref *find_non_local_tags(struct transport *transport) { static struct path_list existing_refs = { NULL, 0, 0, 0 }; struct path_list new_refs = { NULL, 0, 0, 1 }; @@ -547,7 +546,7 @@ static int do_fetch(struct transport *transport, /* if neither --no-tags nor --tags was specified, do automated tag * following ... */ if (tags == TAGS_DEFAULT && autotags) { - ref_map = find_non_local_tags(transport, fetch_map); + ref_map = find_non_local_tags(transport); if (ref_map) { transport_set_option(transport, TRANS_OPT_DEPTH, "0"); fetch_refs(transport, ref_map); -- cgit v1.2.1 From 7f98428d4beb24b564acbbfa779391467aab6f03 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 2 Mar 2008 21:34:43 -0500 Subject: Remove unnecessary delaying of free_refs(ref_map) in builtin-fetch We can free this ref_map as soon as the fetch is complete. It is not used for the automatic tag following, nor is it used to disconnect the transport. This avoids some confusion about why we are holding onto these refs while following tags. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index f8b9542ba6..1348a0e952 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -509,7 +509,7 @@ static struct ref *find_non_local_tags(struct transport *transport) static int do_fetch(struct transport *transport, struct refspec *refs, int ref_count) { - struct ref *ref_map, *fetch_map; + struct ref *ref_map; struct ref *rm; int autotags = (transport->remote->fetch_tags == 1); if (transport->remote->fetch_tags == 2 && tags != TAGS_UNSET) @@ -540,8 +540,7 @@ static int do_fetch(struct transport *transport, free_refs(ref_map); return 1; } - - fetch_map = ref_map; + free_refs(ref_map); /* if neither --no-tags nor --tags was specified, do automated tag * following ... */ @@ -554,8 +553,6 @@ static int do_fetch(struct transport *transport, free_refs(ref_map); } - free_refs(fetch_map); - transport_disconnect(transport); return 0; -- cgit v1.2.1 From 5aaf7f2afb46621c371564b07225ff5e978fc4b5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 2 Mar 2008 21:34:51 -0500 Subject: Ensure tail pointer gets setup correctly when we fetch HEAD only If we ever decided to append onto the end of this list the tail pointer must be looking at the right memory cell at the end of the HEAD ref_map. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 1348a0e952..5bce20f94f 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -157,6 +157,7 @@ static struct ref *get_ref_map(struct transport *transport, if (!ref_map) die("Couldn't find remote ref HEAD"); ref_map->merge = 1; + tail = &ref_map->next; } } ref_remove_duplicates(ref_map); -- cgit v1.2.1 From c50b2b47999134a5da1f9a5ccb36855313e44e7d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 2 Mar 2008 21:35:00 -0500 Subject: Allow builtin-fetch's find_non_local_tags to append onto a list By allowing the function to append onto the end of an existing list we can do more interesting things, like join the list of tags we want to fetch into the first fetch, rather than the second. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 5bce20f94f..1d3ce775ab 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -453,7 +453,9 @@ static int add_existing(const char *refname, const unsigned char *sha1, return 0; } -static struct ref *find_non_local_tags(struct transport *transport) +static void find_non_local_tags(struct transport *transport, + struct ref **head, + struct ref ***tail) { static struct path_list existing_refs = { NULL, 0, 0, 0 }; struct path_list new_refs = { NULL, 0, 0, 1 }; @@ -462,8 +464,6 @@ static struct ref *find_non_local_tags(struct transport *transport) const unsigned char *ref_sha1; const struct ref *tag_ref; struct ref *rm = NULL; - struct ref *ref_map = NULL; - struct ref **tail = &ref_map; const struct ref *ref; for_each_ref(add_existing, &existing_refs); @@ -498,13 +498,11 @@ static struct ref *find_non_local_tags(struct transport *transport) strcpy(rm->peer_ref->name, ref_name); hashcpy(rm->old_sha1, ref_sha1); - *tail = rm; - tail = &rm->next; + **tail = rm; + *tail = &rm->next; } free(ref_name); } - - return ref_map; } static int do_fetch(struct transport *transport, @@ -546,7 +544,9 @@ static int do_fetch(struct transport *transport, /* if neither --no-tags nor --tags was specified, do automated tag * following ... */ if (tags == TAGS_DEFAULT && autotags) { - ref_map = find_non_local_tags(transport); + struct ref **tail = &ref_map; + ref_map = NULL; + find_non_local_tags(transport, &ref_map, &tail); if (ref_map) { transport_set_option(transport, TRANS_OPT_DEPTH, "0"); fetch_refs(transport, ref_map); -- cgit v1.2.1 From 49d58fd0770cbb667a0d7532156ced803e482864 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 2 Mar 2008 21:35:10 -0500 Subject: Free the path_lists used to find non-local tags in git-fetch To support calling find_non_local_tags() more than once in a single git-fetch process we need the existing_refs to be stack-allocated so it resets on the second call. We also should free the path lists to avoid unnecessary memory leaking. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 1d3ce775ab..3758d4817e 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -457,7 +457,7 @@ static void find_non_local_tags(struct transport *transport, struct ref **head, struct ref ***tail) { - static struct path_list existing_refs = { NULL, 0, 0, 0 }; + struct path_list existing_refs = { NULL, 0, 0, 0 }; struct path_list new_refs = { NULL, 0, 0, 1 }; char *ref_name; int ref_name_len; @@ -503,6 +503,8 @@ static void find_non_local_tags(struct transport *transport, } free(ref_name); } + path_list_clear(&existing_refs, 0); + path_list_clear(&new_refs, 0); } static int do_fetch(struct transport *transport, -- cgit v1.2.1 From 767f176a1f11e07b9098f5094dbd9f4033e50504 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 2 Mar 2008 21:35:25 -0500 Subject: Make git-fetch follow tags we already have objects for sooner If autofollowing of tags is enabled, we see a new tag on the remote that we don't have, and we already have the SHA-1 object that the tag is peeled to, then we can fetch the tag while we are fetching the other objects on the first connection. This is a slight optimization for projects that have a habit of tagging a release commit after most users have already seen and downloaded that commit object through a prior fetch session. In such cases the users may still find new objects in branch heads, but the new tag will now also be part of the first pack transfer and the subsequent connection to autofollow tags is not required. Currently git.git does not benefit from this optimization as any release usually gets a new commit at the same time that it gets a new release tag, however git-gui.git and many other projects are in the habit of tagging fairly old commits. Users who did not already have the tagged commit still require opening a second connection to autofollow the tag, as we are unable to determine on the client side if $tag^{} will be sent to the client during the first transfer or not. Such computation must be performed on the remote side of the connection and is deferred to another series of changes. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 3758d4817e..a58efa6ece 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -101,6 +101,10 @@ static void add_merge_config(struct ref **head, } } +static void find_non_local_tags(struct transport *transport, + struct ref **head, + struct ref ***tail); + static struct ref *get_ref_map(struct transport *transport, struct refspec *refs, int ref_count, int tags, int *autotags) @@ -160,6 +164,8 @@ static struct ref *get_ref_map(struct transport *transport, tail = &ref_map->next; } } + if (tags == TAGS_DEFAULT && *autotags) + find_non_local_tags(transport, &ref_map, &tail); ref_remove_duplicates(ref_map); return ref_map; -- cgit v1.2.1 From cf7f929a10f141d319d47c68646c88d5911de777 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 2 Mar 2008 21:35:33 -0500 Subject: Teach git-fetch to grab a tag at the same time as a commit If the situation is the following on the remote and L is the common base between both sides: T - tag1 S - tag2 / / L - A - O - O - B \ \ origin/master master and we have decided to fetch "master" to acquire the range L..B we can also nab tag S at the same time during the first connection, as we can clearly see from the refs advertised by upload-pack that S^{} = B and master = B. Unfortunately we still cannot nab T at the same time as we are not able to see that T^{} will also be in the range implied by L..B. Such computations must be performed on the remote side (not yet supported) or on the client side as post-processing (the current behavior). This optimization is an extension of the previous one in that it helps on projects which tend to publish both a new commit and a new tag, then lay idle for a while before publishing anything else. Most followers are able to download both the new commit and the new tag in one connection, rather than two. git.git tends to follow such patterns with its roughly once-daily updates from Junio. A protocol extension and additional server side logic would be necessary to also ensure T is grabbed on the first connection. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index a58efa6ece..26c3d74b76 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -459,6 +459,17 @@ static int add_existing(const char *refname, const unsigned char *sha1, return 0; } +static int will_fetch(struct ref **head, const unsigned char *sha1) +{ + struct ref *rm = *head; + while (rm) { + if (!hashcmp(rm->old_sha1, sha1)) + return 1; + rm = rm->next; + } + return 0; +} + static void find_non_local_tags(struct transport *transport, struct ref **head, struct ref ***tail) @@ -495,7 +506,8 @@ static void find_non_local_tags(struct transport *transport, if (!path_list_has_path(&existing_refs, ref_name) && !path_list_has_path(&new_refs, ref_name) && - has_sha1_file(ref->old_sha1)) { + (has_sha1_file(ref->old_sha1) || + will_fetch(head, ref->old_sha1))) { path_list_insert(ref_name, &new_refs); rm = alloc_ref(strlen(ref_name) + 1); -- cgit v1.2.1 From 41fa7d2eaeace0c5c23fc75a3d5cc9efbad467a5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 3 Mar 2008 22:27:40 -0500 Subject: Teach git-fetch to exploit server side automatic tag following If the remote peer upload-pack process supports the include-tag protocol extension then we can avoid running a second fetch cycle on the client side by letting the server send us the annotated tags along with the objects it is packing for us. In the following graph we can now fetch both "tag1" and "tag2" on the same connection that we fetched "master" from the remote when we only have L available on the local side: T - tag1 S - tag2 / / L - o ------ o ------ B \ \ \ \ origin/master master The objects for "tag1" are implicitly downloaded without our direct knowledge. The existing "quickfetch" optimization within git-fetch discovers that tag1 is complete after the first connection and does not open a second connection. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-fetch.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 26c3d74b76..55f611e3c2 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -555,6 +555,8 @@ static int do_fetch(struct transport *transport, read_ref(rm->peer_ref->name, rm->peer_ref->old_sha1); } + if (tags == TAGS_DEFAULT && autotags) + transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1"); if (fetch_refs(transport, ref_map)) { free_refs(ref_map); return 1; @@ -568,6 +570,7 @@ static int do_fetch(struct transport *transport, ref_map = NULL; find_non_local_tags(transport, &ref_map, &tail); if (ref_map) { + transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL); transport_set_option(transport, TRANS_OPT_DEPTH, "0"); fetch_refs(transport, ref_map); } -- cgit v1.2.1 From e7951290f6f87ac413a3f1e3a870619275453efe Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 13 Mar 2008 08:13:15 +0100 Subject: git fetch: Take '-n' to mean '--no-tags' Prior to commit 8320199 (Rewrite builtin-fetch option parsing to use parse_options().), we understood '-n' as a short option to mean "don't fetch tags from the remote". This patch reinstates behaviour similar, but not identical to the pre commit 8320199 times. Back then, -n always overrode --tags, so if both --tags and -n was given on command-line, no tags were fetched regardless of argument ordering. Now we use a "last entry wins" strategy, so '-n --tags' means "fetch tags". Since it's patently absurd to say both --tags and --no-tags, this shouldn't matter in practice. Spotted-by: Artem Zolochevskiy Reported-by: Dmitry V. Levin Signed-off-by: Johannes Schindelin Tested-by: Andreas Ericsson Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 320e235682..9a6ddcec92 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -40,6 +40,8 @@ static struct option builtin_fetch_options[] = { "force overwrite of local branch"), OPT_SET_INT('t', "tags", &tags, "fetch all tags and associated objects", TAGS_SET), + OPT_SET_INT('n', NULL, &tags, + "do not fetch all tags (--no-tags)", TAGS_UNSET), OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"), OPT_BOOLEAN('u', "update-head-ok", &update_head_ok, "allow updating of HEAD ref"), -- cgit v1.2.1 From 46220ca100cfbcdd7d80a5ac3326c52a3e98dddb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 20 Mar 2008 23:34:37 -0700 Subject: remote.c: Fix overtight refspec validation We tightened the refspec validation code in an earlier commit ef00d15 (Tighten refspec processing, 2008-03-17) per my suggestion, but the suggestion was misguided to begin with and it broke this usage: $ git push origin HEAD~12:master The syntax of push refspecs and fetch refspecs are similar in that they are both colon separated LHS and RHS (possibly prefixed with a + to force), but the similarity ends there. For example, LHS in a push refspec can be anything that evaluates to a valid object name at runtime (except when colon and RHS is missing, or it is a glob), while it must be a valid-looking refname in a fetch refspec. To validate them correctly, the caller needs to be able to say which kind of refspecs they are. It is unreasonable to keep a single interface that cannot tell which kind it is dealing with, and ask it to behave sensibly. This commit separates the parsing of the two into different functions, and clarifies the code to implement the parsing proper (i.e. splitting into two parts, making sure both sides are wildcard or neither side is). This happens to also allow pushing a commit named with the esoteric "look for that string" syntax: $ git push ../test.git ':/remote.c: Fix overtight refspec:master' Signed-off-by: Junio C Hamano --- builtin-fetch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index b2b9935ed6..a11548c894 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -652,5 +652,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) signal(SIGINT, unlock_pack_on_signal); atexit(unlock_pack); - return do_fetch(transport, parse_ref_spec(ref_nr, refs), ref_nr); + return do_fetch(transport, + parse_fetch_refspec(ref_nr, refs), ref_nr); } -- cgit v1.2.1 From f53423b0e09d0de9584f72ac298bdfdc9e886d73 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Sat, 5 Apr 2008 14:28:53 -0400 Subject: git-fetch: Don't trigger a bus error when given the refspec "tag" When git-fetch encounters the refspec "tag" it assumes that the next argument will be a tag name. If there is no next argument, it should die gracefully instead of erroring. Signed-off-by: Kevin Ballard Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index a11548c894..5841b3e51a 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -637,6 +637,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (!strcmp(argv[i], "tag")) { char *ref; i++; + if (i >= argc) + die("You need to specify a tag name."); ref = xmalloc(strlen(argv[i]) * 2 + 22); strcpy(ref, "refs/tags/"); strcat(ref, argv[i]); -- cgit v1.2.1 From f59774add488a6c5fb440a4aaa7255f594b1027d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 9 Apr 2008 20:03:49 -0400 Subject: git-fetch: fix status output when not storing tracking ref There was code in update_local_ref for handling this case, but it never actually got called. It assumed that storing in FETCH_HEAD meant a blank peer_ref name, but we actually have a NULL peer_ref in this case, so we never even made it to the update_local_ref function. On top of that, the display formatting was different from all of the other cases, probably owing to the fact that nobody had ever actually seen the output. This patch harmonizes the output with the other cases and moves the detection of this case into store_updated_refs, where we can actually trigger it. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-fetch.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 5841b3e51a..139a6b10c5 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -215,13 +215,6 @@ static int update_local_ref(struct ref *ref, if (type < 0) die("object %s not found", sha1_to_hex(ref->new_sha1)); - if (!*ref->name) { - /* Not storing */ - if (verbose) - sprintf(display, "* branch %s -> FETCH_HEAD", remote); - return 0; - } - if (!hashcmp(ref->old_sha1, ref->new_sha1)) { if (verbose) sprintf(display, "= %-*s %-*s -> %s", SUMMARY_WIDTH, @@ -365,16 +358,21 @@ static int store_updated_refs(const char *url, struct ref *ref_map) rm->merge ? "" : "not-for-merge", note); - if (ref) { + if (ref) update_local_ref(ref, what, verbose, note); - if (*note) { - if (!shown_url) { - fprintf(stderr, "From %.*s\n", - url_len, url); - shown_url = 1; - } - fprintf(stderr, " %s\n", note); + else if (verbose) + sprintf(note, "* %-*s %-*s -> FETCH_HEAD", + SUMMARY_WIDTH, *kind ? kind : "branch", + REFCOL_WIDTH, *what ? what : "HEAD"); + else + *note = '\0'; + if (*note) { + if (!shown_url) { + fprintf(stderr, "From %.*s\n", + url_len, url); + shown_url = 1; } + fprintf(stderr, " %s\n", note); } } fclose(fp); -- cgit v1.2.1 From e5c49826d26e71ea18ff3010ef75edb1849df7ec Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 9 Apr 2008 20:11:52 -0400 Subject: git-fetch: always show status of non-tracking-ref fetches Previously, a fetch like: git fetch git://some/url would show no ref status output (just the object downloading status, if there was any), leading to some confusion. With this patch, we now show the usual ref table, with remote refs going into FETCH_HEAD. Previously this output was shown only if "-v"erbose was specified. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-fetch.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 139a6b10c5..e4486e4286 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -360,12 +360,10 @@ static int store_updated_refs(const char *url, struct ref *ref_map) if (ref) update_local_ref(ref, what, verbose, note); - else if (verbose) + else sprintf(note, "* %-*s %-*s -> FETCH_HEAD", SUMMARY_WIDTH, *kind ? kind : "branch", REFCOL_WIDTH, *what ? what : "HEAD"); - else - *note = '\0'; if (*note) { if (!shown_url) { fprintf(stderr, "From %.*s\n", -- cgit v1.2.1 From 7b7f39eae6ab0bbcc68d3c42a5b23595880e528f Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Mon, 28 Apr 2008 22:23:35 +0200 Subject: Fix use after free() in builtin-fetch As reported by Dave Jones: Since master.kernel.org updated to latest, I noticed that I could crash git-fetch by doing this.. export KERNEL=/pub/scm/linux/kernel/git/ git fetch $KERNEL/torvalds/linux-2.6 master:linus (gdb) bt 0 0x000000349fd6d44b in free () from /lib64/libc.so.6 1 0x000000000048f4eb in transport_unlock_pack (transport=0x7ce530) at transport.c:811 2 0x000000349fd31b25 in exit () from /lib64/libc.so.6 3 0x00000000004043d8 in handle_internal_command (argc=3, argv=0x7fffea4449f0) at git.c:379 4 0x0000000000404547 in main (argc=3, argv=0x7fffea4449f0) at git.c:443 5 0x000000349fd1c784 in __libc_start_main () from /lib64/libc.so.6 6 0x0000000000403ef9 in ?? () 7 0x00007fffea4449d8 in ?? () 8 0x0000000000000000 in ?? () I then remembered, my .bashrc has this.. export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) which is handy for showing up such bugs. More info on this glibc feature is at http://udrepper.livejournal.com/11429.html Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-fetch.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 139a6b10c5..167f948036 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -577,8 +577,6 @@ static int do_fetch(struct transport *transport, free_refs(ref_map); } - transport_disconnect(transport); - return 0; } @@ -599,6 +597,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) int i; static const char **refs = NULL; int ref_nr = 0; + int exit_code; /* Record the command line for the reflog */ strbuf_addstr(&default_rla, "fetch"); @@ -652,6 +651,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) signal(SIGINT, unlock_pack_on_signal); atexit(unlock_pack); - return do_fetch(transport, + exit_code = do_fetch(transport, parse_fetch_refspec(ref_nr, refs), ref_nr); + transport_disconnect(transport); + transport = NULL; + return exit_code; } -- cgit v1.2.1 From e0aaa29ff324c40a6428d5cc26867392eedf94ad Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Thu, 17 Apr 2008 19:32:35 -0400 Subject: Have a constant extern refspec for "--tags" The refspec refs/tags/*:refs/tags/* is sufficiently common and generic to merit having a constant instead of generating it as needed. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 167f948036..30aa42df6e 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -127,14 +127,8 @@ static struct ref *get_ref_map(struct transport *transport, /* Merge everything on the command line, but not --tags */ for (rm = ref_map; rm; rm = rm->next) rm->merge = 1; - if (tags == TAGS_SET) { - struct refspec refspec; - refspec.src = "refs/tags/"; - refspec.dst = "refs/tags/"; - refspec.pattern = 1; - refspec.force = 0; - get_fetch_map(remote_refs, &refspec, &tail, 0); - } + if (tags == TAGS_SET) + get_fetch_map(remote_refs, tag_refspec, &tail, 0); } else { /* Use the defaults */ struct remote *remote = transport->remote; -- cgit v1.2.1 From 737922aa648c43bc6a61170bee5bfd46ff953f32 Mon Sep 17 00:00:00 2001 From: Krzysztof Kowalczyk Date: Sat, 10 May 2008 16:26:58 -0700 Subject: alloc_ref_from_str(): factor out a common pattern of alloc_ref from string Also fix an underallocation in walker.c::interpret_target(). Signed-off-by: Krzysztof Kowalczyk Signed-off-by: Junio C Hamano --- builtin-fetch.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index e56617e32e..f6584ecea1 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -508,10 +508,8 @@ static void find_non_local_tags(struct transport *transport, will_fetch(head, ref->old_sha1))) { path_list_insert(ref_name, &new_refs); - rm = alloc_ref(strlen(ref_name) + 1); - strcpy(rm->name, ref_name); - rm->peer_ref = alloc_ref(strlen(ref_name) + 1); - strcpy(rm->peer_ref->name, ref_name); + rm = alloc_ref_from_str(ref_name); + rm->peer_ref = alloc_ref_from_str(ref_name); hashcpy(rm->old_sha1, ref_sha1); **tail = rm; -- cgit v1.2.1 From efb98b44536300f5daed25da3650033a1ce7fdef Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Wed, 28 May 2008 19:29:36 +0400 Subject: builtin-fetch.c (store_updated_refs): Honor update_local_ref() return value Sync with builtin-fetch--tool.c where append_fetch_head() honors update_local_ref() return value. This fixes non fast forward fetch exit status, http://bugzilla.altlinux.org/show_bug.cgi?id=15037 Signed-off-by: Dmitry V. Levin Signed-off-by: Junio C Hamano --- builtin-fetch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index bfe7711aa8..e81ee2d02b 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -286,7 +286,7 @@ static int store_updated_refs(const char *url, struct ref *ref_map) { FILE *fp; struct commit *commit; - int url_len, i, note_len, shown_url = 0; + int url_len, i, note_len, shown_url = 0, rc = 0; char note[1024]; const char *what, *kind; struct ref *rm; @@ -353,7 +353,7 @@ static int store_updated_refs(const char *url, struct ref *ref_map) note); if (ref) - update_local_ref(ref, what, verbose, note); + rc |= update_local_ref(ref, what, verbose, note); else sprintf(note, "* %-*s %-*s -> FETCH_HEAD", SUMMARY_WIDTH, *kind ? kind : "branch", @@ -368,7 +368,7 @@ static int store_updated_refs(const char *url, struct ref *ref_map) } } fclose(fp); - return 0; + return rc; } /* -- cgit v1.2.1 From 6315472eed9ff5f594560ddfd592ea21c665fe96 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 26 Jun 2008 23:59:50 -0400 Subject: fetch: report local storage errors in status table Previously, if there was an error while storing a local tracking ref, the low-level functions would report an error, but fetch's status output wouldn't indicate any problem. E.g., imagine you have an old "refs/remotes/origin/foo/bar" but upstream has deleted "foo/bar" in favor of a new branch "foo". You would get output like this: error: there are still refs under 'refs/remotes/origin/foo' From $url_of_repo * [new branch] foo -> origin/foo With this patch, the output takes into account the status of updating the local ref: error: there are still refs under 'refs/remotes/origin/foo' From $url_of_repo ! [new branch] foo -> origin/foo (unable to update local ref) Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-fetch.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index e81ee2d02b..7c16d38de7 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -233,10 +233,12 @@ static int update_local_ref(struct ref *ref, if (!is_null_sha1(ref->old_sha1) && !prefixcmp(ref->name, "refs/tags/")) { - sprintf(display, "- %-*s %-*s -> %s", + int r; + r = s_update_ref("updating tag", ref, 0); + sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-', SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote, - pretty_ref); - return s_update_ref("updating tag", ref, 0); + pretty_ref, r ? " (unable to update local ref)" : ""); + return r; } current = lookup_commit_reference_gently(ref->old_sha1, 1); @@ -244,6 +246,7 @@ static int update_local_ref(struct ref *ref, if (!current || !updated) { const char *msg; const char *what; + int r; if (!strncmp(ref->name, "refs/tags/", 10)) { msg = "storing tag"; what = "[new tag]"; @@ -253,27 +256,36 @@ static int update_local_ref(struct ref *ref, what = "[new branch]"; } - sprintf(display, "* %-*s %-*s -> %s", SUMMARY_WIDTH, what, - REFCOL_WIDTH, remote, pretty_ref); - return s_update_ref(msg, ref, 0); + r = s_update_ref(msg, ref, 0); + sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*', + SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref, + r ? " (unable to update local ref)" : ""); + return r; } if (in_merge_bases(current, &updated, 1)) { char quickref[83]; + int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, ".."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); - sprintf(display, " %-*s %-*s -> %s", SUMMARY_WIDTH, quickref, - REFCOL_WIDTH, remote, pretty_ref); - return s_update_ref("fast forward", ref, 1); + r = s_update_ref("fast forward", ref, 1); + sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ', + SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, + pretty_ref, r ? " (unable to update local ref)" : ""); + return r; } else if (force || ref->force) { char quickref[84]; + int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, "..."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); - sprintf(display, "+ %-*s %-*s -> %s (forced update)", - SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref); - return s_update_ref("forced-update", ref, 1); + r = s_update_ref("forced-update", ref, 1); + sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+', + SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, + pretty_ref, + r ? "unable to update local ref" : "forced update"); + return r; } else { sprintf(display, "! %-*s %-*s -> %s (non fast forward)", SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, -- cgit v1.2.1 From f3cb169bc9822e39a3efe637602b829cb338a213 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 27 Jun 2008 00:01:41 -0400 Subject: fetch: give a hint to the user when local refs fail to update There are basically two categories of update failures for local refs: 1. problems outside of git, like disk full, bad permissions, etc. 2. D/F conflicts on tracking branch ref names In either case, there should already have been an error message. In case '1', hopefully enough information has already been given that the user can fix it. In the case of '2', we can hint that the user can clean up their tracking branch area by using 'git remote prune'. Note that we don't actually know _which_ case we have, so the user will receive the hint in case 1, as well. In this case the suggestion won't do any good, but hopefully the user is smart enough to figure out that it's just a hint. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-fetch.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 7c16d38de7..97fdc51e31 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -181,9 +181,9 @@ static int s_update_ref(const char *action, lock = lock_any_ref_for_update(ref->name, check_old ? ref->old_sha1 : NULL, 0); if (!lock) - return 1; + return 2; if (write_ref_sha1(lock, ref->new_sha1, msg) < 0) - return 1; + return 2; return 0; } @@ -294,7 +294,8 @@ static int update_local_ref(struct ref *ref, } } -static int store_updated_refs(const char *url, struct ref *ref_map) +static int store_updated_refs(const char *url, const char *remote_name, + struct ref *ref_map) { FILE *fp; struct commit *commit; @@ -380,6 +381,10 @@ static int store_updated_refs(const char *url, struct ref *ref_map) } } fclose(fp); + if (rc & 2) + error("some local refs could not be updated; try running\n" + " 'git remote prune %s' to remove any old, conflicting " + "branches", remote_name); return rc; } @@ -450,7 +455,9 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) if (ret) ret = transport_fetch_refs(transport, ref_map); if (!ret) - ret |= store_updated_refs(transport->url, ref_map); + ret |= store_updated_refs(transport->url, + transport->remote->name, + ref_map); transport_unlock_pack(transport); return ret; } -- cgit v1.2.1 From 1b1dd23f2d6a707b7077cdf6bc6d4055bd0bfb7d Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Sun, 13 Jul 2008 15:36:15 +0200 Subject: Make usage strings dash-less When you misuse a git command, you are shown the usage string. But this is currently shown in the dashed form. So if you just copy what you see, it will not work, when the dashed form is no longer supported. This patch makes git commands show the dash-less version. For shell scripts that do not specify OPTIONS_SPEC, git-sh-setup.sh generates a dash-less usage string now. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 97fdc51e31..61de50a020 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -12,7 +12,7 @@ #include "parse-options.h" static const char * const builtin_fetch_usage[] = { - "git-fetch [options] [ ...]", + "git fetch [options] [ ...]", NULL }; -- cgit v1.2.1 From c455c87c5cd42bbbe586b31cea1143132f3a39e4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 21 Jul 2008 19:03:49 +0100 Subject: Rename path_list to string_list The name path_list was correct for the first usage of that data structure, but it really is a general-purpose string list. $ perl -i -pe 's/path-list/string-list/g' $(git grep -l path-list) $ perl -i -pe 's/path_list/string_list/g' $(git grep -l path_list) $ git mv path-list.h string-list.h $ git mv path-list.c string-list.c $ perl -i -pe 's/has_path/has_string/g' $(git grep -l has_path) $ perl -i -pe 's/path/string/g' string-list.[ch] $ git mv Documentation/technical/api-path-list.txt \ Documentation/technical/api-string-list.txt $ perl -i -pe 's/strdup_paths/strdup_strings/g' $(git grep -l strdup_paths) ... and then fix all users of string-list to access the member "string" instead of "path". Documentation/technical/api-string-list.txt needed some rewrapping, too. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-fetch.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 61de50a020..7eec4a0e43 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -5,7 +5,7 @@ #include "refs.h" #include "commit.h" #include "builtin.h" -#include "path-list.h" +#include "string-list.h" #include "remote.h" #include "transport.h" #include "run-command.h" @@ -465,8 +465,8 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) static int add_existing(const char *refname, const unsigned char *sha1, int flag, void *cbdata) { - struct path_list *list = (struct path_list *)cbdata; - path_list_insert(refname, list); + struct string_list *list = (struct string_list *)cbdata; + string_list_insert(refname, list); return 0; } @@ -485,8 +485,8 @@ static void find_non_local_tags(struct transport *transport, struct ref **head, struct ref ***tail) { - struct path_list existing_refs = { NULL, 0, 0, 0 }; - struct path_list new_refs = { NULL, 0, 0, 1 }; + struct string_list existing_refs = { NULL, 0, 0, 0 }; + struct string_list new_refs = { NULL, 0, 0, 1 }; char *ref_name; int ref_name_len; const unsigned char *ref_sha1; @@ -515,11 +515,11 @@ static void find_non_local_tags(struct transport *transport, } } - if (!path_list_has_path(&existing_refs, ref_name) && - !path_list_has_path(&new_refs, ref_name) && + if (!string_list_has_string(&existing_refs, ref_name) && + !string_list_has_string(&new_refs, ref_name) && (has_sha1_file(ref->old_sha1) || will_fetch(head, ref->old_sha1))) { - path_list_insert(ref_name, &new_refs); + string_list_insert(ref_name, &new_refs); rm = alloc_ref_from_str(ref_name); rm->peer_ref = alloc_ref_from_str(ref_name); @@ -530,8 +530,8 @@ static void find_non_local_tags(struct transport *transport, } free(ref_name); } - path_list_clear(&existing_refs, 0); - path_list_clear(&new_refs, 0); + string_list_clear(&existing_refs, 0); + string_list_clear(&new_refs, 0); } static int do_fetch(struct transport *transport, -- cgit v1.2.1 From 05207a28818623e417b69f337a9e8604d799d09d Mon Sep 17 00:00:00 2001 From: Heikki Orsila Date: Tue, 9 Sep 2008 13:28:30 +0300 Subject: Start conforming code to "git subcmd" style part 2 User notifications are presented as 'git cmd', and code comments are presented as '"cmd"' or 'git's cmd', rather than 'git-cmd'. Signed-off-by: Heikki Orsila Signed-off-by: Junio C Hamano --- builtin-fetch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 7eec4a0e43..ee93d3a93d 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -86,10 +86,10 @@ static void add_merge_config(struct ref **head, /* * Not fetched to a tracking branch? We need to fetch * it anyway to allow this branch's "branch.$name.merge" - * to be honored by git-pull, but we do not have to + * to be honored by 'git pull', but we do not have to * fail if branch.$name.merge is misconfigured to point * at a nonexisting branch. If we were indeed called by - * git-pull, it will notice the misconfiguration because + * 'git pull', it will notice the misconfiguration because * there is no entry in the resulting FETCH_HEAD marked * for merging. */ @@ -396,7 +396,7 @@ static int store_updated_refs(const char *url, const char *remote_name, * The refs we are going to fetch are in to_fetch (nr_heads in * total). If running * - * $ git-rev-list --objects to_fetch[0] to_fetch[1] ... --not --all + * $ git rev-list --objects to_fetch[0] to_fetch[1] ... --not --all * * does not error out, that means everything reachable from the * refs we are going to fetch exists and is connected to some of -- cgit v1.2.1 From 8ee5d73137f355c21e8d4db365ae8d301e067395 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 13 Oct 2008 11:36:52 +0200 Subject: Fix fetch/pull when run without --update-head-ok Some confusing tutorials suggested that it would be a good idea to fetch into the current branch with something like this: git fetch origin master:master (or even worse: the same command line with "pull" instead of "fetch"). While it might make sense to store what you want to pull, it typically is plain wrong when the current branch is "master". This should only be allowed when (an incorrect) "git pull origin master:master" tries to work around by giving --update-head-ok to underlying "git fetch", and otherwise we should refuse it, but somewhere along the lines we lost that behavior. The check for the current branch is now _only_ performed in non-bare repositories, which is an improvement from the original behaviour. Some newer tests were depending on the broken behaviour of "git fetch" this patch fixes, and have been adjusted. Signed-off-by: Johannes Schindelin Acked-by: Shawn O. Pearce Acked-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index ee93d3a93d..57c161d35b 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -534,6 +534,19 @@ static void find_non_local_tags(struct transport *transport, string_list_clear(&new_refs, 0); } +static void check_not_current_branch(struct ref *ref_map) +{ + struct branch *current_branch = branch_get(NULL); + + if (is_bare_repository() || !current_branch) + return; + + 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"); +} + static int do_fetch(struct transport *transport, struct refspec *refs, int ref_count) { @@ -558,6 +571,8 @@ static int do_fetch(struct transport *transport, } ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags); + if (!update_head_ok) + check_not_current_branch(ref_map); for (rm = ref_map; rm; rm = rm->next) { if (rm->peer_ref) -- cgit v1.2.1 From 59c69c0c656ebce2f7ce870b4913512597a98390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 18 Oct 2008 10:44:18 +0200 Subject: make alloc_ref_from_str() the new alloc_ref() With all calls to alloc_ref() gone, we can remove it and then we're free to give alloc_ref_from_str() the shorter name. It's a much nicer interface, as the callers always need to have a name string when they allocate a ref anyway and don't need to calculate and pass its length+1 any more. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- builtin-fetch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index ee93d3a93d..e008ee92ab 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -521,8 +521,8 @@ static void find_non_local_tags(struct transport *transport, will_fetch(head, ref->old_sha1))) { string_list_insert(ref_name, &new_refs); - rm = alloc_ref_from_str(ref_name); - rm->peer_ref = alloc_ref_from_str(ref_name); + rm = alloc_ref(ref_name); + rm->peer_ref = alloc_ref(ref_name); hashcpy(rm->old_sha1, ref_sha1); **tail = rm; -- cgit v1.2.1 From 7f87aff22c0232a5ce327ea3d2923776936c97f4 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Sat, 15 Nov 2008 01:14:24 +0100 Subject: Teach/Fix pull/fetch -q/-v options Implement git-pull --quiet and git-pull --verbose by adding the options to git-pull and fixing verbosity handling in git-fetch. Signed-off-by: Junio C Hamano --- builtin-fetch.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index f151cfa2fd..7568163af2 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -22,7 +22,7 @@ enum { TAGS_SET = 2 }; -static int append, force, keep, update_head_ok, verbose, quiet; +static int append, force, keep, update_head_ok, verbosity; static int tags = TAGS_DEFAULT; static const char *depth; static const char *upload_pack; @@ -30,8 +30,7 @@ static struct strbuf default_rla = STRBUF_INIT; static struct transport *transport; static struct option builtin_fetch_options[] = { - OPT__QUIET(&quiet), - OPT__VERBOSE(&verbose), + OPT__VERBOSITY(&verbosity), OPT_BOOLEAN('a', "append", &append, "append to .git/FETCH_HEAD instead of overwriting"), OPT_STRING(0, "upload-pack", &upload_pack, "PATH", @@ -192,7 +191,6 @@ static int s_update_ref(const char *action, static int update_local_ref(struct ref *ref, const char *remote, - int verbose, char *display) { struct commit *current = NULL, *updated; @@ -210,7 +208,7 @@ static int update_local_ref(struct ref *ref, die("object %s not found", sha1_to_hex(ref->new_sha1)); if (!hashcmp(ref->old_sha1, ref->new_sha1)) { - if (verbose) + if (verbosity > 0) sprintf(display, "= %-*s %-*s -> %s", SUMMARY_WIDTH, "[up to date]", REFCOL_WIDTH, remote, pretty_ref); @@ -366,18 +364,19 @@ static int store_updated_refs(const char *url, const char *remote_name, note); if (ref) - rc |= update_local_ref(ref, what, verbose, note); + rc |= update_local_ref(ref, what, note); else sprintf(note, "* %-*s %-*s -> FETCH_HEAD", SUMMARY_WIDTH, *kind ? kind : "branch", REFCOL_WIDTH, *what ? what : "HEAD"); if (*note) { - if (!shown_url) { + if (verbosity >= 0 && !shown_url) { fprintf(stderr, "From %.*s\n", url_len, url); shown_url = 1; } - fprintf(stderr, " %s\n", note); + if (verbosity >= 0) + fprintf(stderr, " %s\n", note); } } fclose(fp); @@ -637,9 +636,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) remote = remote_get(argv[0]); transport = transport_get(remote, remote->url[0]); - if (verbose >= 2) + if (verbosity >= 2) transport->verbose = 1; - if (quiet) + if (verbosity < 0) transport->verbose = -1; if (upload_pack) set_option(TRANS_OPT_UPLOADPACK, upload_pack); -- cgit v1.2.1 From d75307084da5f89329de190bb9b4a3196cec1d0e Mon Sep 17 00:00:00 2001 From: Alexander Potashev Date: Sun, 4 Jan 2009 21:38:41 +0300 Subject: remove trailing LF in die() messages LF at the end of format strings given to die() is redundant because die already adds one on its own. Signed-off-by: Alexander Potashev Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 7568163af2..de6f3074b1 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -607,7 +607,7 @@ static void set_option(const char *name, const char *value) { int r = transport_set_option(transport, name, value); if (r < 0) - die("Option \"%s\" value \"%s\" is not valid for %s\n", + 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", -- cgit v1.2.1 From 4a16d072723b48699ea162da24eff05eba298834 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Jan 2009 01:02:35 -0500 Subject: chain kill signals for cleanup functions If a piece of code wanted to do some cleanup before exiting (e.g., cleaning up a lockfile or a tempfile), our usual strategy was to install a signal handler that did something like this: do_cleanup(); /* actual work */ signal(signo, SIG_DFL); /* restore previous behavior */ raise(signo); /* deliver signal, killing ourselves */ For a single handler, this works fine. However, if we want to clean up two _different_ things, we run into a problem. The most recently installed handler will run, but when it removes itself as a handler, it doesn't put back the first handler. This patch introduces sigchain, a tiny library for handling a stack of signal handlers. You sigchain_push each handler, and use sigchain_pop to restore whoever was before you in the stack. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-fetch.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index de6f3074b1..8c86974cbe 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -10,6 +10,7 @@ #include "transport.h" #include "run-command.h" #include "parse-options.h" +#include "sigchain.h" static const char * const builtin_fetch_usage[] = { "git fetch [options] [ ...]", @@ -58,7 +59,7 @@ static void unlock_pack(void) static void unlock_pack_on_signal(int signo) { unlock_pack(); - signal(SIGINT, SIG_DFL); + sigchain_pop(signo); raise(signo); } @@ -672,7 +673,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) ref_nr = j; } - signal(SIGINT, unlock_pack_on_signal); + sigchain_push(SIGINT, unlock_pack_on_signal); atexit(unlock_pack); exit_code = do_fetch(transport, parse_fetch_refspec(ref_nr, refs), ref_nr); -- cgit v1.2.1 From 57b235a4bc8884a57c6f863605a54b7bfceb0997 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Jan 2009 01:03:08 -0500 Subject: refactor signal handling for cleanup functions The current code is very inconsistent about which signals are caught for doing cleanup of temporary files and lock files. Some callsites checked only SIGINT, while others checked a variety of death-dealing signals. This patch factors out those signals to a single function, and then calls it everywhere. For some sites, that means this is a simple clean up. For others, it is an improvement in that they will now properly clean themselves up after a larger variety of signals. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 8c86974cbe..1e4a3d9c51 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -673,7 +673,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) ref_nr = j; } - sigchain_push(SIGINT, unlock_pack_on_signal); + sigchain_push_common(unlock_pack_on_signal); atexit(unlock_pack); exit_code = do_fetch(transport, parse_fetch_refspec(ref_nr, refs), ref_nr); -- cgit v1.2.1 From a9c37a72c4fbc8537de294d66b05bdfd7f9a4016 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Sun, 8 Mar 2009 21:06:05 -0400 Subject: Use a common function to get the pretty name of refs The result should be consistent between fetch and push, so we ought to use the same code in both cases, even though it's short. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 1e4a3d9c51..f3bdeda059 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -197,11 +197,7 @@ static int update_local_ref(struct ref *ref, struct commit *current = NULL, *updated; enum object_type type; struct branch *current_branch = branch_get(NULL); - const char *pretty_ref = ref->name + ( - !prefixcmp(ref->name, "refs/heads/") ? 11 : - !prefixcmp(ref->name, "refs/tags/") ? 10 : - !prefixcmp(ref->name, "refs/remotes/") ? 13 : - 0); + const char *pretty_ref = prettify_ref(ref); *display = 0; type = sha1_object_info(ref->new_sha1, NULL); -- cgit v1.2.1 From fa685bdf45cbaa997255cc78a23494b995e9769a Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Wed, 11 Mar 2009 01:47:20 -0400 Subject: Give error when no remote is configured When there's no explicitly-named remote, we use the remote specified for the current branch, which in turn defaults to "origin". But it this case should require the remote to actually be configured, and not fall back to the path "origin". Possibly, the config file's "remote = something" should require the something to be a configured remote instead of a bare repository URL, but we actually test with a bare repository URL. In fetch, we were giving the sensible error message when coming up with a URL failed, but this wasn't actually reachable, so move that error up and use it when appropriate. In push, we need a new error message, because the old one (formerly unreachable without a lot of help) used the repo name, which was NULL. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-fetch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 1e4a3d9c51..7fb35fca9d 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -636,6 +636,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) else remote = remote_get(argv[0]); + if (!remote) + die("Where do you want to fetch from today?"); + transport = transport_get(remote, remote->url[0]); if (verbosity >= 2) transport->verbose = 1; @@ -648,9 +651,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) if (depth) set_option(TRANS_OPT_DEPTH, depth); - if (!transport->url) - die("Where do you want to fetch from today?"); - if (argc > 1) { int j = 0; refs = xcalloc(argc + 1, sizeof(const char *)); -- cgit v1.2.1 From 26284f9356f4c4d8865db8bb024121311a1f90ff Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Sun, 22 Mar 2009 23:07:33 +0100 Subject: Improve error message about fetch into current branch Otherwise, it is hard to guess why the fetch failed. Make sure we at least mention that the repository must be bare. Also the current branch is printed. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-fetch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 7fb35fca9d..7293146525 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -544,7 +544,8 @@ static void check_not_current_branch(struct ref *ref_map) 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"); + die("Refusing to fetch into current branch %s " + "of non-bare repository", current_branch->refname); } static int do_fetch(struct transport *transport, -- cgit v1.2.1 From 47abd85ba06ed7209d1caa3e5ac7cc6b232bece4 Mon Sep 17 00:00:00 2001 From: Andreas Ericsson Date: Fri, 17 Apr 2009 10:20:11 +0200 Subject: fetch: Strip usernames from url's before storing them When pulling from a remote, the full URL including username is by default added to the commit message. Since it adds very little value but could be used by malicious people to glean valid usernames (with matching hostnames), we're far better off just stripping the username before storing the remote URL locally. Note that this patch has no lasting visible effect when "git pull" does not create a merge commit. It simply alters what gets written to .git/FETCH_HEAD, which is used by "git merge" to automagically create its messages. Signed-off-by: Andreas Ericsson Signed-off-by: Junio C Hamano --- builtin-fetch.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 3c998ea740..0bb290bf2f 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -289,7 +289,7 @@ static int update_local_ref(struct ref *ref, } } -static int store_updated_refs(const char *url, const char *remote_name, +static int store_updated_refs(const char *raw_url, const char *remote_name, struct ref *ref_map) { FILE *fp; @@ -298,11 +298,13 @@ static int store_updated_refs(const char *url, const char *remote_name, char note[1024]; const char *what, *kind; struct ref *rm; - char *filename = git_path("FETCH_HEAD"); + char *url, *filename = git_path("FETCH_HEAD"); fp = fopen(filename, "a"); if (!fp) return error("cannot open %s: %s\n", filename, strerror(errno)); + + url = transport_anonymize_url(raw_url); for (rm = ref_map; rm; rm = rm->next) { struct ref *ref = NULL; @@ -376,6 +378,7 @@ static int store_updated_refs(const char *url, const char *remote_name, fprintf(stderr, " %s\n", note); } } + free(url); fclose(fp); if (rc & 2) error("some local refs could not be updated; try running\n" -- cgit v1.2.1 From 95405ba6cf7adeaa4a066e8a3a1b76b73f7b9341 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Wed, 13 May 2009 20:08:53 +0200 Subject: Quote LF in urls git fetch saves in FETCH_HEAD The fmt-merge-msg does a strong syntax checking of its input and fails with if it is incorrect. The LF character is the only character important for fmt-merge-msg. As the url in FETCH_HEAD plays only informational role, a quoted representation of the url should be good and true enough. The url often comes from either user-editable config or command line, so it is reasonable to expect all kinds of characters in it, including the characters which the format of FETCH_HEAD considers special (line separator in this case). Noticed and reported by Hugo Mildenberger. Signed-off-by: Alex Riesen 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 3c998ea740..ec75df0900 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -353,12 +353,18 @@ static int store_updated_refs(const char *url, const char *remote_name, kind); note_len += sprintf(note + note_len, "'%s' of ", what); } - note_len += sprintf(note + note_len, "%.*s", url_len, url); - fprintf(fp, "%s\t%s\t%s\n", + note[note_len] = '\0'; + fprintf(fp, "%s\t%s\t%s", sha1_to_hex(commit ? commit->object.sha1 : rm->old_sha1), rm->merge ? "" : "not-for-merge", note); + for (i = 0; i < url_len; ++i) + if ('\n' == url[i]) + fputs("\\n", fp); + else + fputc(url[i], fp); + fputc('\n', fp); if (ref) rc |= update_local_ref(ref, what, note); -- cgit v1.2.1 From 4577e483648f50dd80faa401dc1d3eb33ffb627b Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Thu, 14 May 2009 00:22:04 +0300 Subject: Change prettify_ref to prettify_refname In preparation to be used when the ref object is not available Signed-off-by: Felipe Contreras Acked-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 3c998ea740..ebd0c08788 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -197,7 +197,7 @@ static int update_local_ref(struct ref *ref, struct commit *current = NULL, *updated; enum object_type type; struct branch *current_branch = branch_get(NULL); - const char *pretty_ref = prettify_ref(ref); + const char *pretty_ref = prettify_refname(ref->name); *display = 0; type = sha1_object_info(ref->new_sha1, NULL); -- cgit v1.2.1 From 377829201783b8a648e07af6ce7d747e0f45dc19 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 23 May 2009 11:53:12 -0700 Subject: parse-opts: prepare for OPT_FILENAME To give OPT_FILENAME the prefix, we pass the prefix to parse_options() which passes the prefix to parse_options_start() which sets the prefix member of parse_opts_ctx accordingly. If there isn't a prefix in the calling context, passing NULL will suffice. Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- builtin-fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 77acabfcc7..0ed6016da1 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -634,7 +634,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) for (i = 1; i < argc; i++) strbuf_addf(&default_rla, " %s", argv[i]); - argc = parse_options(argc, argv, + argc = parse_options(argc, argv, prefix, builtin_fetch_options, builtin_fetch_usage, 0); if (argc == 0) -- cgit v1.2.1 From fa250759794ab98e6edfbbf2f6aa2cb912e535eb Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 25 May 2009 06:40:54 -0400 Subject: fetch: report ref storage DF errors more accurately When we fail to store a fetched ref, we recommend that the user try running "git prune" to remove up any old refs that have been deleted by the remote, which would clear up any DF conflicts. However, ref storage might fail for other reasons (e.g., permissions problems) in which case the advice is useless and misleading. This patch detects when there is an actual DF situation and only issues the advice when one is found. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-fetch.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index 3c998ea740..1f7a3f1ce6 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -167,6 +167,9 @@ static struct ref *get_ref_map(struct transport *transport, return ref_map; } +#define STORE_REF_ERROR_OTHER 1 +#define STORE_REF_ERROR_DF_CONFLICT 2 + static int s_update_ref(const char *action, struct ref *ref, int check_old) @@ -181,9 +184,11 @@ static int s_update_ref(const char *action, lock = lock_any_ref_for_update(ref->name, check_old ? ref->old_sha1 : NULL, 0); if (!lock) - return 2; + return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT : + STORE_REF_ERROR_OTHER; if (write_ref_sha1(lock, ref->new_sha1, msg) < 0) - return 2; + return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT : + STORE_REF_ERROR_OTHER; return 0; } @@ -377,7 +382,7 @@ static int store_updated_refs(const char *url, const char *remote_name, } } fclose(fp); - if (rc & 2) + 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); -- cgit v1.2.1 From d9eb0205a217984f3e70bf18ae66c02a22d3d475 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Fri, 10 Jul 2009 01:52:30 +0200 Subject: quickfetch(): Prevent overflow of the rev-list command line quickfetch() calls rev-list to check whether the objects we are about to fetch are already present in the repo (if so, we can skip the object fetch). However, when there are many (~1000) refs to be fetched, the rev-list command line grows larger than the maximum command line size on some systems (32K in Windows). This causes rev-list to fail, making quickfetch() return non-zero, which unnecessarily triggers the transport machinery. This somehow causes fetch to fail with an exit code. By using the --stdin option to rev-list (and feeding the object list to its standard input), we prevent the overflow of the rev-list command line, which causes quickfetch(), and subsequently the overall fetch, to succeed. However, using rev-list --stdin is not entirely straightforward: rev-list terminates immediately when encountering an unknown object, which can trigger SIGPIPE if we are still writing object's to its standard input. We therefore temporarily ignore SIGPIPE so that the fetch process is not terminated. The patch also contains a testcase to verify the fix (note that before the patch, the testcase would only fail on msysGit). Signed-off-by: Johan Herland Improved-by: Johannes Sixt Improved-by: Alex Riesen Tested-by: Peter Krefting Signed-off-by: Junio C Hamano --- builtin-fetch.c | 67 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 27 deletions(-) (limited to 'builtin-fetch.c') diff --git a/builtin-fetch.c b/builtin-fetch.c index cd5eb9aff5..817dd6bff0 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -400,14 +400,14 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, /* * We would want to bypass the object transfer altogether if - * everything we are going to fetch already exists and connected + * everything we are going to fetch already exists and is connected * locally. * - * The refs we are going to fetch are in to_fetch (nr_heads in - * total). If running + * The refs we are going to fetch are in ref_map. If running * - * $ git rev-list --objects to_fetch[0] to_fetch[1] ... --not --all + * $ 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. @@ -416,8 +416,9 @@ static int quickfetch(struct ref *ref_map) { struct child_process revlist; struct ref *ref; - char **argv; - int i, err; + int err; + const char *argv[] = {"rev-list", + "--quiet", "--objects", "--stdin", "--not", "--all", NULL}; /* * If we are deepening a shallow clone we already have these @@ -429,34 +430,46 @@ static int quickfetch(struct ref *ref_map) if (depth) return -1; - for (i = 0, ref = ref_map; ref; ref = ref->next) - i++; - if (!i) + if (!ref_map) return 0; - argv = xmalloc(sizeof(*argv) * (i + 6)); - i = 0; - argv[i++] = xstrdup("rev-list"); - argv[i++] = xstrdup("--quiet"); - argv[i++] = xstrdup("--objects"); - for (ref = ref_map; ref; ref = ref->next) - argv[i++] = xstrdup(sha1_to_hex(ref->old_sha1)); - argv[i++] = xstrdup("--not"); - argv[i++] = xstrdup("--all"); - argv[i++] = NULL; - memset(&revlist, 0, sizeof(revlist)); - revlist.argv = (const char**)argv; + revlist.argv = argv; revlist.git_cmd = 1; - revlist.no_stdin = 1; revlist.no_stdout = 1; revlist.no_stderr = 1; - err = run_command(&revlist); + 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_in_full(revlist.in, "\n", 1) < 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); - for (i = 0; argv[i]; i++) - free(argv[i]); - free(argv); - return err; + return finish_command(&revlist) || err; } static int fetch_refs(struct transport *transport, struct ref *ref_map) -- cgit v1.2.1