'option check-connectivity' \{'true'|'false'\}::
        Request the helper to check connectivity of a clone.
 
+'option cloning \{'true'|'false'\}::
+       Notify the helper this is a clone request (i.e. the current
+       repository is guaranteed empty).
+
+'option update-shallow \{'true'|'false'\}::
+       Allow to extend .git/shallow if the new refs require it.
+
 SEE ALSO
 --------
 linkgit:git-remote[1]
 
 #include "fetch-pack.h"
 #include "remote.h"
 #include "connect.h"
+#include "sha1-array.h"
 
 static const char fetch_pack_usage[] =
 "git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
        char **pack_lockfile_ptr = NULL;
        struct child_process *conn;
        struct fetch_pack_args args;
+       struct sha1_array shallow = SHA1_ARRAY_INIT;
 
        packet_trace_identity("fetch-pack");
 
                        args.check_self_contained_and_connected = 1;
                        continue;
                }
+               if (!strcmp("--cloning", arg)) {
+                       args.cloning = 1;
+                       continue;
+               }
+               if (!strcmp("--update-shallow", arg)) {
+                       args.update_shallow = 1;
+                       continue;
+               }
                usage(fetch_pack_usage);
        }
 
                                   args.verbose ? CONNECT_VERBOSE : 0);
        }
 
-       get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, NULL);
+       get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, &shallow);
 
-       ref = fetch_pack(&args, fd, conn, ref, dest,
-                        sought, nr_sought, NULL, pack_lockfile_ptr);
+       ref = fetch_pack(&args, fd, conn, ref, dest, sought, nr_sought,
+                        &shallow, pack_lockfile_ptr);
        if (pack_lockfile) {
                printf("lock %s\n", pack_lockfile);
                fflush(stdout);
 
 #include "sideband.h"
 #include "argv-array.h"
 #include "credential.h"
+#include "sha1-array.h"
 
 static struct remote *remote;
 /* always ends with a trailing slash */
        unsigned long depth;
        unsigned progress : 1,
                check_self_contained_and_connected : 1,
+               cloning : 1,
+               update_shallow : 1,
                followtags : 1,
                dry_run : 1,
                thin : 1;
                string_list_append(&cas_options, val.buf);
                strbuf_release(&val);
                return 0;
-       }
-       else {
+       } else if (!strcmp(name, "cloning")) {
+               if (!strcmp(value, "true"))
+                       options.cloning = 1;
+               else if (!strcmp(value, "false"))
+                       options.cloning = 0;
+               else
+                       return -1;
+               return 0;
+       } else if (!strcmp(name, "update-shallow")) {
+               if (!strcmp(value, "true"))
+                       options.update_shallow = 1;
+               else if (!strcmp(value, "false"))
+                       options.update_shallow = 0;
+               else
+                       return -1;
+               return 0;
+       } else {
                return 1 /* unsupported */;
        }
 }
        char *buf;
        size_t len;
        struct ref *refs;
+       struct sha1_array shallow;
        unsigned proto_git : 1;
 };
 static struct discovery *last_discovery;
 {
        struct ref *list = NULL;
        get_remote_heads(-1, heads->buf, heads->len, &list,
-                        for_push ? REF_NORMAL : 0, NULL, NULL);
+                        for_push ? REF_NORMAL : 0, NULL, &heads->shallow);
        return list;
 }
 
        if (d) {
                if (d == last_discovery)
                        last_discovery = NULL;
+               free(d->shallow.sha1);
                free(d->buf_alloc);
                free_refs(d->refs);
                free(d);
        struct strbuf preamble = STRBUF_INIT;
        char *depth_arg = NULL;
        int argc = 0, i, err;
-       const char *argv[16];
+       const char *argv[17];
 
        argv[argc++] = "fetch-pack";
        argv[argc++] = "--stateless-rpc";
        }
        if (options.check_self_contained_and_connected)
                argv[argc++] = "--check-self-contained-and-connected";
+       if (options.cloning)
+               argv[argc++] = "--cloning";
+       if (options.update_shallow)
+               argv[argc++] = "--update-shallow";
        if (!options.progress)
                argv[argc++] = "--no-progress";
        if (options.depth) {
 
        )
 '
 
+if test -n "$NO_CURL" -o -z "$GIT_TEST_HTTPD"; then
+       say 'skipping remaining tests, git built without http support'
+       test_done
+fi
+
+LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5536'}
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+test_expect_success 'clone http repository' '
+       git clone --bare --no-local shallow "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+       git clone $HTTPD_URL/smart/repo.git clone &&
+       (
+       cd clone &&
+       git fsck &&
+       git log --format=%s origin/master >actual &&
+       cat <<EOF >expect &&
+6
+5
+4
+3
+EOF
+       test_cmp expect actual
+       )
+'
+
+stop_httpd
 test_done
 
            data->transport_options.check_self_contained_and_connected)
                set_helper_option(transport, "check-connectivity", "true");
 
+       if (transport->cloning)
+               set_helper_option(transport, "cloning", "true");
+
+       if (data->transport_options.update_shallow)
+               set_helper_option(transport, "update-shallow", "true");
+
        for (i = 0; i < nr_heads; i++) {
                const struct ref *posn = to_fetch[i];
                if (posn->status & REF_STATUS_UPTODATE)
 
 
        if (!enter_repo(dir, strict))
                die("'%s' does not appear to be a git repository", dir);
-       if (is_repository_shallow() && stateless_rpc)
-               die("attempt to push into a shallow repository");
 
        git_config(upload_pack_config, NULL);
        upload_pack();