Code

allow cloning a repository "shallowly"
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Mon, 30 Oct 2006 19:09:29 +0000 (20:09 +0100)
committerJunio C Hamano <junkio@cox.net>
Fri, 24 Nov 2006 23:42:49 +0000 (15:42 -0800)
By specifying a depth, you can now clone a repository such that
all fetched ancestor-chains' length is at most "depth". For example,
if the upstream repository has only 2 branches ("A" and "B"), which
are linear, and you specify depth 3, you will get A, A~1, A~2, A~3,
B, B~1, B~2, and B~3. The ends are automatically made shallow
commits.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
fetch-pack.c
git-clone.sh
upload-pack.c

index bc5e725055198e28a9174f249902e5be095851de..f335bd42b7b61429a307b0d6930987f1058c8034 100644 (file)
@@ -11,8 +11,9 @@ static int keep_pack;
 static int quiet;
 static int verbose;
 static int fetch_all;
+static int depth;
 static const char fetch_pack_usage[] =
-"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory <refs>...";
+"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [--depth=<n>] [host:]directory <refs>...";
 static const char *exec = "git-upload-pack";
 
 #define COMPLETE       (1U << 0)
@@ -182,10 +183,29 @@ static int find_common(int fd[2], unsigned char *result_sha1,
        }
        if (is_repository_shallow())
                write_shallow_commits(fd[1], 1);
+       if (depth > 0)
+               packet_write(fd[1], "deepen %d", depth);
        packet_flush(fd[1]);
        if (!fetching)
                return 1;
 
+       if (depth >  0) {
+               char line[1024];
+               unsigned char sha1[20];
+               int len;
+
+               while ((len = packet_read_line(fd[0], line, sizeof(line)))) {
+                       if (!strncmp("shallow ", line, 8)) {
+                               if (get_sha1_hex(line + 8, sha1))
+                                       die("invalid shallow line: %s", line);
+                               /* no need making it shallow if we have it already */
+                               if (lookup_object(sha1))
+                                       continue;
+                               register_shallow(sha1);
+                       }
+               }
+       }
+
        flushes = 0;
        retval = -1;
        while ((sha1 = get_rev())) {
@@ -576,6 +596,8 @@ int main(int argc, char **argv)
        char *dest = NULL, **heads;
        int fd[2];
        pid_t pid;
+       struct stat st;
+       struct lock_file lock;
 
        setup_git_directory();
 
@@ -609,6 +631,12 @@ int main(int argc, char **argv)
                                verbose = 1;
                                continue;
                        }
+                       if (!strncmp("--depth=", arg, 8)) {
+                               depth = strtol(arg + 8, NULL, 0);
+                               if (stat(git_path("shallow"), &st))
+                                       st.st_mtime = 0;
+                               continue;
+                       }
                        usage(fetch_pack_usage);
                }
                dest = arg;
@@ -618,6 +646,8 @@ int main(int argc, char **argv)
        }
        if (!dest)
                usage(fetch_pack_usage);
+       if (is_repository_shallow() && depth > 0)
+               die("Deepening of a shallow repository not yet supported!");
        pid = git_connect(fd, dest, exec);
        if (pid < 0)
                return 1;
@@ -639,5 +669,34 @@ int main(int argc, char **argv)
                        }
        }
 
+       if (!ret && depth > 0) {
+               struct cache_time mtime;
+               char *shallow = git_path("shallow");
+               int fd;
+
+               mtime.sec = st.st_mtime;
+#ifdef USE_NSEC
+               mtime.usec = st.st_mtim.usec;
+#endif
+               if (stat(shallow, &st)) {
+                       if (mtime.sec)
+                               die("shallow file was removed during fetch");
+               } else if (st.st_mtime != mtime.sec
+#ifdef USE_NSEC
+                               || st.st_mtim.usec != mtime.usec
+#endif
+                         )
+                       die("shallow file was changed during fetch");
+
+               fd = hold_lock_file_for_update(&lock, shallow, 1);
+               if (!write_shallow_commits(fd, 0)) {
+                       unlink(lock.filename);
+                       rollback_lock_file(&lock);
+               } else {
+                       close(fd);
+                       commit_lock_file(&lock);
+               }
+       }
+
        return !!ret;
 }
index 9ed413554455a7869c6c2223319eb58b4f3e6463..8c0a93ebd15399fad6f58fcf315709cb94fd6128 100755 (executable)
@@ -14,7 +14,7 @@ die() {
 }
 
 usage() {
-       die "Usage: $0 [--template=<template_directory>] [--use-immingled-remote] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [-n] <repo> [<dir>]"
+       die "Usage: $0 [--template=<template_directory>] [--use-immingled-remote] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] <repo> [<dir>]"
 }
 
 get_repo_base() {
@@ -116,6 +116,7 @@ reference=
 origin=
 origin_override=
 use_separate_remote=t
+depth=
 while
        case "$#,$1" in
        0,*) break ;;
@@ -161,6 +162,10 @@ while
        *,-u|*,--upload-pack)
                shift
                upload_pack="--exec=$1" ;;
+       1,--depth) usage;;
+       *,--depth)
+               shift
+               depth="--depth=$1";;
        *,-*) usage ;;
        *) break ;;
        esac
@@ -265,6 +270,10 @@ yes,yes)
 *)
        case "$repo" in
        rsync://*)
+               case "$depth" in
+               "") ;;
+               *) die "shallow over rsync not supported" ;;
+               esac
                rsync $quiet -av --ignore-existing  \
                        --exclude info "$repo/objects/" "$GIT_DIR/objects/" ||
                exit
@@ -293,6 +302,10 @@ yes,yes)
                git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
                ;;
        https://*|http://*|ftp://*)
+               case "$depth" in
+               "") ;;
+               *) die "shallow over http or ftp not supported" ;;
+               esac
                if test -z "@@NO_CURL@@"
                then
                        clone_dumb_http "$repo" "$D"
@@ -302,8 +315,8 @@ yes,yes)
                ;;
        *)
                case "$upload_pack" in
-               '') git-fetch-pack --all -k $quiet "$repo" ;;
-               *) git-fetch-pack --all -k $quiet "$upload_pack" "$repo" ;;
+               '') git-fetch-pack --all -k $quiet $depth "$repo" ;;
+               *) git-fetch-pack --all -k $quiet "$upload_pack" $depth "$repo" ;;
                esac >"$GIT_DIR/CLONE_HEAD" ||
                        die "fetch-pack from '$repo' failed."
                ;;
index 8dd6121dab89963aa771e6e67b8dee71fdbc009f..ebe1e5ae4d12eb32dbd14eb40ee1c1e5d21bb100 100644 (file)
@@ -488,7 +488,7 @@ static void receive_needs(void)
 {
        struct object_array shallows = {0, 0, NULL};
        static char line[1000];
-       int len;
+       int len, depth = 0;
 
        for (;;) {
                struct object *o;
@@ -509,6 +509,13 @@ static void receive_needs(void)
                        add_object_array(object, NULL, &shallows);
                        continue;
                }
+               if (!strncmp("deepen ", line, 7)) {
+                       char *end;
+                       depth = strtol(line + 7, &end, 0);
+                       if (end == line + 7 || depth <= 0)
+                               die("Invalid deepen: %s", line);
+                       continue;
+               }
                if (strncmp("want ", line, 5) ||
                    get_sha1_hex(line+5, sha1_buf))
                        die("git-upload-pack: protocol error, "
@@ -540,6 +547,18 @@ static void receive_needs(void)
                        add_object_array(o, NULL, &want_obj);
                }
        }
+       if (depth > 0) {
+               struct commit_list *result, *backup;
+               if (shallows.nr > 0)
+                       die("Deepening a shallow repository not yet supported");
+               backup = result = get_shallow_commits(&want_obj, depth);
+               while (result) {
+                       packet_write(1, "shallow %s",
+                                       sha1_to_hex(result->item->object.sha1));
+                       result = result->next;
+               }
+               free_commit_list(backup);
+       }
        if (shallows.nr > 0) {
                int i;
                for (i = 0; i < shallows.nr; i++)