From 016e6ccbe03438454777e43dd73d67844296a3fd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 30 Oct 2006 20:09:29 +0100 Subject: [PATCH] allow cloning a repository "shallowly" 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 Signed-off-by: Junio C Hamano --- fetch-pack.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++- git-clone.sh | 19 +++++++++++++--- upload-pack.c | 21 +++++++++++++++++- 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/fetch-pack.c b/fetch-pack.c index bc5e725055..f335bd42b7 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -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 ..."; +"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [--depth=] [host:]directory ..."; 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; } diff --git a/git-clone.sh b/git-clone.sh index 9ed4135544..8c0a93ebd1 100755 --- a/git-clone.sh +++ b/git-clone.sh @@ -14,7 +14,7 @@ die() { } usage() { - die "Usage: $0 [--template=] [--use-immingled-remote] [--reference ] [--bare] [-l [-s]] [-q] [-u ] [--origin ] [-n] []" + die "Usage: $0 [--template=] [--use-immingled-remote] [--reference ] [--bare] [-l [-s]] [-q] [-u ] [--origin ] [--depth ] [-n] []" } 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." ;; diff --git a/upload-pack.c b/upload-pack.c index 8dd6121dab..ebe1e5ae4d 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -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++)