diff --git a/builtin-count-objects.c b/builtin-count-objects.c index 62fd1f0961..b814fe5070 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -60,7 +60,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose, hex[40] = 0; if (get_sha1_hex(hex, sha1)) die("internal error"); - if (has_sha1_pack(sha1, NULL)) + if (has_sha1_pack(sha1)) (*packed_loose)++; } } diff --git a/builtin-fsck.c b/builtin-fsck.c index 64dffa5421..6436bc2248 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -160,7 +160,7 @@ static void check_reachable_object(struct object *obj) * do a full fsck */ if (!obj->parsed) { - if (has_sha1_pack(obj->sha1, NULL)) + if (has_sha1_pack(obj->sha1)) return; /* it is in pack - forget about it */ printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1)); errors_found |= ERROR_REACHABLE; diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 8ca46c8deb..9fc3b35547 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -1966,11 +1966,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs) const unsigned char *sha1; struct object *o; - for (i = 0; i < revs->num_ignore_packed; i++) { - if (matches_pack_name(p, revs->ignore_packed[i])) - break; - } - if (revs->num_ignore_packed <= i) + if (!p->pack_local || p->pack_keep) continue; if (open_pack_index(p)) die("cannot open pack index"); @@ -1999,6 +1995,29 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs) free(in_pack.array); } +static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1) +{ + static struct packed_git *last_found = (void *)1; + struct packed_git *p; + + p = (last_found != (void *)1) ? last_found : packed_git; + + while (p) { + if ((!p->pack_local || p->pack_keep) && + find_pack_entry_one(sha1, p)) { + last_found = p; + return 1; + } + if (p == last_found) + p = packed_git; + else + p = p->next; + if (p == last_found) + p = p->next; + } + return 0; +} + static void loosen_unused_packed_objects(struct rev_info *revs) { struct packed_git *p; @@ -2006,11 +2025,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs) const unsigned char *sha1; for (p = packed_git; p; p = p->next) { - for (i = 0; i < revs->num_ignore_packed; i++) { - if (matches_pack_name(p, revs->ignore_packed[i])) - break; - } - if (revs->num_ignore_packed <= i) + if (!p->pack_local || p->pack_keep) continue; if (open_pack_index(p)) @@ -2018,7 +2033,8 @@ static void loosen_unused_packed_objects(struct rev_info *revs) for (i = 0; i < p->num_objects; i++) { sha1 = nth_packed_object_sha1(p, i); - if (!locate_object_entry(sha1)) + if (!locate_object_entry(sha1) && + !has_sha1_pack_kept_or_nonlocal(sha1)) if (force_object_loose(sha1, p->mtime)) die("unable to force loose object"); } @@ -2208,7 +2224,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) continue; } if (!strcmp("--unpacked", arg) || - !prefixcmp(arg, "--unpacked=") || !strcmp("--reflog", arg) || !strcmp("--all", arg)) { use_internal_rev_list = 1; diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 10cb8df845..2d5b2cd353 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -23,7 +23,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) memcpy(hex+2, de->d_name, 38); if (get_sha1_hex(hex, sha1)) continue; - if (!has_sha1_pack(sha1, NULL)) + if (!has_sha1_pack(sha1)) continue; memcpy(pathname + len, de->d_name, 38); if (opts & DRY_RUN) diff --git a/cache.h b/cache.h index 189151de25..50179687b5 100644 --- a/cache.h +++ b/cache.h @@ -644,7 +644,7 @@ extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned l extern int move_temp_to_file(const char *tmpfile, const char *filename); -extern int has_sha1_pack(const unsigned char *sha1, const char **ignore); +extern int has_sha1_pack(const unsigned char *sha1); extern int has_sha1_file(const unsigned char *sha1); extern int has_loose_object_nonlocal(const unsigned char *sha1); @@ -839,7 +839,6 @@ extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsign extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep); extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t); extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigned long *, unsigned long *, unsigned int *, unsigned char *); -extern int matches_pack_name(struct packed_git *p, const char *name); /* Dumb servers support */ extern int update_server_info(int); diff --git a/diff.c b/diff.c index 11798af0c1..37f99209a0 100644 --- a/diff.c +++ b/diff.c @@ -1783,7 +1783,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int * objects however would tend to be slower as they need * to be individually opened and inflated. */ - if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1, NULL)) + if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1)) return 0; len = strlen(name); diff --git a/git-repack.sh b/git-repack.sh index 00c597e97c..0868734723 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -60,6 +60,7 @@ case ",$all_into_one," in args='--unpacked --incremental' ;; ,t,) + args= existing= if [ -d "$PACKDIR" ]; then for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \ | sed -e 's/^\.\///' -e 's/\.pack$//'` @@ -67,11 +68,10 @@ case ",$all_into_one," in if [ -e "$PACKDIR/$e.keep" ]; then : keep else - args="$args --unpacked=$e.pack" existing="$existing $e" fi done - if test -n "$args" -a -n "$unpack_unreachable" -a \ + if test -n "$existing" -a -n "$unpack_unreachable" -a \ -n "$remove_redundant" then args="$args $unpack_unreachable" diff --git a/revision.c b/revision.c index 286e416b75..34ee490ea0 100644 --- a/revision.c +++ b/revision.c @@ -994,16 +994,6 @@ static void add_message_grep(struct rev_info *revs, const char *pattern) add_grep(revs, pattern, GREP_PATTERN_BODY); } -static void add_ignore_packed(struct rev_info *revs, const char *name) -{ - int num = ++revs->num_ignore_packed; - - revs->ignore_packed = xrealloc(revs->ignore_packed, - sizeof(const char *) * (num + 1)); - revs->ignore_packed[num-1] = name; - revs->ignore_packed[num] = NULL; -} - static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv, int *unkc, const char **unkv) { @@ -1116,12 +1106,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->edge_hint = 1; } else if (!strcmp(arg, "--unpacked")) { revs->unpacked = 1; - free(revs->ignore_packed); - revs->ignore_packed = NULL; - revs->num_ignore_packed = 0; } else if (!prefixcmp(arg, "--unpacked=")) { - revs->unpacked = 1; - add_ignore_packed(revs, arg+11); + die("--unpacked= no longer supported."); } else if (!strcmp(arg, "-r")) { revs->diff = 1; DIFF_OPT_SET(&revs->diffopt, RECURSIVE); @@ -1685,7 +1671,7 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit) { if (commit->object.flags & SHOWN) return commit_ignore; - if (revs->unpacked && has_sha1_pack(commit->object.sha1, revs->ignore_packed)) + if (revs->unpacked && has_sha1_pack(commit->object.sha1)) return commit_ignore; if (revs->show_all) return commit_show; diff --git a/revision.h b/revision.h index 7cf848771b..66d211ac2e 100644 --- a/revision.h +++ b/revision.h @@ -49,7 +49,7 @@ struct rev_info { blob_objects:1, edge_hint:1, limited:1, - unpacked:1, /* see also ignore_packed below */ + unpacked:1, boundary:2, left_right:1, rewrite_parents:1, @@ -80,9 +80,6 @@ struct rev_info { missing_newline:1; enum date_mode date_mode; - const char **ignore_packed; /* pretend objects in these are unpacked */ - int num_ignore_packed; - unsigned int abbrev; enum cmit_fmt commit_format; struct log_info *loginfo; diff --git a/sha1_file.c b/sha1_file.c index a07aa4e5c4..37e833b77d 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1919,25 +1919,7 @@ off_t find_pack_entry_one(const unsigned char *sha1, return 0; } -int matches_pack_name(struct packed_git *p, const char *name) -{ - const char *last_c, *c; - - if (!strcmp(p->pack_name, name)) - return 1; - - for (c = p->pack_name, last_c = c; *c;) - if (*c == '/') - last_c = ++c; - else - ++c; - if (!strcmp(last_c, name)) - return 1; - - return 0; -} - -static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed) +static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e) { static struct packed_git *last_found = (void *)1; struct packed_git *p; @@ -1949,15 +1931,6 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, cons p = (last_found == (void *)1) ? packed_git : last_found; do { - if (ignore_packed) { - const char **ig; - for (ig = ignore_packed; *ig; ig++) - if (matches_pack_name(p, *ig)) - break; - if (*ig) - goto next; - } - if (p->num_bad_objects) { unsigned i; for (i = 0; i < p->num_bad_objects; i++) @@ -2038,7 +2011,7 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep) struct pack_entry e; int status; - if (!find_pack_entry(sha1, &e, NULL)) { + if (!find_pack_entry(sha1, &e)) { /* Most likely it's a loose object. */ status = sha1_loose_object_info(sha1, sizep); if (status >= 0) @@ -2046,7 +2019,7 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep) /* Not a loose object; someone else may have just packed it. */ reprepare_packed_git(); - if (!find_pack_entry(sha1, &e, NULL)) + if (!find_pack_entry(sha1, &e)) return status; } @@ -2065,7 +2038,7 @@ static void *read_packed_sha1(const unsigned char *sha1, struct pack_entry e; void *data; - if (!find_pack_entry(sha1, &e, NULL)) + if (!find_pack_entry(sha1, &e)) return NULL; data = cache_or_unpack_entry(e.p, e.offset, size, type, 1); if (!data) { @@ -2464,17 +2437,17 @@ int has_pack_file(const unsigned char *sha1) return 1; } -int has_sha1_pack(const unsigned char *sha1, const char **ignore_packed) +int has_sha1_pack(const unsigned char *sha1) { struct pack_entry e; - return find_pack_entry(sha1, &e, ignore_packed); + return find_pack_entry(sha1, &e); } int has_sha1_file(const unsigned char *sha1) { struct pack_entry e; - if (find_pack_entry(sha1, &e, NULL)) + if (find_pack_entry(sha1, &e)) return 1; return has_loose_object(sha1); } diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index f5682d66db..6b29bff782 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -88,5 +88,66 @@ test_expect_failure 'packed obs in alt ODB are repacked when local repo has pack done ' +test_expect_success 'packed obs in alternate ODB kept pack are repacked' ' + # swap the .keep so the commit object is in the pack with .keep + for p in alt_objects/pack/*.pack + do + base_name=$(basename $p .pack) + if test -f alt_objects/pack/$base_name.keep + then + rm alt_objects/pack/$base_name.keep + else + touch alt_objects/pack/$base_name.keep + fi + done + git repack -a -d && + myidx=$(ls -1 .git/objects/pack/*.idx) && + test -f "$myidx" && + for p in alt_objects/pack/*.idx; do + git verify-pack -v $p | sed -n -e "/^[0-9a-f]\{40\}/p" + done | while read sha1 rest; do + if ! ( git verify-pack -v $myidx | grep "^$sha1" ); then + echo "Missing object in local pack: $sha1" + return 1 + fi + done +' + +test_expect_success 'packed unreachable obs in alternate ODB are not loosened' ' + rm -f alt_objects/pack/*.keep && + mv .git/objects/pack/* alt_objects/pack/ && + csha1=$(git rev-parse HEAD^{commit}) && + git reset --hard HEAD^ && + sleep 1 && + git reflog expire --expire=now --expire-unreachable=now --all && + # The pack-objects call on the next line is equivalent to + # git repack -A -d without the call to prune-packed + git pack-objects --honor-pack-keep --non-empty --all --reflog \ + --unpack-unreachable .git/objects/info/alternates && + test_must_fail git show $csha1 +' + +test_expect_success 'local packed unreachable obs that exist in alternate ODB are not loosened' ' + echo `pwd`/alt_objects > .git/objects/info/alternates && + echo "$csha1" | git pack-objects --non-empty --all --reflog pack && + rm -f .git/objects/pack/* && + mv pack-* .git/objects/pack/ && + # The pack-objects call on the next line is equivalent to + # git repack -A -d without the call to prune-packed + git pack-objects --honor-pack-keep --non-empty --all --reflog \ + --unpack-unreachable .git/objects/info/alternates && + test_must_fail git show $csha1 +' + test_done