Skip to content

Commit 08cdfb1

Browse files
committed
pack-objects --keep-unreachable
This new option is meant to be used in conjunction with the options "git repack -a -d" usually invokes the underlying pack-objects with. When this option is given, objects unreachable from the refs in packs named with --unpacked= option are added to the resulting pack, in addition to the reachable objects that are not in packs marked with *.keep files. Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 000dfd3 commit 08cdfb1

File tree

1 file changed

+93
-2
lines changed

1 file changed

+93
-2
lines changed

builtin-pack-objects.c

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ git-pack-objects [{ -q | --progress | --all-progress }] \n\
2121
[--window=N] [--window-memory=N] [--depth=N] \n\
2222
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
2323
[--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
24-
[--stdout | base-name] [<ref-list | <object-list]";
24+
[--stdout | base-name] [--keep-unreachable] [<ref-list | <object-list]";
2525

2626
struct object_entry {
2727
struct pack_idx_entry idx;
@@ -57,7 +57,7 @@ static struct object_entry **written_list;
5757
static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
5858

5959
static int non_empty;
60-
static int no_reuse_delta, no_reuse_object;
60+
static int no_reuse_delta, no_reuse_object, keep_unreachable;
6161
static int local;
6262
static int incremental;
6363
static int allow_ofs_delta;
@@ -1625,22 +1625,106 @@ static void read_object_list_from_stdin(void)
16251625
}
16261626
}
16271627

1628+
#define OBJECT_ADDED (1u<<20)
1629+
16281630
static void show_commit(struct commit *commit)
16291631
{
16301632
add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
1633+
commit->object.flags |= OBJECT_ADDED;
16311634
}
16321635

16331636
static void show_object(struct object_array_entry *p)
16341637
{
16351638
add_preferred_base_object(p->name);
16361639
add_object_entry(p->item->sha1, p->item->type, p->name, 0);
1640+
p->item->flags |= OBJECT_ADDED;
16371641
}
16381642

16391643
static void show_edge(struct commit *commit)
16401644
{
16411645
add_preferred_base(commit->object.sha1);
16421646
}
16431647

1648+
struct in_pack_object {
1649+
off_t offset;
1650+
struct object *object;
1651+
};
1652+
1653+
struct in_pack {
1654+
int alloc;
1655+
int nr;
1656+
struct in_pack_object *array;
1657+
};
1658+
1659+
static void mark_in_pack_object(struct object *object, struct packed_git *p, struct in_pack *in_pack)
1660+
{
1661+
in_pack->array[in_pack->nr].offset = find_pack_entry_one(object->sha1, p);
1662+
in_pack->array[in_pack->nr].object = object;
1663+
in_pack->nr++;
1664+
}
1665+
1666+
/*
1667+
* Compare the objects in the offset order, in order to emulate the
1668+
* "git-rev-list --objects" output that produced the pack originally.
1669+
*/
1670+
static int ofscmp(const void *a_, const void *b_)
1671+
{
1672+
struct in_pack_object *a = (struct in_pack_object *)a_;
1673+
struct in_pack_object *b = (struct in_pack_object *)b_;
1674+
1675+
if (a->offset < b->offset)
1676+
return -1;
1677+
else if (a->offset > b->offset)
1678+
return 1;
1679+
else
1680+
return hashcmp(a->object->sha1, b->object->sha1);
1681+
}
1682+
1683+
static void add_objects_in_unpacked_packs(struct rev_info *revs)
1684+
{
1685+
struct packed_git *p;
1686+
struct in_pack in_pack;
1687+
uint32_t i;
1688+
1689+
memset(&in_pack, 0, sizeof(in_pack));
1690+
1691+
for (p = packed_git; p; p = p->next) {
1692+
const unsigned char *sha1;
1693+
struct object *o;
1694+
1695+
for (i = 0; i < revs->num_ignore_packed; i++) {
1696+
if (matches_pack_name(p, revs->ignore_packed[i]))
1697+
break;
1698+
}
1699+
if (revs->num_ignore_packed <= i)
1700+
continue;
1701+
if (open_pack_index(p))
1702+
die("cannot open pack index");
1703+
1704+
ALLOC_GROW(in_pack.array,
1705+
in_pack.nr + p->num_objects,
1706+
in_pack.alloc);
1707+
1708+
for (i = 0; i < p->num_objects; i++) {
1709+
sha1 = nth_packed_object_sha1(p, i);
1710+
o = lookup_unknown_object(sha1);
1711+
if (!(o->flags & OBJECT_ADDED))
1712+
mark_in_pack_object(o, p, &in_pack);
1713+
o->flags |= OBJECT_ADDED;
1714+
}
1715+
}
1716+
1717+
if (in_pack.nr) {
1718+
qsort(in_pack.array, in_pack.nr, sizeof(in_pack.array[0]),
1719+
ofscmp);
1720+
for (i = 0; i < in_pack.nr; i++) {
1721+
struct object *o = in_pack.array[i].object;
1722+
add_object_entry(o->sha1, o->type, "", 0);
1723+
}
1724+
}
1725+
free(in_pack.array);
1726+
}
1727+
16441728
static void get_object_list(int ac, const char **av)
16451729
{
16461730
struct rev_info revs;
@@ -1672,6 +1756,9 @@ static void get_object_list(int ac, const char **av)
16721756
prepare_revision_walk(&revs);
16731757
mark_edges_uninteresting(revs.commits, &revs, show_edge);
16741758
traverse_commit_list(&revs, show_commit, show_object);
1759+
1760+
if (keep_unreachable)
1761+
add_objects_in_unpacked_packs(&revs);
16751762
}
16761763

16771764
static int adjust_perm(const char *path, mode_t mode)
@@ -1789,6 +1876,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
17891876
use_internal_rev_list = 1;
17901877
continue;
17911878
}
1879+
if (!strcmp("--keep-unreachable", arg)) {
1880+
keep_unreachable = 1;
1881+
continue;
1882+
}
17921883
if (!strcmp("--unpacked", arg) ||
17931884
!prefixcmp(arg, "--unpacked=") ||
17941885
!strcmp("--reflog", arg) ||

0 commit comments

Comments
 (0)