From 4dcb167fc3536db0e78c50f239cd3a19afd383fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 11 Jan 2013 16:05:46 +0700 Subject: fetch: add --unshallow for turning shallow repo into complete one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user can do --depth=2147483647 (*) for restoring complete repo now. But it's hard to remember. Any other numbers larger than the longest commit chain in the repository would also do, but some guessing may be involved. Make easy-to-remember --unshallow an alias for --depth=2147483647. Make upload-pack recognize this special number as infinite depth. The effect is essentially the same as before, except that upload-pack is more efficient because it does not have to traverse to the bottom anymore. The chance of a user actually wanting exactly 2147483647 commits depth, not infinite, on a repository with a history that long, is probably too small to consider. The client can learn to add or subtract one commit to avoid the special treatment when that actually happens. (*) This is the largest positive number a 32-bit signed integer can contain. JGit and older C Git store depth as "int" so both are OK with this number. Dulwich does not support shallow clone. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- Documentation/fetch-options.txt | 4 ++++ Documentation/git-fetch-pack.txt | 2 ++ Documentation/technical/shallow.txt | 3 +++ builtin/fetch.c | 17 ++++++++++++++++- commit.h | 3 +++ t/t5500-fetch-pack.sh | 20 ++++++++++++++++++++ upload-pack.c | 13 ++++++++++--- 7 files changed, 58 insertions(+), 4 deletions(-) diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 6e98bdf149..7fea9a8ecd 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -13,6 +13,10 @@ to the specified number of commits from the tip of each remote branch history. Tags for the deepened commits are not fetched. +--unshallow:: + Convert a shallow repository to a complete one, removing all + the limitations imposed by shallow repositories. + ifndef::git-pull[] --dry-run:: Show what would be done, without making any changes. diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt index 8c751202d7..b81e90d8e7 100644 --- a/Documentation/git-fetch-pack.txt +++ b/Documentation/git-fetch-pack.txt @@ -84,6 +84,8 @@ be in a separate packet, and the list must end with a flush packet. --depth=:: Limit fetching to ancestor-chains not longer than n. + 'git-upload-pack' treats the special depth 2147483647 as + infinite even if there is an ancestor-chain that long. --no-progress:: Do not show the progress. diff --git a/Documentation/technical/shallow.txt b/Documentation/technical/shallow.txt index 0502a5471e..ea2f69faf5 100644 --- a/Documentation/technical/shallow.txt +++ b/Documentation/technical/shallow.txt @@ -53,3 +53,6 @@ It also writes an appropriate $GIT_DIR/shallow. You can deepen a shallow repository with "git-fetch --depth 20 repo branch", which will fetch branch from repo, but stop at depth 20, updating $GIT_DIR/shallow. + +The special depth 2147483647 (or 0x7fffffff, the largest positive +number a signed 32-bit integer can contain) means infinite depth. diff --git a/builtin/fetch.c b/builtin/fetch.c index 4b5a89839b..3b97fc9bc6 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -32,7 +32,7 @@ enum { static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity; static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT; -static int tags = TAGS_DEFAULT; +static int tags = TAGS_DEFAULT, unshallow; static const char *depth; static const char *upload_pack; static struct strbuf default_rla = STRBUF_INIT; @@ -82,6 +82,9 @@ static struct option builtin_fetch_options[] = { OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), OPT_STRING(0, "depth", &depth, N_("depth"), N_("deepen history of shallow clone")), + { OPTION_SET_INT, 0, "unshallow", &unshallow, NULL, + N_("convert to a complete repository"), + PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 }, { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"), N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN }, { OPTION_STRING, 0, "recurse-submodules-default", @@ -970,6 +973,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, builtin_fetch_options, builtin_fetch_usage, 0); + if (unshallow) { + if (depth) + die(_("--depth and --unshallow cannot be used together")); + else if (!is_repository_shallow()) + die(_("--unshallow on a complete repository does not make sense")); + else { + static char inf_depth[12]; + sprintf(inf_depth, "%d", INFINITE_DEPTH); + depth = inf_depth; + } + } + if (recurse_submodules != RECURSE_SUBMODULES_OFF) { if (recurse_submodules_default) { int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default); diff --git a/commit.h b/commit.h index 9f2131318d..0adfce96e4 100644 --- a/commit.h +++ b/commit.h @@ -163,6 +163,9 @@ extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *r extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup); extern struct commit_list *get_octopus_merge_bases(struct commit_list *in); +/* largest postive number a signed 32-bit integer can contain */ +#define INFINITE_DEPTH 0x7fffffff + extern int register_shallow(const unsigned char *sha1); extern int unregister_shallow(const unsigned char *sha1); extern int for_each_commit_graft(each_commit_graft_fn, void *); diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 6322e8ade8..426027ee92 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -264,6 +264,26 @@ test_expect_success 'clone shallow object count' ' grep "^count: 52" count.shallow ' +test_expect_success 'fetch --no-shallow on full repo' ' + test_must_fail git fetch --noshallow +' + +test_expect_success 'fetch --depth --no-shallow' ' + ( + cd shallow && + test_must_fail git fetch --depth=1 --noshallow + ) +' + +test_expect_success 'turn shallow to complete repository' ' + ( + cd shallow && + git fetch --unshallow && + ! test -f .git/shallow && + git fsck --full + ) +' + test_expect_success 'clone shallow without --no-single-branch' ' git clone --depth 1 "file://$(pwd)/." shallow2 ' diff --git a/upload-pack.c b/upload-pack.c index 2e90ccb74f..8740002817 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -670,10 +670,17 @@ static void receive_needs(void) if (depth == 0 && shallows.nr == 0) return; if (depth > 0) { - struct commit_list *result, *backup; + struct commit_list *result = NULL, *backup = NULL; int i; - backup = result = get_shallow_commits(&want_obj, depth, - SHALLOW, NOT_SHALLOW); + if (depth == INFINITE_DEPTH) + for (i = 0; i < shallows.nr; i++) { + struct object *object = shallows.objects[i].item; + object->flags |= NOT_SHALLOW; + } + else + backup = result = + get_shallow_commits(&want_obj, depth, + SHALLOW, NOT_SHALLOW); while (result) { struct object *object = &result->item->object; if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { -- cgit v1.2.1 From 682c7d2f1a2d1a5443777237450505738af2ff1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 11 Jan 2013 16:05:47 +0700 Subject: upload-pack: fix off-by-one depth calculation in shallow clone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_shallow_commits() is used to determine the cut points at a given depth (i.e. the number of commits in a chain that the user likes to get). However we count current depth up to the commit "commit" but we do the cutting at its parents (i.e. current depth + 1). This makes upload-pack always return one commit more than requested. This patch fixes it. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- shallow.c | 8 +++++++- t/t5500-fetch-pack.sh | 25 +++++++++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/shallow.c b/shallow.c index a0363dea20..6be915f38f 100644 --- a/shallow.c +++ b/shallow.c @@ -72,8 +72,14 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth, } if (parse_commit(commit)) die("invalid commit"); - commit->object.flags |= not_shallow_flag; cur_depth++; + if (cur_depth >= depth) { + commit_list_insert(commit, &result); + commit->object.flags |= shallow_flag; + commit = NULL; + continue; + } + commit->object.flags |= not_shallow_flag; for (p = commit->parents, commit = NULL; p; p = p->next) { if (!p->item->util) { int *pointer = xmalloc(sizeof(int)); diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 426027ee92..354d32c584 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -130,16 +130,25 @@ test_expect_success 'single given branch clone' ' test_must_fail git --git-dir=branch-a/.git rev-parse origin/B ' +test_expect_success 'clone shallow depth 1' ' + git clone --no-single-branch --depth 1 "file://$(pwd)/." shallow0 && + test "`git --git-dir=shallow0/.git rev-list --count HEAD`" = 1 +' + test_expect_success 'clone shallow' ' git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow ' +test_expect_success 'clone shallow depth count' ' + test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 2 +' + test_expect_success 'clone shallow object count' ' ( cd shallow && git count-objects -v ) > count.shallow && - grep "^in-pack: 18" count.shallow + grep "^in-pack: 12" count.shallow ' test_expect_success 'clone shallow object count (part 2)' ' @@ -256,12 +265,16 @@ test_expect_success 'additional simple shallow deepenings' ' ) ' +test_expect_success 'clone shallow depth count' ' + test "`git --git-dir=shallow/.git rev-list --count HEAD`" = 11 +' + test_expect_success 'clone shallow object count' ' ( cd shallow && git count-objects -v ) > count.shallow && - grep "^count: 52" count.shallow + grep "^count: 55" count.shallow ' test_expect_success 'fetch --no-shallow on full repo' ' @@ -293,7 +306,7 @@ test_expect_success 'clone shallow object count' ' cd shallow2 && git count-objects -v ) > count.shallow2 && - grep "^in-pack: 6" count.shallow2 + grep "^in-pack: 3" count.shallow2 ' test_expect_success 'clone shallow with --branch' ' @@ -301,7 +314,7 @@ test_expect_success 'clone shallow with --branch' ' ' test_expect_success 'clone shallow object count' ' - echo "in-pack: 6" > count3.expected && + echo "in-pack: 3" > count3.expected && GIT_DIR=shallow3/.git git count-objects -v | grep "^in-pack" > count3.actual && test_cmp count3.expected count3.actual @@ -330,7 +343,7 @@ EOF GIT_DIR=shallow6/.git git tag -l >taglist.actual && test_cmp taglist.expected taglist.actual && - echo "in-pack: 7" > count6.expected && + echo "in-pack: 4" > count6.expected && GIT_DIR=shallow6/.git git count-objects -v | grep "^in-pack" > count6.actual && test_cmp count6.expected count6.actual @@ -345,7 +358,7 @@ EOF GIT_DIR=shallow7/.git git tag -l >taglist.actual && test_cmp taglist.expected taglist.actual && - echo "in-pack: 7" > count7.expected && + echo "in-pack: 4" > count7.expected && GIT_DIR=shallow7/.git git count-objects -v | grep "^in-pack" > count7.actual && test_cmp count7.expected count7.actual -- cgit v1.2.1 From cfb70e1fa506e79f337e716ed4813c6caa428644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Fri, 11 Jan 2013 16:05:48 +0700 Subject: fetch: elaborate --depth action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --depth is explained as deepen, but the way it's applied, it can shorten the history as well. Keen users may have noticed the implication by the phrase "the specified number of commits from the tip of each remote branch". Put "shorten" in the description to make it clearer. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- Documentation/fetch-options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 7fea9a8ecd..9cb649673d 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -8,7 +8,7 @@ option old data in `.git/FETCH_HEAD` will be overwritten. --depth=:: - Deepen the history of a 'shallow' repository created by + Deepen or shorten the history of a 'shallow' repository created by `git clone` with `--depth=` option (see linkgit:git-clone[1]) to the specified number of commits from the tip of each remote branch history. Tags for the deepened commits are not fetched. -- cgit v1.2.1