Merge branch 'jc/quickfetch'
authorJunio C Hamano <junkio@cox.net>
Sun, 22 Apr 2007 00:19:25 +0000 (17:19 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 22 Apr 2007 00:19:25 +0000 (17:19 -0700)
* jc/quickfetch:
Make sure quickfetch is not fooled with a previous, incomplete fetch.
git-fetch: use fetch--tool pick-rref to avoid local fetch from alternate
git-fetch--tool pick-rref

builtin-fetch--tool.c
builtin-rev-list.c
git-fetch.sh
t/t5502-quickfetch.sh [new file with mode: 0755]
index e9d676455078b40138ad4716a912c4b2b5e10c2e..be341c159fb17117c4cc55a8efa9e2107375a06b 100644 (file)
@@ -436,10 +436,87 @@ static int expand_refs_wildcard(const char *ls_remote_result, int numrefs,
        return 0;
 }
 
+static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_result)
+{
+       int err = 0;
+       int lrr_count = lrr_count, i, pass;
+       const char *cp;
+       struct lrr {
+               const char *line;
+               const char *name;
+               int namelen;
+               int shown;
+       } *lrr_list = lrr_list;
+
+       for (pass = 0; pass < 2; pass++) {
+               /* pass 0 counts and allocates, pass 1 fills... */
+               cp = ls_remote_result;
+               i = 0;
+               while (1) {
+                       const char *np;
+                       while (*cp && isspace(*cp))
+                               cp++;
+                       if (!*cp)
+                               break;
+                       np = strchr(cp, '\n');
+                       if (!np)
+                               np = cp + strlen(cp);
+                       if (pass) {
+                               lrr_list[i].line = cp;
+                               lrr_list[i].name = cp + 41;
+                               lrr_list[i].namelen = np - (cp + 41);
+                       }
+                       i++;
+                       cp = np;
+               }
+               if (!pass) {
+                       lrr_count = i;
+                       lrr_list = xcalloc(lrr_count, sizeof(*lrr_list));
+               }
+       }
+
+       while (1) {
+               const char *next;
+               int rreflen;
+               int i;
+
+               while (*rref && isspace(*rref))
+                       rref++;
+               if (!*rref)
+                       break;
+               next = strchr(rref, '\n');
+               if (!next)
+                       next = rref + strlen(rref);
+               rreflen = next - rref;
+
+               for (i = 0; i < lrr_count; i++) {
+                       struct lrr *lrr = &(lrr_list[i]);
+
+                       if (rreflen == lrr->namelen &&
+                           !memcmp(lrr->name, rref, rreflen)) {
+                               if (!lrr->shown)
+                                       printf("%.*s\n",
+                                              sha1_only ? 40 : lrr->namelen + 41,
+                                              lrr->line);
+                               lrr->shown = 1;
+                               break;
+                       }
+               }
+               if (lrr_count <= i) {
+                       error("pick-rref: %.*s not found", rreflen, rref);
+                       err = 1;
+               }
+               rref = next;
+       }
+       free(lrr_list);
+       return err;
+}
+
 int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
 {
        int verbose = 0;
        int force = 0;
+       int sopt = 0;
 
        while (1 < argc) {
                const char *arg = argv[1];
@@ -447,6 +524,8 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
                        verbose = 1;
                else if (!strcmp("-f", arg))
                        force = 1;
+               else if (!strcmp("-s", arg))
+                       sopt = 1;
                else
                        break;
                argc--;
@@ -491,6 +570,11 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
                        reflist = get_stdin();
                return parse_reflist(reflist);
        }
+       if (!strcmp("pick-rref", argv[1])) {
+               if (argc != 4)
+                       return error("pick-rref takes 2 args");
+               return pick_rref(sopt, argv[2], argv[3]);
+       }
        if (!strcmp("expand-refs-wildcard", argv[1])) {
                const char *reflist;
                if (argc < 4)
index 09774f9559b81050d89bd6663b8b672438da4342..c0329dcecdbb4775b2c438a0bf6429a5ee72b18e 100644 (file)
@@ -113,6 +113,10 @@ static void show_object(struct object_array_entry *p)
         * confuse downstream git-pack-objects very badly.
         */
        const char *ep = strchr(p->name, '\n');
+
+       if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
+               die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
+
        if (ep) {
                printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
                       (int) (ep - p->name),
index b04bd553f86213478a36f8ec2f19476f02ccf09f..832b20cce629cb5753e849fb2a5b60ca707397a0 100755 (executable)
@@ -177,9 +177,33 @@ fetch_all_at_once () {
            git-bundle unbundle "$remote" $rref ||
            echo failed "$remote"
        else
-         git-fetch-pack --thin $exec $keep $shallow_depth \
-             $quiet $no_progress "$remote" $rref ||
-         echo failed "$remote"
+               if      test -d "$remote" &&
+
+                       # The remote might be our alternate.  With
+                       # this optimization we will bypass fetch-pack
+                       # altogether, which means we cannot be doing
+                       # the shallow stuff at all.
+                       test ! -f "$GIT_DIR/shallow" &&
+                       test -z "$shallow_depth" &&
+
+                       # See if all of what we are going to fetch are
+                       # connected to our repository's tips, in which
+                       # case we do not have to do any fetch.
+                       theirs=$(git-fetch--tool -s pick-rref \
+                                       "$rref" "$ls_remote_result") &&
+
+                       # This will barf when $theirs reach an object that
+                       # we do not have in our repository.  Otherwise,
+                       # we already have everything the fetch would bring in.
+                       git-rev-list --objects $theirs --not --all \
+                               >/dev/null 2>/dev/null
+               then
+                       git-fetch--tool pick-rref "$rref" "$ls_remote_result"
+               else
+                       git-fetch-pack --thin $exec $keep $shallow_depth \
+                               $quiet $no_progress "$remote" $rref ||
+                       echo failed "$remote"
+               fi
        fi
       ) |
       (
@@ -239,16 +263,8 @@ fetch_per_ref () {
          fi
 
          # Find $remote_name from ls-remote output.
-         head=$(
-               IFS='   '
-               echo "$ls_remote_result" |
-               while read sha1 name
-               do
-                       test "z$name" = "z$remote_name" || continue
-                       echo "$sha1"
-                       break
-               done
-         )
+         head=$(git-fetch--tool -s pick-rref \
+                       "$remote_name" "$ls_remote_result")
          expr "z$head" : "z$_x40\$" >/dev/null ||
                die "No such ref $remote_name at $remote"
          echo >&2 "Fetching $remote_name from $remote using $proto"
diff --git a/t/t5502-quickfetch.sh b/t/t5502-quickfetch.sh
new file mode 100755 (executable)
index 0000000..b4760f2
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+test_description='test quickfetch from local'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       test_tick &&
+       echo ichi >file &&
+       git add file &&
+       git commit -m initial &&
+
+       cnt=$( (
+               git count-objects | sed -e "s/ *objects,.*//"
+       ) ) &&
+       test $cnt -eq 3
+'
+
+test_expect_success 'clone without alternate' '
+
+       (
+               mkdir cloned &&
+               cd cloned &&
+               git init-db &&
+               git remote add -f origin ..
+       ) &&
+       cnt=$( (
+               cd cloned &&
+               git count-objects | sed -e "s/ *objects,.*//"
+       ) ) &&
+       test $cnt -eq 3
+'
+
+test_expect_success 'further commits in the original' '
+
+       test_tick &&
+       echo ni >file &&
+       git commit -a -m second &&
+
+       cnt=$( (
+               git count-objects | sed -e "s/ *objects,.*//"
+       ) ) &&
+       test $cnt -eq 6
+'
+
+test_expect_success 'copy commit and tree but not blob by hand' '
+
+       git rev-list --objects HEAD |
+       git pack-objects --stdout |
+       (
+               cd cloned &&
+               git unpack-objects
+       ) &&
+
+       cnt=$( (
+               cd cloned &&
+               git count-objects | sed -e "s/ *objects,.*//"
+       ) ) &&
+       test $cnt -eq 6
+
+       blob=$(git rev-parse HEAD:file | sed -e "s|..|&/|") &&
+       test -f "cloned/.git/objects/$blob" &&
+       rm -f "cloned/.git/objects/$blob" &&
+
+       cnt=$( (
+               cd cloned &&
+               git count-objects | sed -e "s/ *objects,.*//"
+       ) ) &&
+       test $cnt -eq 5
+
+'
+
+test_expect_success 'quickfetch should not leave a corrupted repository' '
+
+       (
+               cd cloned &&
+               git fetch
+       ) &&
+
+       cnt=$( (
+               cd cloned &&
+               git count-objects | sed -e "s/ *objects,.*//"
+       ) ) &&
+       test $cnt -eq 6
+
+'
+
+test_done