зеркало из https://github.com/microsoft/git.git
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:
Коммит
ecbbfb15a4
|
@ -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::
|
||||||
|
|
12
builtin-gc.c
12
builtin-gc.c
|
@ -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);
|
||||||
|
|
4
cache.h
4
cache.h
|
@ -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
|
||||||
|
|
24
sha1_file.c
24
sha1_file.c
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче