fetch: add --unshallow for turning shallow repo into complete one

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 <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Jan 11, 2013 at 16:05 UTC 4dcb167fc3536db0e78c50f239cd3a19afd383fa
7 files changed +58 -4
Documentation/fetch-options.txt
+4
@@ -13,6 +13,10 @@
13 to the specified number of commits from the tip of each remote
14 branch history. Tags for the deepened commits are not fetched.
15
16 +--unshallow::
17 + Convert a shallow repository to a complete one, removing all
18 + the limitations imposed by shallow repositories.
19 +
20 ifndef::git-pull[]
21 --dry-run::
22 Show what would be done, without making any changes.
Documentation/git-fetch-pack.txt
+2
@@ -84,6 +84,8 @@ be in a separate packet, and the list must end with a flush packet.
84
85 --depth=<n>::
86 Limit fetching to ancestor-chains not longer than n.
87 + 'git-upload-pack' treats the special depth 2147483647 as
88 + infinite even if there is an ancestor-chain that long.
89
90 --no-progress::
91 Do not show the progress.
Documentation/technical/shallow.txt
+3
@@ -53,3 +53,6 @@ It also writes an appropriate $GIT_DIR/shallow.
53 You can deepen a shallow repository with "git-fetch --depth 20
54 repo branch", which will fetch branch from repo, but stop at depth
55 20, updating $GIT_DIR/shallow.
56 +
57 +The special depth 2147483647 (or 0x7fffffff, the largest positive
58 +number a signed 32-bit integer can contain) means infinite depth.
builtin/fetch.c
+16 -1
@@ -32,7 +32,7 @@ enum {
32
33 static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
34 static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
35 -static int tags = TAGS_DEFAULT;
35 +static int tags = TAGS_DEFAULT, unshallow;
36 static const char *depth;
37 static const char *upload_pack;
38 static struct strbuf default_rla = STRBUF_INIT;
@@ -82,6 +82,9 @@ static struct option builtin_fetch_options[] = {
82 OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
83 OPT_STRING(0, "depth", &depth, N_("depth"),
84 N_("deepen history of shallow clone")),
85 + { OPTION_SET_INT, 0, "unshallow", &unshallow, NULL,
86 + N_("convert to a complete repository"),
87 + PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1 },
88 { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
89 N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
90 { OPTION_STRING, 0, "recurse-submodules-default",
@@ -970,6 +973,18 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
973 argc = parse_options(argc, argv, prefix,
974 builtin_fetch_options, builtin_fetch_usage, 0);
975
976 + if (unshallow) {
977 + if (depth)
978 + die(_("--depth and --unshallow cannot be used together"));
979 + else if (!is_repository_shallow())
980 + die(_("--unshallow on a complete repository does not make sense"));
981 + else {
982 + static char inf_depth[12];
983 + sprintf(inf_depth, "%d", INFINITE_DEPTH);
984 + depth = inf_depth;
985 + }
986 + }
987 +
988 if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
989 if (recurse_submodules_default) {
990 int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default);
commit.h
+3
@@ -163,6 +163,9 @@ extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *r
163 extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup);
164 extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
165
166 +/* largest postive number a signed 32-bit integer can contain */
167 +#define INFINITE_DEPTH 0x7fffffff
168 +
169 extern int register_shallow(const unsigned char *sha1);
170 extern int unregister_shallow(const unsigned char *sha1);
171 extern int for_each_commit_graft(each_commit_graft_fn, void *);
t/t5500-fetch-pack.sh
+20
@@ -264,6 +264,26 @@ test_expect_success 'clone shallow object count' '
264 grep "^count: 52" count.shallow
265 '
266
267 +test_expect_success 'fetch --no-shallow on full repo' '
268 + test_must_fail git fetch --noshallow
269 +'
270 +
271 +test_expect_success 'fetch --depth --no-shallow' '
272 + (
273 + cd shallow &&
274 + test_must_fail git fetch --depth=1 --noshallow
275 + )
276 +'
277 +
278 +test_expect_success 'turn shallow to complete repository' '
279 + (
280 + cd shallow &&
281 + git fetch --unshallow &&
282 + ! test -f .git/shallow &&
283 + git fsck --full
284 + )
285 +'
286 +
287 test_expect_success 'clone shallow without --no-single-branch' '
288 git clone --depth 1 "file://$(pwd)/." shallow2
289 '
upload-pack.c
+10 -3
@@ -670,10 +670,17 @@ static void receive_needs(void)
670 if (depth == 0 && shallows.nr == 0)
671 return;
672 if (depth > 0) {
673 - struct commit_list *result, *backup;
673 + struct commit_list *result = NULL, *backup = NULL;
674 int i;
675 - backup = result = get_shallow_commits(&want_obj, depth,
676 - SHALLOW, NOT_SHALLOW);
675 + if (depth == INFINITE_DEPTH)
676 + for (i = 0; i < shallows.nr; i++) {
677 + struct object *object = shallows.objects[i].item;
678 + object->flags |= NOT_SHALLOW;
679 + }
680 + else
681 + backup = result =
682 + get_shallow_commits(&want_obj, depth,
683 + SHALLOW, NOT_SHALLOW);
684 while (result) {
685 struct object *object = &result->item->object;
686 if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) {