Merge branch 'bc/maint-keep-pack'

* bc/maint-keep-pack:
  t7700: test that 'repack -a' packs alternate packed objects
  pack-objects: extend --local to mean ignore non-local loose objects too
  sha1_file.c: split has_loose_object() into local and non-local counterparts
  t7700: demonstrate mishandling of loose objects in an alternate ODB
  builtin-gc.c: use new pack_keep bitfield to detect .keep file existence
  repack: do not fall back to incremental repacking with [-a|-A]
  repack: don't repack local objects in packs with .keep file
  pack-objects: new option --honor-pack-keep
  packed_git: convert pack_local flag into a bitfield and add pack_keep
  t7700: demonstrate mishandling of objects in packs with a .keep file
This commit is contained in:
Junio C Hamano 2008-11-12 22:00:43 -08:00
Родитель a5b2d4ac24 3289b9dec5
Коммит ecbbfb15a4
7 изменённых файлов: 116 добавлений и 27 удалений

Просмотреть файл

@ -109,6 +109,11 @@ base-name::
The default is unlimited, unless the config variable The default is unlimited, unless the config variable
`pack.packSizeLimit` is set. `pack.packSizeLimit` is set.
--honor-pack-keep::
This flag causes an object already in a local pack that
has a .keep file to be ignored, even if it appears in the
standard input.
--incremental:: --incremental::
This flag causes an object already in a pack ignored This flag causes an object already in a pack ignored
even if it appears in the standard input. even if it appears in the standard input.
@ -116,7 +121,7 @@ base-name::
--local:: --local::
This flag is similar to `--incremental`; instead of This flag is similar to `--incremental`; instead of
ignoring all packed objects, it only ignores objects ignoring all packed objects, it only ignores objects
that are packed and not in the local object store that are packed and/or not in the local object store
(i.e. borrowed from an alternate). (i.e. borrowed from an alternate).
--non-empty:: --non-empty::

Просмотреть файл

@ -131,19 +131,9 @@ static int too_many_packs(void)
prepare_packed_git(); prepare_packed_git();
for (cnt = 0, p = packed_git; p; p = p->next) { for (cnt = 0, p = packed_git; p; p = p->next) {
char path[PATH_MAX];
size_t len;
int keep;
if (!p->pack_local) if (!p->pack_local)
continue; continue;
len = strlen(p->pack_name); if (p->pack_keep)
if (PATH_MAX <= len + 1)
continue; /* oops, give up */
memcpy(path, p->pack_name, len-5);
memcpy(path + len - 5, ".keep", 6);
keep = access(p->pack_name, F_OK) && (errno == ENOENT);
if (keep)
continue; continue;
/* /*
* Perhaps check the size of the pack and count only * Perhaps check the size of the pack and count only

Просмотреть файл

@ -71,6 +71,7 @@ static int reuse_delta = 1, reuse_object = 1;
static int keep_unreachable, unpack_unreachable, include_tag; static int keep_unreachable, unpack_unreachable, include_tag;
static int local; static int local;
static int incremental; static int incremental;
static int ignore_packed_keep;
static int allow_ofs_delta; static int allow_ofs_delta;
static const char *base_name; static const char *base_name;
static int progress = 1; static int progress = 1;
@ -698,6 +699,9 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
return 0; return 0;
} }
if (!exclude && local && has_loose_object_nonlocal(sha1))
return 0;
for (p = packed_git; p; p = p->next) { for (p = packed_git; p; p = p->next) {
off_t offset = find_pack_entry_one(sha1, p); off_t offset = find_pack_entry_one(sha1, p);
if (offset) { if (offset) {
@ -711,6 +715,8 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
return 0; return 0;
if (local && !p->pack_local) if (local && !p->pack_local)
return 0; return 0;
if (ignore_packed_keep && p->pack_local && p->pack_keep)
return 0;
} }
} }
@ -2056,6 +2062,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
incremental = 1; incremental = 1;
continue; continue;
} }
if (!strcmp("--honor-pack-keep", arg)) {
ignore_packed_keep = 1;
continue;
}
if (!prefixcmp(arg, "--compression=")) { if (!prefixcmp(arg, "--compression=")) {
char *end; char *end;
int level = strtoul(arg+14, &end, 0); int level = strtoul(arg+14, &end, 0);

Просмотреть файл

@ -580,6 +580,7 @@ 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, const char **ignore);
extern int has_sha1_file(const unsigned char *sha1); extern int has_sha1_file(const unsigned char *sha1);
extern int has_loose_object_nonlocal(const unsigned char *sha1);
extern int has_pack_file(const unsigned char *sha1); extern int has_pack_file(const unsigned char *sha1);
extern int has_pack_index(const unsigned char *sha1); extern int has_pack_index(const unsigned char *sha1);
@ -688,7 +689,8 @@ extern struct packed_git {
int index_version; int index_version;
time_t mtime; time_t mtime;
int pack_fd; int pack_fd;
int pack_local; unsigned pack_local:1,
pack_keep:1;
unsigned char sha1[20]; unsigned char sha1[20];
/* something like ".git/objects/pack/xxxxx.pack" */ /* something like ".git/objects/pack/xxxxx.pack" */
char pack_name[FLEX_ARRAY]; /* more */ char pack_name[FLEX_ARRAY]; /* more */

Просмотреть файл

@ -71,19 +71,16 @@ case ",$all_into_one," in
existing="$existing $e" existing="$existing $e"
fi fi
done done
fi if test -n "$args" -a -n "$unpack_unreachable"
if test -z "$args" then
then args="$args $unpack_unreachable"
args='--unpacked --incremental' fi
elif test -n "$unpack_unreachable"
then
args="$args $unpack_unreachable"
fi fi
;; ;;
esac esac
args="$args $local $quiet $no_reuse$extra" args="$args $local $quiet $no_reuse$extra"
names=$(git pack-objects --non-empty --all --reflog $args </dev/null "$PACKTMP") || names=$(git pack-objects --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
exit 1 exit 1
if [ -z "$names" ]; then if [ -z "$names" ]; then
if test -z "$quiet"; then if test -z "$quiet"; then

Просмотреть файл

@ -423,23 +423,30 @@ void prepare_alt_odb(void)
read_info_alternates(get_object_directory(), 0); read_info_alternates(get_object_directory(), 0);
} }
static int has_loose_object(const unsigned char *sha1) static int has_loose_object_local(const unsigned char *sha1)
{ {
char *name = sha1_file_name(sha1); char *name = sha1_file_name(sha1);
struct alternate_object_database *alt; return !access(name, F_OK);
}
if (!access(name, F_OK)) int has_loose_object_nonlocal(const unsigned char *sha1)
return 1; {
struct alternate_object_database *alt;
prepare_alt_odb(); prepare_alt_odb();
for (alt = alt_odb_list; alt; alt = alt->next) { for (alt = alt_odb_list; alt; alt = alt->next) {
name = alt->name; fill_sha1_path(alt->name, sha1);
fill_sha1_path(name, sha1);
if (!access(alt->base, F_OK)) if (!access(alt->base, F_OK))
return 1; return 1;
} }
return 0; return 0;
} }
static int has_loose_object(const unsigned char *sha1)
{
return has_loose_object_local(sha1) ||
has_loose_object_nonlocal(sha1);
}
static unsigned int pack_used_ctr; static unsigned int pack_used_ctr;
static unsigned int pack_mmap_calls; static unsigned int pack_mmap_calls;
static unsigned int peak_pack_open_windows; static unsigned int peak_pack_open_windows;
@ -841,6 +848,11 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
return NULL; return NULL;
} }
memcpy(p->pack_name, path, path_len); memcpy(p->pack_name, path, path_len);
strcpy(p->pack_name + path_len, ".keep");
if (!access(p->pack_name, F_OK))
p->pack_keep = 1;
strcpy(p->pack_name + path_len, ".pack"); strcpy(p->pack_name + path_len, ".pack");
if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) { if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) {
free(p); free(p);

73
t/t7700-repack.sh Executable file
Просмотреть файл

@ -0,0 +1,73 @@
#!/bin/sh
test_description='git repack works correctly'
. ./test-lib.sh
test_expect_success 'objects in packs marked .keep are not repacked' '
echo content1 > file1 &&
echo content2 > file2 &&
git add . &&
git commit -m initial_commit &&
# Create two packs
# The first pack will contain all of the objects except one
git rev-list --objects --all | grep -v file2 |
git pack-objects pack > /dev/null &&
# The second pack will contain the excluded object
packsha1=$(git rev-list --objects --all | grep file2 |
git pack-objects pack) &&
touch -r pack-$packsha1.pack pack-$packsha1.keep &&
objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 |
sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") &&
mv pack-* .git/objects/pack/ &&
git repack -A -d -l &&
git prune-packed &&
for p in .git/objects/pack/*.idx; do
idx=$(basename $p)
test "pack-$packsha1.idx" = "$idx" && continue
if git verify-pack -v $p | egrep "^$objsha1"; then
found_duplicate_object=1
echo "DUPLICATE OBJECT FOUND"
break
fi
done &&
test -z "$found_duplicate_object"
'
test_expect_success 'loose objects in alternate ODB are not repacked' '
mkdir alt_objects &&
echo `pwd`/alt_objects > .git/objects/info/alternates &&
echo content3 > file3 &&
objsha1=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) &&
git add file3 &&
git commit -m commit_file3 &&
git repack -a -d -l &&
git prune-packed &&
for p in .git/objects/pack/*.idx; do
if git verify-pack -v $p | egrep "^$objsha1"; then
found_duplicate_object=1
echo "DUPLICATE OBJECT FOUND"
break
fi
done &&
test -z "$found_duplicate_object"
'
test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' '
mkdir alt_objects/pack
mv .git/objects/pack/* alt_objects/pack &&
git repack -a &&
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_done