Skip to content

Commit c90f9e1

Browse files
peffgitster
authored andcommitted
repack: pack objects mentioned by the index
When we pack all objects, we use only the objects reachable from references and reflogs. This misses any objects which are reachable from the index, but not yet referenced. By itself this isn't a big deal; the objects can remain loose until they are actually used in a commit. However, it does create a problem when we drop packed but unreachable objects. We try to optimize out the writing of objects that we will immediately prune, which means we must follow the same rules as prune in determining what is reachable. And prune uses the index for this purpose. This is rather uncommon in practice, as objects in the index would not usually have been packed in the first place. But it could happen in a sequence like: 1. You make a commit on a branch that references blob X. 2. You repack, moving X into the pack. 3. You delete the branch (and its reflog), so that X is unreferenced. 4. You "git add" blob X so that it is now referenced only by the index. 5. You repack again with git-gc. The pack-objects we invoke will see that X is neither referenced nor recent and not bother loosening it. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent edfbb2a commit c90f9e1

File tree

3 files changed

+22
-0
lines changed

3 files changed

+22
-0
lines changed

builtin/pack-objects.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2617,6 +2617,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
26172617
int all_progress_implied = 0;
26182618
struct argv_array rp = ARGV_ARRAY_INIT;
26192619
int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
2620+
int rev_list_index = 0;
26202621
struct option pack_objects_options[] = {
26212622
OPT_SET_INT('q', "quiet", &progress,
26222623
N_("do not show progress meter"), 0),
@@ -2663,6 +2664,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
26632664
{ OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
26642665
N_("include objects referred by reflog entries"),
26652666
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
2667+
{ OPTION_SET_INT, 0, "indexed-objects", &rev_list_index, NULL,
2668+
N_("include objects referred to by the index"),
2669+
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
26662670
OPT_BOOL(0, "stdout", &pack_to_stdout,
26672671
N_("output pack to stdout")),
26682672
OPT_BOOL(0, "include-tag", &include_tag,
@@ -2720,6 +2724,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
27202724
use_internal_rev_list = 1;
27212725
argv_array_push(&rp, "--reflog");
27222726
}
2727+
if (rev_list_index) {
2728+
use_internal_rev_list = 1;
2729+
argv_array_push(&rp, "--indexed-objects");
2730+
}
27232731
if (rev_list_unpacked) {
27242732
use_internal_rev_list = 1;
27252733
argv_array_push(&rp, "--unpacked");

builtin/repack.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
209209
argv_array_push(&cmd_args, "--non-empty");
210210
argv_array_push(&cmd_args, "--all");
211211
argv_array_push(&cmd_args, "--reflog");
212+
argv_array_push(&cmd_args, "--indexed-objects");
212213
if (window)
213214
argv_array_pushf(&cmd_args, "--window=%s", window);
214215
if (window_memory)

t/t7701-repack-unpack-unreachable.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,17 @@ test_expect_success 'do not bother loosening old objects' '
109109
test_must_fail git cat-file -p $obj2
110110
'
111111

112+
test_expect_success 'keep packed objects found only in index' '
113+
echo my-unique-content >file &&
114+
git add file &&
115+
git commit -m "make it reachable" &&
116+
git gc &&
117+
git reset HEAD^ &&
118+
git reflog expire --expire=now --all &&
119+
git add file &&
120+
test-chmtime =-86400 .git/objects/pack/* &&
121+
git gc --prune=1.hour.ago &&
122+
git cat-file blob :file
123+
'
124+
112125
test_done

0 commit comments

Comments
 (0)