Skip to content

Commit 0fd9d7e

Browse files
committed
Merge branch 'bc/maint-keep-pack' into maint
* bc/maint-keep-pack: repack: only unpack-unreachable if we are deleting redundant packs 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
2 parents e23f682 + 83d0289 commit 0fd9d7e

File tree

9 files changed

+137
-36
lines changed

9 files changed

+137
-36
lines changed

Documentation/git-pack-objects.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,19 @@ base-name::
109109
The default is unlimited, unless the config variable
110110
`pack.packSizeLimit` is set.
111111

112+
--honor-pack-keep::
113+
This flag causes an object already in a local pack that
114+
has a .keep file to be ignored, even if it appears in the
115+
standard input.
116+
112117
--incremental::
113118
This flag causes an object already in a pack ignored
114119
even if it appears in the standard input.
115120

116121
--local::
117122
This flag is similar to `--incremental`; instead of
118123
ignoring all packed objects, it only ignores objects
119-
that are packed and not in the local object store
124+
that are packed and/or not in the local object store
120125
(i.e. borrowed from an alternate).
121126

122127
--non-empty::

Documentation/git-repack.txt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,11 @@ OPTIONS
3838
dangling.
3939

4040
-A::
41-
Same as `-a`, but any unreachable objects in a previous
42-
pack become loose, unpacked objects, instead of being
43-
left in the old pack. Unreachable objects are never
44-
intentionally added to a pack, even when repacking.
45-
When used with '-d', this option
46-
prevents unreachable objects from being immediately
41+
Same as `-a`, unless '-d' is used. Then any unreachable
42+
objects in a previous pack become loose, unpacked objects,
43+
instead of being left in the old pack. Unreachable objects
44+
are never intentionally added to a pack, even when repacking.
45+
This option prevents unreachable objects from being immediately
4746
deleted by way of being left in the old pack and then
4847
removed. Instead, the loose unreachable objects
4948
will be pruned according to normal expiry rules

builtin-gc.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,9 @@ static int too_many_packs(void)
134134

135135
prepare_packed_git();
136136
for (cnt = 0, p = packed_git; p; p = p->next) {
137-
char path[PATH_MAX];
138-
size_t len;
139-
int keep;
140-
141137
if (!p->pack_local)
142138
continue;
143-
len = strlen(p->pack_name);
144-
if (PATH_MAX <= len + 1)
145-
continue; /* oops, give up */
146-
memcpy(path, p->pack_name, len-5);
147-
memcpy(path + len - 5, ".keep", 6);
148-
keep = access(p->pack_name, F_OK) && (errno == ENOENT);
149-
if (keep)
139+
if (p->pack_keep)
150140
continue;
151141
/*
152142
* Perhaps check the size of the pack and count only

builtin-pack-objects.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ static int reuse_delta = 1, reuse_object = 1;
7171
static int keep_unreachable, unpack_unreachable, include_tag;
7272
static int local;
7373
static int incremental;
74+
static int ignore_packed_keep;
7475
static int allow_ofs_delta;
7576
static const char *base_name;
7677
static int progress = 1;
@@ -698,6 +699,9 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
698699
return 0;
699700
}
700701

702+
if (!exclude && local && has_loose_object_nonlocal(sha1))
703+
return 0;
704+
701705
for (p = packed_git; p; p = p->next) {
702706
off_t offset = find_pack_entry_one(sha1, p);
703707
if (offset) {
@@ -711,6 +715,8 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
711715
return 0;
712716
if (local && !p->pack_local)
713717
return 0;
718+
if (ignore_packed_keep && p->pack_local && p->pack_keep)
719+
return 0;
714720
}
715721
}
716722

@@ -2050,6 +2056,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
20502056
incremental = 1;
20512057
continue;
20522058
}
2059+
if (!strcmp("--honor-pack-keep", arg)) {
2060+
ignore_packed_keep = 1;
2061+
continue;
2062+
}
20532063
if (!prefixcmp(arg, "--compression=")) {
20542064
char *end;
20552065
int level = strtoul(arg+14, &end, 0);

cache.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ extern int move_temp_to_file(const char *tmpfile, const char *filename);
567567

568568
extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
569569
extern int has_sha1_file(const unsigned char *sha1);
570+
extern int has_loose_object_nonlocal(const unsigned char *sha1);
570571

571572
extern int has_pack_file(const unsigned char *sha1);
572573
extern int has_pack_index(const unsigned char *sha1);
@@ -673,7 +674,8 @@ extern struct packed_git {
673674
int index_version;
674675
time_t mtime;
675676
int pack_fd;
676-
int pack_local;
677+
unsigned pack_local:1,
678+
pack_keep:1;
677679
unsigned char sha1[20];
678680
/* something like ".git/objects/pack/xxxxx.pack" */
679681
char pack_name[FLEX_ARRAY]; /* more */

git-repack.sh

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,17 @@ case ",$all_into_one," in
7171
existing="$existing $e"
7272
fi
7373
done
74-
fi
75-
if test -z "$args"
76-
then
77-
args='--unpacked --incremental'
78-
elif test -n "$unpack_unreachable"
79-
then
80-
args="$args $unpack_unreachable"
74+
if test -n "$args" -a -n "$unpack_unreachable" -a \
75+
-n "$remove_redundant"
76+
then
77+
args="$args $unpack_unreachable"
78+
fi
8179
fi
8280
;;
8381
esac
8482

8583
args="$args $local $quiet $no_reuse$extra"
86-
names=$(git pack-objects --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
84+
names=$(git pack-objects --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
8785
exit 1
8886
if [ -z "$names" ]; then
8987
if test -z "$quiet"; then

sha1_file.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -410,23 +410,30 @@ void prepare_alt_odb(void)
410410
read_info_alternates(get_object_directory(), 0);
411411
}
412412

413-
static int has_loose_object(const unsigned char *sha1)
413+
static int has_loose_object_local(const unsigned char *sha1)
414414
{
415415
char *name = sha1_file_name(sha1);
416-
struct alternate_object_database *alt;
416+
return !access(name, F_OK);
417+
}
417418

418-
if (!access(name, F_OK))
419-
return 1;
419+
int has_loose_object_nonlocal(const unsigned char *sha1)
420+
{
421+
struct alternate_object_database *alt;
420422
prepare_alt_odb();
421423
for (alt = alt_odb_list; alt; alt = alt->next) {
422-
name = alt->name;
423-
fill_sha1_path(name, sha1);
424+
fill_sha1_path(alt->name, sha1);
424425
if (!access(alt->base, F_OK))
425426
return 1;
426427
}
427428
return 0;
428429
}
429430

431+
static int has_loose_object(const unsigned char *sha1)
432+
{
433+
return has_loose_object_local(sha1) ||
434+
has_loose_object_nonlocal(sha1);
435+
}
436+
430437
static unsigned int pack_used_ctr;
431438
static unsigned int pack_mmap_calls;
432439
static unsigned int peak_pack_open_windows;
@@ -828,6 +835,11 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
828835
return NULL;
829836
}
830837
memcpy(p->pack_name, path, path_len);
838+
839+
strcpy(p->pack_name + path_len, ".keep");
840+
if (!access(p->pack_name, F_OK))
841+
p->pack_keep = 1;
842+
831843
strcpy(p->pack_name + path_len, ".pack");
832844
if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) {
833845
free(p);

t/t7700-repack.sh

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/bin/sh
2+
3+
test_description='git repack works correctly'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success 'objects in packs marked .keep are not repacked' '
8+
echo content1 > file1 &&
9+
echo content2 > file2 &&
10+
git add . &&
11+
git commit -m initial_commit &&
12+
# Create two packs
13+
# The first pack will contain all of the objects except one
14+
git rev-list --objects --all | grep -v file2 |
15+
git pack-objects pack > /dev/null &&
16+
# The second pack will contain the excluded object
17+
packsha1=$(git rev-list --objects --all | grep file2 |
18+
git pack-objects pack) &&
19+
touch -r pack-$packsha1.pack pack-$packsha1.keep &&
20+
objsha1=$(git verify-pack -v pack-$packsha1.idx | head -n 1 |
21+
sed -e "s/^\([0-9a-f]\{40\}\).*/\1/") &&
22+
mv pack-* .git/objects/pack/ &&
23+
git repack -A -d -l &&
24+
git prune-packed &&
25+
for p in .git/objects/pack/*.idx; do
26+
idx=$(basename $p)
27+
test "pack-$packsha1.idx" = "$idx" && continue
28+
if git verify-pack -v $p | egrep "^$objsha1"; then
29+
found_duplicate_object=1
30+
echo "DUPLICATE OBJECT FOUND"
31+
break
32+
fi
33+
done &&
34+
test -z "$found_duplicate_object"
35+
'
36+
37+
test_expect_success 'loose objects in alternate ODB are not repacked' '
38+
mkdir alt_objects &&
39+
echo `pwd`/alt_objects > .git/objects/info/alternates &&
40+
echo content3 > file3 &&
41+
objsha1=$(GIT_OBJECT_DIRECTORY=alt_objects git hash-object -w file3) &&
42+
git add file3 &&
43+
git commit -m commit_file3 &&
44+
git repack -a -d -l &&
45+
git prune-packed &&
46+
for p in .git/objects/pack/*.idx; do
47+
if git verify-pack -v $p | egrep "^$objsha1"; then
48+
found_duplicate_object=1
49+
echo "DUPLICATE OBJECT FOUND"
50+
break
51+
fi
52+
done &&
53+
test -z "$found_duplicate_object"
54+
'
55+
56+
test_expect_success 'packed obs in alt ODB are repacked even when local repo is packless' '
57+
mkdir alt_objects/pack
58+
mv .git/objects/pack/* alt_objects/pack &&
59+
git repack -a &&
60+
myidx=$(ls -1 .git/objects/pack/*.idx) &&
61+
test -f "$myidx" &&
62+
for p in alt_objects/pack/*.idx; do
63+
git verify-pack -v $p | sed -n -e "/^[0-9a-f]\{40\}/p"
64+
done | while read sha1 rest; do
65+
if ! ( git verify-pack -v $myidx | grep "^$sha1" ); then
66+
echo "Missing object in local pack: $sha1"
67+
return 1
68+
fi
69+
done
70+
'
71+
72+
test_done
73+

t/t7701-repack-unpack-unreachable.sh

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fsha1=
88
csha1=
99
tsha1=
1010

11-
test_expect_success '-A option leaves unreachable objects unpacked' '
11+
test_expect_success '-A with -d option leaves unreachable objects unpacked' '
1212
echo content > file1 &&
1313
git add . &&
1414
git commit -m initial_commit &&
@@ -58,7 +58,7 @@ compare_mtimes ()
5858
' -- "$@"
5959
}
6060

61-
test_expect_success 'unpacked objects receive timestamp of pack file' '
61+
test_expect_success '-A without -d option leaves unreachable objects packed' '
6262
fsha1path=$(echo "$fsha1" | sed -e "s|\(..\)|\1/|") &&
6363
fsha1path=".git/objects/$fsha1path" &&
6464
csha1path=$(echo "$csha1" | sed -e "s|\(..\)|\1/|") &&
@@ -75,7 +75,19 @@ test_expect_success 'unpacked objects receive timestamp of pack file' '
7575
git branch -D transient_branch &&
7676
sleep 1 &&
7777
git repack -A -l &&
78-
compare_mtimes "$packfile" "$fsha1path" "$csha1path" "$tsha1path"
78+
test ! -f "$fsha1path" &&
79+
test ! -f "$csha1path" &&
80+
test ! -f "$tsha1path" &&
81+
git show $fsha1 &&
82+
git show $csha1 &&
83+
git show $tsha1
84+
'
85+
86+
test_expect_success 'unpacked objects receive timestamp of pack file' '
87+
tmppack=".git/objects/pack/tmp_pack" &&
88+
ln "$packfile" "$tmppack" &&
89+
git repack -A -l -d &&
90+
compare_mtimes "$tmppack" "$fsha1path" "$csha1path" "$tsha1path"
7991
'
8092

8193
test_done

0 commit comments

Comments
 (0)