allow deepening of a shallow repository
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Mon, 30 Oct 2006 19:09:53 +0000 (20:09 +0100)
committerJunio C Hamano <junkio@cox.net>
Fri, 24 Nov 2006 23:42:49 +0000 (15:42 -0800)
Now, by saying "git fetch -depth <n> <repo>" you can deepen
a shallow repository.

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

index bffa278868f13b8ba3ba72d45c3dee9eb813fca8..d5103cd3c6358bea2acc8040dfb6eb3afd273420 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -255,6 +255,19 @@ int write_shallow_commits(int fd, int use_pack_protocol)
        return count;
 }
 
+int unregister_shallow(const unsigned char *sha1)
+{
+       int pos = commit_graft_pos(sha1);
+       if (pos < 0)
+               return -1;
+       if (pos + 1 < commit_graft_nr)
+               memcpy(commit_graft + pos, commit_graft + pos + 1,
+                               sizeof(struct commit_graft *)
+                               * (commit_graft_nr - pos - 1));
+       commit_graft_nr--;
+       return 0;
+}
+
 int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
 {
        char *tail = buffer;
index c559510b46d7aa84187b616be1ed7654a0447ec8..e9e158f4e1c670635dda02766f67da3821374669 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -108,9 +108,10 @@ int read_graft_file(const char *graft_file);
 extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
 
 extern int register_shallow(const unsigned char *sha1);
+extern int unregister_shallow(const unsigned char *sha1);
 extern int write_shallow_commits(int fd, int use_pack_protocol);
 extern int is_repository_shallow();
 extern struct commit_list *get_shallow_commits(struct object_array *heads,
-               int depth);
+               int depth, int shallow_flag, int not_shallow_flag);
 
 #endif /* COMMIT_H */
index f335bd42b7b61429a307b0d6930987f1058c8034..c3064b94ad1d9e682014a83eb46349af5733e295 100644 (file)
@@ -202,7 +202,17 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                                if (lookup_object(sha1))
                                        continue;
                                register_shallow(sha1);
-                       }
+                       }  else if (!strncmp("unshallow ", line, 10)) {
+                               if (get_sha1_hex(line + 10, sha1))
+                                       die("invalid unshallow line: %s", line);
+                               if (!lookup_object(sha1))
+                                       die("object not found: %s", line);
+                               /* make sure that it is parsed as shallow */
+                               parse_object(sha1);
+                               if (unregister_shallow(sha1))
+                                       die("no shallow found: %s", line);
+                       } else
+                               die("expected shallow/unshallow, got %s", line);
                }
        }
 
@@ -391,9 +401,11 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
                }
        }
 
-       for_each_ref(mark_complete, NULL);
-       if (cutoff)
-               mark_recent_complete_commits(cutoff);
+       if (!depth) {
+               for_each_ref(mark_complete, NULL);
+               if (cutoff)
+                       mark_recent_complete_commits(cutoff);
+       }
 
        /*
         * Mark all complete remote refs as common refs.
@@ -646,8 +658,6 @@ 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;
index eb32476bbdc98cc9a34d4026575e4d1a608289be..0b1e6d1071350af34e95a402d7ef53f00d03d8a4 100755 (executable)
@@ -21,6 +21,7 @@ update_head_ok=
 exec=
 upload_pack=
 keep=
+shallow_depth=
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
@@ -56,6 +57,13 @@ do
        --reflog-action=*)
                rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
                ;;
+       --depth=*)
+               shallow_depth="--depth=`expr "z$1" : 'z-[^=]*=\(.*\)'`"
+               ;;
+       --depth)
+               shift
+               shallow_depth="--depth=$1"
+               ;;
        -*)
                usage
                ;;
@@ -296,6 +304,8 @@ fetch_main () {
       # There are transports that can fetch only one head at a time...
       case "$remote" in
       http://* | https://* | ftp://*)
+         test -n "$shallow_depth" &&
+               die "shallow clone with http not supported"
          proto=`expr "$remote" : '\([^:]*\):'`
          if [ -n "$GIT_SSL_NO_VERIFY" ]; then
              curl_extra_args="-k"
@@ -324,6 +334,8 @@ fetch_main () {
          git-http-fetch -v -a "$head" "$remote/" || exit
          ;;
       rsync://*)
+         test -n "$shallow_depth" &&
+               die "shallow clone with rsync not supported"
          TMP_HEAD="$GIT_DIR/TMP_HEAD"
          rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
          head=$(git-rev-parse --verify TMP_HEAD)
@@ -371,7 +383,7 @@ fetch_main () {
       pack_lockfile=
       IFS="    $LF"
       (
-         git-fetch-pack --thin $exec $keep "$remote" $rref || echo failed "$remote"
+         git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref || echo failed "$remote"
       ) |
       while read sha1 remote_name
       do
index 3cf2127134787586ac30e16764f6b639fa315a59..58a7b20d793cbc71ab924d5f5aedf28cd01ca32a 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -41,7 +41,8 @@ int is_repository_shallow()
        return is_shallow;
 }
 
-struct commit_list *get_shallow_commits(struct object_array *heads, int depth)
+struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
+               int shallow_flag, int not_shallow_flag)
 {
        int i = 0, cur_depth = 0;
        struct commit_list *result = NULL;
@@ -67,6 +68,7 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth)
                        }
                }
                parse_commit(commit);
+               commit->object.flags |= not_shallow_flag;
                cur_depth++;
                for (p = commit->parents, commit = NULL; p; p = p->next) {
                        if (!p->item->util) {
@@ -87,8 +89,10 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth)
                                        commit = p->item;
                                        cur_depth = *(int *)commit->util;
                                }
-                       } else
+                       } else {
                                commit_list_insert(p->item, &result);
+                               p->item->object.flags |= shallow_flag;
+                       }
                }
        }
 
index ebe1e5ae4d12eb32dbd14eb40ee1c1e5d21bb100..4a9d6720a5a0e9977bd9346e649666ead4e18fe4 100644 (file)
@@ -22,6 +22,10 @@ static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=n
 #define COMMON_KNOWN   (1u << 14)
 #define REACHABLE      (1u << 15)
 
+#define SHALLOW                (1u << 16)
+#define NOT_SHALLOW    (1u << 17)
+#define CLIENT_SHALLOW (1u << 18)
+
 static unsigned long oldest_have;
 
 static int multi_ack, nr_our_refs;
@@ -134,6 +138,7 @@ static void create_pack_file(void)
                } else {
                        for (i = 0; i < want_obj.nr; i++) {
                                struct object *o = want_obj.objects[i].item;
+                               o->flags &= ~UNINTERESTING;
                                add_pending_object(&revs, o, NULL);
                        }
                        for (i = 0; i < have_obj.nr; i++) {
@@ -501,16 +506,19 @@ static void receive_needs(void)
                if (!strncmp("shallow ", line, 8)) {
                        unsigned char sha1[20];
                        struct object *object;
+                       use_thin_pack = 0;
                        if (get_sha1(line + 8, sha1))
                                die("invalid shallow line: %s", line);
                        object = parse_object(sha1);
                        if (!object)
                                die("did not find object for %s", line);
+                       object->flags |= CLIENT_SHALLOW;
                        add_object_array(object, NULL, &shallows);
                        continue;
                }
                if (!strncmp("deepen ", line, 7)) {
                        char *end;
+                       use_thin_pack = 0;
                        depth = strtol(line + 7, &end, 0);
                        if (end == line + 7 || depth <= 0)
                                die("Invalid deepen: %s", line);
@@ -547,23 +555,51 @@ static void receive_needs(void)
                        add_object_array(o, NULL, &want_obj);
                }
        }
+       if (depth == 0 && shallows.nr == 0)
+               return;
        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);
+               int i;
+               backup = result = get_shallow_commits(&want_obj, depth,
+                       SHALLOW, NOT_SHALLOW);
                while (result) {
-                       packet_write(1, "shallow %s",
-                                       sha1_to_hex(result->item->object.sha1));
+                       struct object *object = &result->item->object;
+                       if (!(object->flags & CLIENT_SHALLOW)) {
+                               packet_write(1, "shallow %s",
+                                               sha1_to_hex(object->sha1));
+                               register_shallow(object->sha1);
+                       }
                        result = result->next;
                }
                free_commit_list(backup);
-       }
-       if (shallows.nr > 0) {
-               int i;
-               for (i = 0; i < shallows.nr; i++)
-                       register_shallow(shallows.objects[i].item->sha1);
-       }
+               for (i = 0; i < shallows.nr; i++) {
+                       struct object *object = shallows.objects[i].item;
+                       if (object->flags & NOT_SHALLOW) {
+                               struct commit_list *parents;
+                               packet_write(1, "unshallow %s",
+                                       sha1_to_hex(object->sha1));
+                               object->flags &= ~CLIENT_SHALLOW;
+                               /* make sure the real parents are parsed */
+                               unregister_shallow(object->sha1);
+                               parse_commit((struct commit *)object);
+                               parents = ((struct commit *)object)->parents;
+                               while (parents) {
+                                       add_object_array(&parents->item->object,
+                                                       NULL, &want_obj);
+                                       parents = parents->next;
+                               }
+                       }
+                       /* make sure commit traversal conforms to client */
+                       register_shallow(object->sha1);
+               }
+               packet_flush(1);
+       } else
+               if (shallows.nr > 0) {
+                       int i;
+                       for (i = 0; i < shallows.nr; i++)
+                               register_shallow(shallows.objects[i].item->sha1);
+               }
+       free(shallows.objects);
 }
 
 static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)