smart-http: support shallow fetch/clone

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 Dec 5, 2013 at 20:02 UTC 16094885ca94f72abc28a915f9aa4021e203a16d
6 files changed +81 -9
Documentation/gitremote-helpers.txt
+7
@@ -437,6 +437,13 @@ set by Git if the remote helper has the 'option' capability.
437 'option check-connectivity' \{'true'|'false'\}::
438 Request the helper to check connectivity of a clone.
439
440 +'option cloning \{'true'|'false'\}::
441 + Notify the helper this is a clone request (i.e. the current
442 + repository is guaranteed empty).
443 +
444 +'option update-shallow \{'true'|'false'\}::
445 + Allow to extend .git/shallow if the new refs require it.
446 +
447 SEE ALSO
448 --------
449 linkgit:git-remote[1]
builtin/fetch-pack.c
+13 -3
@@ -3,6 +3,7 @@
3 #include "fetch-pack.h"
4 #include "remote.h"
5 #include "connect.h"
6 +#include "sha1-array.h"
7
8 static const char fetch_pack_usage[] =
9 "git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
@@ -46,6 +47,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
47 char **pack_lockfile_ptr = NULL;
48 struct child_process *conn;
49 struct fetch_pack_args args;
50 + struct sha1_array shallow = SHA1_ARRAY_INIT;
51
52 packet_trace_identity("fetch-pack");
53
@@ -113,6 +115,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
115 args.check_self_contained_and_connected = 1;
116 continue;
117 }
118 + if (!strcmp("--cloning", arg)) {
119 + args.cloning = 1;
120 + continue;
121 + }
122 + if (!strcmp("--update-shallow", arg)) {
123 + args.update_shallow = 1;
124 + continue;
125 + }
126 usage(fetch_pack_usage);
127 }
128
@@ -157,10 +167,10 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
167 args.verbose ? CONNECT_VERBOSE : 0);
168 }
169
160 - get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, NULL);
170 + get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow);
171
162 - ref = fetch_pack(&args, fd, conn, ref, dest,
163 - sought, nr_sought, NULL, pack_lockfile_ptr);
172 + ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
173 + &shallow, pack_lockfile_ptr);
174 if (pack_lockfile) {
175 printf("lock %s\n", pack_lockfile);
176 fflush(stdout);
remote-curl.c
+28 -4
@@ -10,6 +10,7 @@
10 #include "sideband.h"
11 #include "argv-array.h"
12 #include "credential.h"
13 +#include "sha1-array.h"
14
15 static struct remote *remote;
16 /* always ends with a trailing slash */
@@ -20,6 +21,8 @@ struct options {
21 unsigned long depth;
22 unsigned progress : 1,
23 check_self_contained_and_connected : 1,
24 + cloning : 1,
25 + update_shallow : 1,
26 followtags : 1,
27 dry_run : 1,
28 thin : 1;
@@ -87,8 +90,23 @@ static int set_option(const char *name, const char *value)
90 string_list_append(&cas_options, val.buf);
91 strbuf_release(&val);
92 return 0;
90 - }
91 - else {
93 + } else if (!strcmp(name, "cloning")) {
94 + if (!strcmp(value, "true"))
95 + options.cloning = 1;
96 + else if (!strcmp(value, "false"))
97 + options.cloning = 0;
98 + else
99 + return -1;
100 + return 0;
101 + } else if (!strcmp(name, "update-shallow")) {
102 + if (!strcmp(value, "true"))
103 + options.update_shallow = 1;
104 + else if (!strcmp(value, "false"))
105 + options.update_shallow = 0;
106 + else
107 + return -1;
108 + return 0;
109 + } else {
110 return 1 /* unsupported */;
111 }
112 }
@@ -99,6 +117,7 @@ struct discovery {
117 char *buf;
118 size_t len;
119 struct ref *refs;
120 + struct sha1_array shallow;
121 unsigned proto_git : 1;
122 };
123 static struct discovery *last_discovery;
@@ -107,7 +126,7 @@ static struct ref *parse_git_refs(struct discovery *heads, int for_push)
126 {
127 struct ref *list = NULL;
128 get_remote_heads(-1, heads->buf, heads->len, &list,
110 - for_push ? REF_NORMAL : 0, NULL, NULL);
129 + for_push ? REF_NORMAL : 0, NULL, &heads->shallow);
130 return list;
131 }
132
@@ -168,6 +187,7 @@ static void free_discovery(struct discovery *d)
187 if (d) {
188 if (d == last_discovery)
189 last_discovery = NULL;
190 + free(d->shallow.sha1);
191 free(d->buf_alloc);
192 free_refs(d->refs);
193 free(d);
@@ -688,7 +708,7 @@ static int fetch_git(struct discovery *heads,
708 struct strbuf preamble = STRBUF_INIT;
709 char *depth_arg = NULL;
710 int argc = 0, i, err;
691 - const char *argv[16];
711 + const char *argv[17];
712
713 argv[argc++] = "fetch-pack";
714 argv[argc++] = "--stateless-rpc";
@@ -704,6 +724,10 @@ static int fetch_git(struct discovery *heads,
724 }
725 if (options.check_self_contained_and_connected)
726 argv[argc++] = "--check-self-contained-and-connected";
727 + if (options.cloning)
728 + argv[argc++] = "--cloning";
729 + if (options.update_shallow)
730 + argv[argc++] = "--update-shallow";
731 if (!options.progress)
732 argv[argc++] = "--no-progress";
733 if (options.depth) {
t/t5537-fetch-shallow.sh
+27
@@ -173,4 +173,31 @@ EOF
173 )
174 '
175
176 +if test -n "$NO_CURL" -o -z "$GIT_TEST_HTTPD"; then
177 + say 'skipping remaining tests, git built without http support'
178 + test_done
179 +fi
180 +
181 +LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5536'}
182 +. "$TEST_DIRECTORY"/lib-httpd.sh
183 +start_httpd
184 +
185 +test_expect_success 'clone http repository' '
186 + git clone --bare --no-local shallow "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
187 + git clone $HTTPD_URL/smart/repo.git clone &&
188 + (
189 + cd clone &&
190 + git fsck &&
191 + git log --format=%s origin/master >actual &&
192 + cat <<EOF >expect &&
193 +6
194 +5
195 +4
196 +3
197 +EOF
198 + test_cmp expect actual
199 + )
200 +'
201 +
202 +stop_httpd
203 test_done
transport-helper.c
+6
@@ -360,6 +360,12 @@ static int fetch_with_fetch(struct transport *transport,
360 data->transport_options.check_self_contained_and_connected)
361 set_helper_option(transport, "check-connectivity", "true");
362
363 + if (transport->cloning)
364 + set_helper_option(transport, "cloning", "true");
365 +
366 + if (data->transport_options.update_shallow)
367 + set_helper_option(transport, "update-shallow", "true");
368 +
369 for (i = 0; i < nr_heads; i++) {
370 const struct ref *posn = to_fetch[i];
371 if (posn->status & REF_STATUS_UPTODATE)
upload-pack.c
-2
@@ -836,8 +836,6 @@ int main(int argc, char **argv)
836
837 if (!enter_repo(dir, strict))
838 die("'%s' does not appear to be a git repository", dir);
839 - if (is_repository_shallow() && stateless_rpc)
840 - die("attempt to push into a shallow repository");
839
840 git_config(upload_pack_config, NULL);
841 upload_pack();