diff options
-rw-r--r-- | Documentation/fetch-options.txt | 5 | ||||
-rw-r--r-- | Documentation/git-fetch-pack.txt | 5 | ||||
-rw-r--r-- | Documentation/gitremote-helpers.txt | 4 | ||||
-rw-r--r-- | Documentation/technical/protocol-capabilities.txt | 7 | ||||
-rw-r--r-- | builtin/fetch-pack.c | 4 | ||||
-rw-r--r-- | builtin/fetch.c | 14 | ||||
-rw-r--r-- | fetch-pack.c | 3 | ||||
-rw-r--r-- | fetch-pack.h | 1 | ||||
-rw-r--r-- | remote-curl.c | 14 | ||||
-rwxr-xr-x | t/t5500-fetch-pack.sh | 23 | ||||
-rwxr-xr-x | t/t5539-fetch-http-shallow.sh | 26 | ||||
-rw-r--r-- | transport-helper.c | 1 | ||||
-rw-r--r-- | transport.c | 4 | ||||
-rw-r--r-- | transport.h | 4 | ||||
-rw-r--r-- | upload-pack.c | 23 |
15 files changed, 132 insertions, 6 deletions
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 7aa1285fc9..3b91f1528e 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -14,6 +14,11 @@ linkgit:git-clone[1]), deepen or shorten the history to the specified number of commits. Tags for the deepened commits are not fetched. +--deepen=<depth>:: + Similar to --depth, except it specifies the number of commits + from the current shallow boundary instead of from the tip of + each remote branch history. + --shallow-since=<date>:: Deepen or shorten the history of a shallow repository to include all reachable commits after <date>. diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt index 4d15b0469c..c20958f58f 100644 --- a/Documentation/git-fetch-pack.txt +++ b/Documentation/git-fetch-pack.txt @@ -96,6 +96,11 @@ be in a separate packet, and the list must end with a flush packet. exclude commits reachable from a specified remote branch or tag. This option can be specified multiple times. +--deepen-relative:: + Argument --depth specifies the number of commits from the + current shallow boundary instead of from the tip of each + remote branch history. + --no-progress:: Do not show the progress. diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt index 75bb6381f6..6fca268742 100644 --- a/Documentation/gitremote-helpers.txt +++ b/Documentation/gitremote-helpers.txt @@ -422,6 +422,10 @@ set by Git if the remote helper has the 'option' capability. Deepens the history of a shallow repository excluding ref. Multiple options add up. +'option deepen-relative {'true'|'false'}:: + Deepens the history of a shallow repository relative to + current boundary. Only valid when used with "option depth". + 'option followtags' {'true'|'false'}:: If enabled the helper should automatically fetch annotated tag objects if the object the tag points at was transferred diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt index 0e6b57df75..4fd6dccdb5 100644 --- a/Documentation/technical/protocol-capabilities.txt +++ b/Documentation/technical/protocol-capabilities.txt @@ -197,6 +197,13 @@ specific revision, instead of depth. Internally it's equivalent of doing "rev-list --not <rev>" on the server side. "deepen-not" cannot be used with "deepen", but can be used with "deepen-since". +deepen-relative +--------------- + +If this capability is requested by the client, the semantics of +"deepen" command is changed. The "depth" argument is the depth from +the current shallow boundary, instead of the depth from remote refs. + no-progress ----------- diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 07570bee2d..82653487f8 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -113,6 +113,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) string_list_append(&deepen_not, arg); continue; } + if (!strcmp(arg, "--deepen-relative")) { + args.deepen_relative = 1; + continue; + } if (!strcmp("--no-progress", arg)) { args.no_progress = 1; continue; diff --git a/builtin/fetch.c b/builtin/fetch.c index 147504dd51..7b0ea1c86e 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -34,7 +34,7 @@ static int fetch_prune_config = -1; /* unspecified */ static int prune = -1; /* unspecified */ #define PRUNE_BY_DEFAULT 0 /* do we prune by default? */ -static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity; +static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative; static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen; static int max_children = 1; @@ -121,6 +121,8 @@ static struct option builtin_fetch_options[] = { N_("deepen history of shallow repository based on time")), OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"), N_("deepen history of shallow clone by excluding rev")), + OPT_INTEGER(0, "deepen", &deepen_relative, + N_("deepen history of shallow clone")), { OPTION_SET_INT, 0, "unshallow", &unshallow, NULL, N_("convert to a complete repository"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 }, @@ -881,6 +883,8 @@ static struct transport *prepare_transport(struct remote *remote, int deepen) if (deepen && deepen_not.nr) set_option(transport, TRANS_OPT_DEEPEN_NOT, (const char *)&deepen_not); + if (deepen_relative) + set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, "yes"); if (update_shallow) set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes"); return transport; @@ -906,6 +910,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map) transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL); transport_set_option(transport, TRANS_OPT_DEPTH, "0"); + transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL); fetch_refs(transport, ref_map); if (gsecondary) { @@ -1177,6 +1182,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, builtin_fetch_options, builtin_fetch_usage, 0); + if (deepen_relative) { + if (deepen_relative < 0) + die(_("Negative depth in --deepen is not supported")); + if (depth) + die(_("--deepen and --depth are mutually exclusive")); + depth = xstrfmt("%d", deepen_relative); + } if (unshallow) { if (depth) die(_("--depth and --unshallow cannot be used together")); diff --git a/fetch-pack.c b/fetch-pack.c index ad7d00f09c..e2a235f536 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -324,6 +324,7 @@ static int find_common(struct fetch_pack_args *args, if (no_done) strbuf_addstr(&c, " no-done"); if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k"); if (use_sideband == 1) strbuf_addstr(&c, " side-band"); + if (args->deepen_relative) strbuf_addstr(&c, " deepen-relative"); if (args->use_thin_pack) strbuf_addstr(&c, " thin-pack"); if (args->no_progress) strbuf_addstr(&c, " no-progress"); if (args->include_tag) strbuf_addstr(&c, " include-tag"); @@ -883,6 +884,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, deepen_not_ok = 1; else if (args->deepen_not) die(_("Server does not support --shallow-exclude")); + if (!server_supports("deepen-relative") && args->deepen_relative) + die(_("Server does not support --deepen")); if (everything_local(args, &ref, sought, nr_sought)) { packet_flush(fd[1]); diff --git a/fetch-pack.h b/fetch-pack.h index 144301fbcd..c912e3d321 100644 --- a/fetch-pack.h +++ b/fetch-pack.h @@ -12,6 +12,7 @@ struct fetch_pack_args { int depth; const char *deepen_since; const struct string_list *deepen_not; + unsigned deepen_relative:1; unsigned quiet:1; unsigned keep_pack:1; unsigned lock_pack:1; diff --git a/remote-curl.c b/remote-curl.c index 1406e6a4eb..d56412deb1 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -30,7 +30,8 @@ struct options { dry_run : 1, thin : 1, /* One of the SEND_PACK_PUSH_CERT_* constants. */ - push_cert : 2; + push_cert : 2, + deepen_relative : 1; }; static struct options options; static struct string_list cas_options = STRING_LIST_INIT_DUP; @@ -70,6 +71,15 @@ static int set_option(const char *name, const char *value) string_list_append(&options.deepen_not, value); return 0; } + else if (!strcmp(name, "deepen-relative")) { + if (!strcmp(value, "true")) + options.deepen_relative = 1; + else if (!strcmp(value, "false")) + options.deepen_relative = 0; + else + return -1; + return 0; + } else if (!strcmp(name, "followtags")) { if (!strcmp(value, "true")) options.followtags = 1; @@ -761,6 +771,8 @@ static int fetch_git(struct discovery *heads, for (i = 0; i < options.deepen_not.nr; i++) argv_array_pushf(&args, "--shallow-exclude=%s", options.deepen_not.items[i].string); + if (options.deepen_relative && options.depth) + argv_array_push(&args, "--deepen-relative"); argv_array_push(&args, url.buf); for (i = 0; i < nr_heads; i++) { diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 145b370768..a908036be7 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -682,4 +682,27 @@ test_expect_success 'fetch exclude tag one' ' test_cmp expected actual ' +test_expect_success 'fetching deepen' ' + test_create_repo shallow-deepen && + ( + cd shallow-deepen && + test_commit one && + test_commit two && + test_commit three && + git clone --depth 1 "file://$(pwd)/." deepen && + test_commit four && + git -C deepen log --pretty=tformat:%s master >actual && + echo three >expected && + test_cmp expected actual && + git -C deepen fetch --deepen=1 && + git -C deepen log --pretty=tformat:%s origin/master >actual && + cat >expected <<-\EOF && + four + three + two + EOF + test_cmp expected actual + ) +' + test_done diff --git a/t/t5539-fetch-http-shallow.sh b/t/t5539-fetch-http-shallow.sh index 8e38c1be65..5fbf67c446 100755 --- a/t/t5539-fetch-http-shallow.sh +++ b/t/t5539-fetch-http-shallow.sh @@ -120,5 +120,31 @@ test_expect_success 'fetch exclude tag one' ' test_cmp expected actual ' +test_expect_success 'fetching deepen' ' + test_create_repo shallow-deepen && + ( + cd shallow-deepen && + test_commit one && + test_commit two && + test_commit three && + mv .git "$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git" && + git clone --depth 1 $HTTPD_URL/smart/shallow-deepen.git deepen && + mv "$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git" .git && + test_commit four && + git -C deepen log --pretty=tformat:%s master >actual && + echo three >expected && + test_cmp expected actual && + mv .git "$HTTPD_DOCUMENT_ROOT_PATH/shallow-deepen.git" && + git -C deepen fetch --deepen=1 && + git -C deepen log --pretty=tformat:%s origin/master >actual && + cat >expected <<-\EOF && + four + three + two + EOF + test_cmp expected actual + ) +' + stop_httpd test_done diff --git a/transport-helper.c b/transport-helper.c index cc1a396c25..a5cdd7730c 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -258,6 +258,7 @@ static const char *boolean_options[] = { TRANS_OPT_THIN, TRANS_OPT_KEEP, TRANS_OPT_FOLLOWTAGS, + TRANS_OPT_DEEPEN_RELATIVE }; static int strbuf_set_helper_option(struct helper_data *data, diff --git a/transport.c b/transport.c index 3e6f3aa117..3e76a9af4d 100644 --- a/transport.c +++ b/transport.c @@ -157,6 +157,9 @@ static int set_git_option(struct git_transport_options *opts, } else if (!strcmp(name, TRANS_OPT_DEEPEN_NOT)) { opts->deepen_not = (const struct string_list *)value; return 0; + } else if (!strcmp(name, TRANS_OPT_DEEPEN_RELATIVE)) { + opts->deepen_relative = !!value; + return 0; } return 1; } @@ -213,6 +216,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.depth = data->options.depth; args.deepen_since = data->options.deepen_since; args.deepen_not = data->options.deepen_not; + args.deepen_relative = data->options.deepen_relative; args.check_self_contained_and_connected = data->options.check_self_contained_and_connected; args.cloning = transport->cloning; diff --git a/transport.h b/transport.h index ab61932b5b..bdc35181c3 100644 --- a/transport.h +++ b/transport.h @@ -14,6 +14,7 @@ struct git_transport_options { unsigned check_self_contained_and_connected : 1; unsigned self_contained_and_connected : 1; unsigned update_shallow : 1; + unsigned deepen_relative : 1; int depth; const char *deepen_since; const struct string_list *deepen_not; @@ -181,6 +182,9 @@ int transport_restrict_protocols(void); /* Limit the depth of the fetch based on revs if not null */ #define TRANS_OPT_DEEPEN_NOT "deepen-not" +/* Limit the deepen of the fetch if not null */ +#define TRANS_OPT_DEEPEN_RELATIVE "deepen-relative" + /* Aggressively fetch annotated tags if possible */ #define TRANS_OPT_FOLLOWTAGS "followtags" diff --git a/upload-pack.c b/upload-pack.c index 3227df872c..e40d15adaf 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -32,6 +32,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=< static unsigned long oldest_have; +static int deepen_relative; static int multi_ack; static int no_done; static int use_thin_pack, use_ofs_delta, use_include_tag; @@ -674,7 +675,8 @@ static void send_unshallow(const struct object_array *shallows) } } -static void deepen(int depth, const struct object_array *shallows) +static void deepen(int depth, int deepen_relative, + struct object_array *shallows) { if (depth == INFINITE_DEPTH && !is_repository_shallow()) { int i; @@ -683,6 +685,17 @@ static void deepen(int depth, const struct object_array *shallows) struct object *object = shallows->objects[i].item; object->flags |= NOT_SHALLOW; } + } else if (deepen_relative) { + struct object_array reachable_shallows = OBJECT_ARRAY_INIT; + struct commit_list *result; + + get_reachable_list(shallows, &reachable_shallows); + result = get_shallow_commits(&reachable_shallows, + depth + 1, + SHALLOW, NOT_SHALLOW); + send_shallow(result); + free_commit_list(result); + object_array_clear(&reachable_shallows); } else { struct commit_list *result; @@ -779,6 +792,8 @@ static void receive_needs(void) features = arg + 40; + if (parse_feature_request(features, "deepen-relative")) + deepen_relative = 1; if (parse_feature_request(features, "multi_ack_detailed")) multi_ack = 2; else if (parse_feature_request(features, "multi_ack")) @@ -828,7 +843,7 @@ static void receive_needs(void) if (depth > 0 && deepen_rev_list) die("git upload-pack: deepen and deepen-since (or deepen-not) cannot be used together"); if (depth > 0) - deepen(depth, &shallows); + deepen(depth, deepen_relative, &shallows); else if (deepen_rev_list) { struct argv_array av = ARGV_ARRAY_INIT; int i; @@ -899,8 +914,8 @@ static int send_ref(const char *refname, const struct object_id *oid, int flag, void *cb_data) { static const char *capabilities = "multi_ack thin-pack side-band" - " side-band-64k ofs-delta shallow deepen-since deepen-not no-progress" - " include-tag multi_ack_detailed"; + " side-band-64k ofs-delta shallow deepen-since deepen-not" + " deepen-relative no-progress include-tag multi_ack_detailed"; const char *refname_nons = strip_namespace(refname); struct object_id peeled; |