aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2007-04-21 17:19:25 -0700
committerJunio C Hamano <junkio@cox.net>2007-04-21 17:19:25 -0700
commite660e11b202f12d15cfe8089909a307b1900c03a (patch)
tree7717a73e5920d4e3a5482391e5e290a220ba2d6b
parente8760cde01299817daae26c9ad074b776bbd8f88 (diff)
parentb9849a1ab63143c3b70e339491a897ef62a4173b (diff)
downloadgit-e660e11b202f12d15cfe8089909a307b1900c03a.tar.gz
git-e660e11b202f12d15cfe8089909a307b1900c03a.tar.xz
Merge branch 'jc/quickfetch'
* 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
-rw-r--r--builtin-fetch--tool.c84
-rw-r--r--builtin-rev-list.c4
-rwxr-xr-xgit-fetch.sh42
-rwxr-xr-xt/t5502-quickfetch.sh89
4 files changed, 206 insertions, 13 deletions
diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c
index e9d676455..be341c159 100644
--- a/builtin-fetch--tool.c
+++ b/builtin-fetch--tool.c
@@ -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)
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index 09774f955..c0329dcec 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -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),
diff --git a/git-fetch.sh b/git-fetch.sh
index b04bd553f..832b20cce 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -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
index 000000000..b4760f2dc
--- /dev/null
+++ b/t/t5502-quickfetch.sh
@@ -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