[PATCH 4/5] allow deepening of a shallow repository

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Now, by saying "git fetch -depth <n> <repo>" you can deepen
a shallow repository.

Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx>
---
 commit.c      |   13 +++++++++++++
 commit.h      |    3 ++-
 fetch-pack.c  |   22 ++++++++++++++++------
 git-fetch.sh  |   12 +++++++++++-
 shallow.c     |    8 ++++++--
 upload-pack.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 6 files changed, 94 insertions(+), 21 deletions(-)

diff --git a/commit.c b/commit.c
index bffa278..d5103cd 100644
--- a/commit.c
+++ b/commit.c
@@ -255,6 +255,19 @@ int write_shallow_commits(int fd, int us
 	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;
diff --git a/commit.h b/commit.h
index c559510..e9e158f 100644
--- a/commit.h
+++ b/commit.h
@@ -108,9 +108,10 @@ int read_graft_file(const char *graft_fi
 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 */
diff --git a/fetch-pack.c b/fetch-pack.c
index 9619d6e..a82a5ba 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -199,7 +199,17 @@ static int find_common(int fd[2], unsign
 				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);
 		}
 	}
 
@@ -388,9 +398,11 @@ static int everything_local(struct ref *
 		}
 	}
 
-	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.
@@ -550,8 +562,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;
diff --git a/git-fetch.sh b/git-fetch.sh
index 539dff6..2a4b7a0 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -21,6 +21,7 @@ update_head_ok=
 exec=
 upload_pack=
 keep=--thin
+depth=
 while case "$#" in 0) break ;; esac
 do
 	case "$1" in
@@ -56,6 +57,13 @@ do
 	--reflog-action=*)
 		rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
 		;;
+	--depth=*)
+		depth="--depth=`expr "z$1" : 'z-[^=]*=\(.*\)'`"
+		;;
+	--depth)
+		shift
+		depth="--depth=$1"
+		;;
 	-*)
 		usage
 		;;
@@ -296,6 +304,7 @@ fetch_main () {
       # There are transports that can fetch only one head at a time...
       case "$remote" in
       http://* | https://* | ftp://*)
+	  test -n "$depth" && die "shallow clone with http not supported"
 	  proto=`expr "$remote" : '\([^:]*\):'`
 	  if [ -n "$GIT_SSL_NO_VERIFY" ]; then
 	      curl_extra_args="-k"
@@ -324,6 +333,7 @@ fetch_main () {
 	  git-http-fetch -v -a "$head" "$remote/" || exit
 	  ;;
       rsync://*)
+	  test -n "$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)
@@ -370,7 +380,7 @@ fetch_main () {
     ( : subshell because we muck with IFS
       IFS=" 	$LF"
       (
-	  git-fetch-pack $exec $keep "$remote" $rref || echo failed "$remote"
+	  git-fetch-pack $exec $keep $depth "$remote" $rref || echo failed "$remote"
       ) |
       while read sha1 remote_name
       do
diff --git a/shallow.c b/shallow.c
index 3cf2127..58a7b20 100644
--- 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(
 			}
 		}
 		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(
 					commit = p->item;
 					cur_depth = *(int *)commit->util;
 				}
-			} else
+			} else {
 				commit_list_insert(p->item, &result);
+				p->item->object.flags |= shallow_flag;
+			}
 		}
 	}
 
diff --git a/upload-pack.c b/upload-pack.c
index ebe1e5a..162dd34 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -134,6 +134,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++) {
@@ -490,6 +491,9 @@ static void receive_needs(void)
 	static char line[1000];
 	int len, depth = 0;
 
+#define SHALLOW (1u<<8)
+#define NOT_SHALLOW (1u<<9)
+#define CLIENT_SHALLOW (1u<<10)
 	for (;;) {
 		struct object *o;
 		unsigned char sha1_buf[20];
@@ -501,16 +505,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 +554,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)
-- 
1.4.3.3.gca42

-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]