fetch: add --unshallow for turning shallow repo into complete one
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Fri, 11 Jan 2013 09:05:46 +0000 (16:05 +0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 11 Jan 2013 17:09:30 +0000 (09:09 -0800)
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>
Documentation/fetch-options.txt
Documentation/git-fetch-pack.txt
Documentation/technical/shallow.txt
builtin/fetch.c
commit.h
t/t5500-fetch-pack.sh
upload-pack.c

index 6e98bdf1490a0a5718dd14a4c2d8b2baaee7383e..7fea9a8ecd0a542d49ba37af96bebc9fe8e16d97 100644 (file)
        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.
index 8c751202d75ec5f3e62b7c386bb168f13e63e295..b81e90d8e70722e0da690ab5afa1bca4ad356b68 100644 (file)
@@ -84,6 +84,8 @@ be in a separate packet, and the list must end with a flush packet.
 
 --depth=<n>::
        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.
index 0502a5471e699aac572abd5ab82c71a03f07e9f1..ea2f69faf5cd1e87226eb2a8c281aa4d5f6ed204 100644 (file)
@@ -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.
index 4b5a89839b66f201bda42f06cabdf781d44f0192..3b97fc9bc64fb170bc512cc9054a1a3574a322ba 100644 (file)
@@ -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);
index 9f2131318d4c43fdaaca40e45e45e7d1af61cdfe..0adfce96e46aa9e9017d7c39eed54b01e24bc2d6 100644 (file)
--- 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 *);
index 6322e8ade8436dc4e66b9874638e7ca6b7d222b3..426027ee92975d7d87fe22860870fd5a14524d0e 100755 (executable)
@@ -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
 '
index 2e90ccb74fe45e6335ee6a76451da40d7d3f5a09..8740002817c0fdcd02d5c0c6a6402df222f4d965 100644 (file)
@@ -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))) {