fetch: define shallow boundary with --shallow-exclude

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Jun 12, 2016 at 17:54 UTC a45a260086b395729e3c26c9680602e1352184b5
11 files changed +89 -4
Documentation/fetch-options.txt
+5
@@ -18,6 +18,11 @@
18 Deepen or shorten the history of a shallow repository to
19 include all reachable commits after <date>.
20
21 +--shallow-exclude=<revision>::
22 + Deepen or shorten the history of a shallow repository to
23 + exclude commits reachable from a specified remote branch or tag.
24 + This option can be specified multiple times.
25 +
26 --unshallow::
27 If the source repository is complete, convert a shallow
28 repository to a complete one, removing all the limitations
Documentation/git-fetch-pack.txt
+5
@@ -91,6 +91,11 @@ be in a separate packet, and the list must end with a flush packet.
91 Deepen or shorten the history of a shallow'repository to
92 include all reachable commits after <date>.
93
94 +--shallow-exclude=<revision>::
95 + Deepen or shorten the history of a shallow repository to
96 + exclude commits reachable from a specified remote branch or tag.
97 + This option can be specified multiple times.
98 +
99 --no-progress::
100 Do not show the progress.
101
Documentation/gitremote-helpers.txt
+4
@@ -418,6 +418,10 @@ set by Git if the remote helper has the 'option' capability.
418 'option deepen-since <timestamp>::
419 Deepens the history of a shallow repository based on time.
420
421 +'option deepen-not <ref>::
422 + Deepens the history of a shallow repository excluding ref.
423 + Multiple options add up.
424 +
425 'option followtags' {'true'|'false'}::
426 If enabled the helper should automatically fetch annotated
427 tag objects if the object the tag points at was transferred
builtin/fetch-pack.c
+7
@@ -50,6 +50,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
50 struct child_process *conn;
51 struct fetch_pack_args args;
52 struct sha1_array shallow = SHA1_ARRAY_INIT;
53 + struct string_list deepen_not = STRING_LIST_INIT_DUP;
54
55 packet_trace_identity("fetch-pack");
56
@@ -108,6 +109,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
109 args.deepen_since = xstrdup(arg);
110 continue;
111 }
112 + if (skip_prefix(arg, "--shallow-exclude=", &arg)) {
113 + string_list_append(&deepen_not, arg);
114 + continue;
115 + }
116 if (!strcmp("--no-progress", arg)) {
117 args.no_progress = 1;
118 continue;
@@ -135,6 +140,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
140 }
141 usage(fetch_pack_usage);
142 }
143 + if (deepen_not.nr)
144 + args.deepen_not = &deepen_not;
145
146 if (i < argc)
147 dest = argv[i++];
builtin/fetch.c
+10 -3
@@ -41,6 +41,7 @@ static int max_children = 1;
41 static const char *depth;
42 static const char *deepen_since;
43 static const char *upload_pack;
44 +static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
45 static struct strbuf default_rla = STRBUF_INIT;
46 static struct transport *gtransport;
47 static struct transport *gsecondary;
@@ -118,6 +119,8 @@ static struct option builtin_fetch_options[] = {
119 N_("deepen history of shallow clone")),
120 OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
121 N_("deepen history of shallow repository based on time")),
122 + OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"),
123 + N_("deepen history of shallow clone by excluding rev")),
124 { OPTION_SET_INT, 0, "unshallow", &unshallow, NULL,
125 N_("convert to a complete repository"),
126 PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },
@@ -875,6 +878,9 @@ static struct transport *prepare_transport(struct remote *remote, int deepen)
878 set_option(transport, TRANS_OPT_DEPTH, depth);
879 if (deepen && deepen_since)
880 set_option(transport, TRANS_OPT_DEEPEN_SINCE, deepen_since);
881 + if (deepen && deepen_not.nr)
882 + set_option(transport, TRANS_OPT_DEEPEN_NOT,
883 + (const char *)&deepen_not);
884 if (update_shallow)
885 set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
886 return transport;
@@ -889,9 +895,10 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
895 * when remote helper is used (setting it to an empty string
896 * is not unsetting). We could extend the remote helper
897 * protocol for that, but for now, just force a new connection
892 - * without deepen-since.
898 + * without deepen-since. Similar story for deepen-not.
899 */
894 - cannot_reuse = transport->cannot_reuse || deepen_since;
900 + cannot_reuse = transport->cannot_reuse ||
901 + deepen_since || deepen_not.nr;
902 if (cannot_reuse) {
903 gsecondary = prepare_transport(transport->remote, 0);
904 transport = gsecondary;
@@ -1182,7 +1189,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
1189 /* no need to be strict, transport_set_option() will validate it again */
1190 if (depth && atoi(depth) < 1)
1191 die(_("depth %s is not a positive number"), depth);
1185 - if (depth || deepen_since)
1192 + if (depth || deepen_since || deepen_not.nr)
1193 deepen = 1;
1194
1195 if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
fetch-pack.c
+14 -1
@@ -22,6 +22,7 @@ static int unpack_limit = 100;
22 static int prefer_ofs_delta = 1;
23 static int no_done;
24 static int deepen_since_ok;
25 +static int deepen_not_ok;
26 static int fetch_fsck_objects = -1;
27 static int transfer_fsck_objects = -1;
28 static int agent_supported;
@@ -328,6 +329,7 @@ static int find_common(struct fetch_pack_args *args,
329 if (args->include_tag) strbuf_addstr(&c, " include-tag");
330 if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta");
331 if (deepen_since_ok) strbuf_addstr(&c, " deepen-since");
332 + if (deepen_not_ok) strbuf_addstr(&c, " deepen-not");
333 if (agent_supported) strbuf_addf(&c, " agent=%s",
334 git_user_agent_sanitized());
335 packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
@@ -351,6 +353,13 @@ static int find_common(struct fetch_pack_args *args,
353 unsigned long max_age = approxidate(args->deepen_since);
354 packet_buf_write(&req_buf, "deepen-since %lu", max_age);
355 }
356 + if (args->deepen_not) {
357 + int i;
358 + for (i = 0; i < args->deepen_not->nr; i++) {
359 + struct string_list_item *s = args->deepen_not->items + i;
360 + packet_buf_write(&req_buf, "deepen-not %s", s->string);
361 + }
362 + }
363 packet_buf_flush(&req_buf);
364 state_len = req_buf.len;
365
@@ -818,7 +827,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
827
828 if ((args->depth > 0 || is_repository_shallow()) && !server_supports("shallow"))
829 die(_("Server does not support shallow clients"));
821 - if (args->depth > 0 || args->deepen_since)
830 + if (args->depth > 0 || args->deepen_since || args->deepen_not)
831 args->deepen = 1;
832 if (server_supports("multi_ack_detailed")) {
833 print_verbose(args, _("Server supports multi_ack_detailed"));
@@ -870,6 +879,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
879 deepen_since_ok = 1;
880 else if (args->deepen_since)
881 die(_("Server does not support --shallow-since"));
882 + if (server_supports("deepen-not"))
883 + deepen_not_ok = 1;
884 + else if (args->deepen_not)
885 + die(_("Server does not support --shallow-exclude"));
886
887 if (everything_local(args, &ref, sought, nr_sought)) {
888 packet_flush(fd[1]);
fetch-pack.h
+1
@@ -11,6 +11,7 @@ struct fetch_pack_args {
11 int unpacklimit;
12 int depth;
13 const char *deepen_since;
14 + const struct string_list *deepen_not;
15 unsigned quiet:1;
16 unsigned keep_pack:1;
17 unsigned lock_pack:1;
remote-curl.c
+9
@@ -21,6 +21,7 @@ struct options {
21 int verbosity;
22 unsigned long depth;
23 char *deepen_since;
24 + struct string_list deepen_not;
25 unsigned progress : 1,
26 check_self_contained_and_connected : 1,
27 cloning : 1,
@@ -65,6 +66,10 @@ static int set_option(const char *name, const char *value)
66 options.deepen_since = xstrdup(value);
67 return 0;
68 }
69 + else if (!strcmp(name, "deepen-not")) {
70 + string_list_append(&options.deepen_not, value);
71 + return 0;
72 + }
73 else if (!strcmp(name, "followtags")) {
74 if (!strcmp(value, "true"))
75 options.followtags = 1;
@@ -753,6 +758,9 @@ static int fetch_git(struct discovery *heads,
758 argv_array_pushf(&args, "--depth=%lu", options.depth);
759 if (options.deepen_since)
760 argv_array_pushf(&args, "--shallow-since=%s", options.deepen_since);
761 + for (i = 0; i < options.deepen_not.nr; i++)
762 + argv_array_pushf(&args, "--shallow-exclude=%s",
763 + options.deepen_not.items[i].string);
764 argv_array_push(&args, url.buf);
765
766 for (i = 0; i < nr_heads; i++) {
@@ -973,6 +981,7 @@ int main(int argc, const char **argv)
981 options.verbosity = 1;
982 options.progress = !!isatty(2);
983 options.thin = 1;
984 + string_list_init(&options.deepen_not, 1);
985
986 remote = remote_get(argv[1]);
987
transport-helper.c
+24
@@ -282,6 +282,26 @@ static int strbuf_set_helper_option(struct helper_data *data,
282 return ret;
283 }
284
285 +static int string_list_set_helper_option(struct helper_data *data,
286 + const char *name,
287 + struct string_list *list)
288 +{
289 + struct strbuf buf = STRBUF_INIT;
290 + int i, ret = 0;
291 +
292 + for (i = 0; i < list->nr; i++) {
293 + strbuf_addf(&buf, "option %s ", name);
294 + quote_c_style(list->items[i].string, &buf, NULL, 0);
295 + strbuf_addch(&buf, '\n');
296 +
297 + if ((ret = strbuf_set_helper_option(data, &buf)))
298 + break;
299 + strbuf_reset(&buf);
300 + }
301 + strbuf_release(&buf);
302 + return ret;
303 +}
304 +
305 static int set_helper_option(struct transport *transport,
306 const char *name, const char *value)
307 {
@@ -294,6 +314,10 @@ static int set_helper_option(struct transport *transport,
314 if (!data->option)
315 return 1;
316
317 + if (!strcmp(name, "deepen-not"))
318 + return string_list_set_helper_option(data, name,
319 + (struct string_list *)value);
320 +
321 for (i = 0; i < ARRAY_SIZE(unsupported_options); i++) {
322 if (!strcmp(name, unsupported_options[i]))
323 return 1;
transport.c
+4
@@ -154,6 +154,9 @@ static int set_git_option(struct git_transport_options *opts,
154 } else if (!strcmp(name, TRANS_OPT_DEEPEN_SINCE)) {
155 opts->deepen_since = value;
156 return 0;
157 + } else if (!strcmp(name, TRANS_OPT_DEEPEN_NOT)) {
158 + opts->deepen_not = (const struct string_list *)value;
159 + return 0;
160 }
161 return 1;
162 }
@@ -209,6 +212,7 @@ static int fetch_refs_via_pack(struct transport *transport,
212 args.no_progress = !transport->progress;
213 args.depth = data->options.depth;
214 args.deepen_since = data->options.deepen_since;
215 + args.deepen_not = data->options.deepen_not;
216 args.check_self_contained_and_connected =
217 data->options.check_self_contained_and_connected;
218 args.cloning = transport->cloning;
transport.h
+6
@@ -5,6 +5,8 @@
5 #include "run-command.h"
6 #include "remote.h"
7
8 +struct string_list;
9 +
10 struct git_transport_options {
11 unsigned thin : 1;
12 unsigned keep : 1;
@@ -14,6 +16,7 @@ struct git_transport_options {
16 unsigned update_shallow : 1;
17 int depth;
18 const char *deepen_since;
19 + const struct string_list *deepen_not;
20 const char *uploadpack;
21 const char *receivepack;
22 struct push_cas_option *cas;
@@ -175,6 +178,9 @@ int transport_restrict_protocols(void);
178 /* Limit the depth of the fetch based on time if not null */
179 #define TRANS_OPT_DEEPEN_SINCE "deepen-since"
180
181 +/* Limit the depth of the fetch based on revs if not null */
182 +#define TRANS_OPT_DEEPEN_NOT "deepen-not"
183 +
184 /* Aggressively fetch annotated tags if possible */
185 #define TRANS_OPT_FOLLOWTAGS "followtags"
186