@@ -206,6 +206,7 @@ static int have_non_local_packs;
206206static int incremental ;
207207static int ignore_packed_keep_on_disk ;
208208static int ignore_packed_keep_in_core ;
209+ static int ignore_packed_keep_in_core_has_cruft ;
209210static int allow_ofs_delta ;
210211static struct pack_idx_option pack_idx_opts ;
211212static const char * base_name ;
@@ -1502,8 +1503,60 @@ static int have_duplicate_entry(const struct object_id *oid,
15021503 return 1 ;
15031504}
15041505
1506+ static int want_cruft_object_mtime (struct repository * r ,
1507+ const struct object_id * oid ,
1508+ unsigned flags , uint32_t mtime )
1509+ {
1510+ struct packed_git * * cache ;
1511+
1512+ for (cache = kept_pack_cache (r , flags ); * cache ; cache ++ ) {
1513+ struct packed_git * p = * cache ;
1514+ off_t ofs ;
1515+ uint32_t candidate_mtime ;
1516+
1517+ ofs = find_pack_entry_one (oid , p );
1518+ if (!ofs )
1519+ continue ;
1520+
1521+ /*
1522+ * We have a copy of the object 'oid' in a non-cruft
1523+ * pack. We can avoid packing an additional copy
1524+ * regardless of what the existing copy's mtime is since
1525+ * it is outside of a cruft pack.
1526+ */
1527+ if (!p -> is_cruft )
1528+ return 0 ;
1529+
1530+ /*
1531+ * If we have a copy of the object 'oid' in a cruft
1532+ * pack, then either read the cruft pack's mtime for
1533+ * that object, or, if that can't be loaded, assume the
1534+ * pack's mtime itself.
1535+ */
1536+ if (!load_pack_mtimes (p )) {
1537+ uint32_t pos ;
1538+ if (offset_to_pack_pos (p , ofs , & pos ) < 0 )
1539+ continue ;
1540+ candidate_mtime = nth_packed_mtime (p , pos );
1541+ } else {
1542+ candidate_mtime = p -> mtime ;
1543+ }
1544+
1545+ /*
1546+ * We have a surviving copy of the object in a cruft
1547+ * pack whose mtime is greater than or equal to the one
1548+ * we are considering. We can thus avoid packing an
1549+ * additional copy of that object.
1550+ */
1551+ if (mtime <= candidate_mtime )
1552+ return 0 ;
1553+ }
1554+
1555+ return -1 ;
1556+ }
1557+
15051558static int want_found_object (const struct object_id * oid , int exclude ,
1506- struct packed_git * p )
1559+ struct packed_git * p , uint32_t mtime )
15071560{
15081561 if (exclude )
15091562 return 1 ;
@@ -1553,12 +1606,29 @@ static int want_found_object(const struct object_id *oid, int exclude,
15531606 if (ignore_packed_keep_in_core )
15541607 flags |= IN_CORE_KEEP_PACKS ;
15551608
1556- if (ignore_packed_keep_on_disk && p -> pack_keep )
1557- return 0 ;
1558- if (ignore_packed_keep_in_core && p -> pack_keep_in_core )
1559- return 0 ;
1560- if (has_object_kept_pack (p -> repo , oid , flags ))
1561- return 0 ;
1609+ /*
1610+ * If the object is in a pack that we want to ignore, *and* we
1611+ * don't have any cruft packs that are being retained, we can
1612+ * abort quickly.
1613+ */
1614+ if (!ignore_packed_keep_in_core_has_cruft ) {
1615+ if (ignore_packed_keep_on_disk && p -> pack_keep )
1616+ return 0 ;
1617+ if (ignore_packed_keep_in_core && p -> pack_keep_in_core )
1618+ return 0 ;
1619+ if (has_object_kept_pack (p -> repo , oid , flags ))
1620+ return 0 ;
1621+ } else {
1622+ /*
1623+ * But if there is at least one cruft pack which
1624+ * is being kept, we only want to include the
1625+ * provided object if it has a strictly greater
1626+ * mtime than any existing cruft copy.
1627+ */
1628+ if (!want_cruft_object_mtime (p -> repo , oid , flags ,
1629+ mtime ))
1630+ return 0 ;
1631+ }
15621632 }
15631633
15641634 /*
@@ -1577,7 +1647,8 @@ static int want_object_in_pack_one(struct packed_git *p,
15771647 const struct object_id * oid ,
15781648 int exclude ,
15791649 struct packed_git * * found_pack ,
1580- off_t * found_offset )
1650+ off_t * found_offset ,
1651+ uint32_t found_mtime )
15811652{
15821653 off_t offset ;
15831654
@@ -1593,7 +1664,7 @@ static int want_object_in_pack_one(struct packed_git *p,
15931664 * found_offset = offset ;
15941665 * found_pack = p ;
15951666 }
1596- return want_found_object (oid , exclude , p );
1667+ return want_found_object (oid , exclude , p , found_mtime );
15971668 }
15981669 return -1 ;
15991670}
@@ -1607,10 +1678,11 @@ static int want_object_in_pack_one(struct packed_git *p,
16071678 * function finds if there is any pack that has the object and returns the pack
16081679 * and its offset in these variables.
16091680 */
1610- static int want_object_in_pack (const struct object_id * oid ,
1611- int exclude ,
1612- struct packed_git * * found_pack ,
1613- off_t * found_offset )
1681+ static int want_object_in_pack_mtime (const struct object_id * oid ,
1682+ int exclude ,
1683+ struct packed_git * * found_pack ,
1684+ off_t * found_offset ,
1685+ uint32_t found_mtime )
16141686{
16151687 int want ;
16161688 struct list_head * pos ;
@@ -1625,7 +1697,8 @@ static int want_object_in_pack(const struct object_id *oid,
16251697 * are present we will determine the answer right now.
16261698 */
16271699 if (* found_pack ) {
1628- want = want_found_object (oid , exclude , * found_pack );
1700+ want = want_found_object (oid , exclude , * found_pack ,
1701+ found_mtime );
16291702 if (want != -1 )
16301703 return want ;
16311704
@@ -1636,15 +1709,15 @@ static int want_object_in_pack(const struct object_id *oid,
16361709 for (m = get_multi_pack_index (the_repository ); m ; m = m -> next ) {
16371710 struct pack_entry e ;
16381711 if (fill_midx_entry (the_repository , oid , & e , m )) {
1639- want = want_object_in_pack_one (e .p , oid , exclude , found_pack , found_offset );
1712+ want = want_object_in_pack_one (e .p , oid , exclude , found_pack , found_offset , found_mtime );
16401713 if (want != -1 )
16411714 return want ;
16421715 }
16431716 }
16441717
16451718 list_for_each (pos , get_packed_git_mru (the_repository )) {
16461719 struct packed_git * p = list_entry (pos , struct packed_git , mru );
1647- want = want_object_in_pack_one (p , oid , exclude , found_pack , found_offset );
1720+ want = want_object_in_pack_one (p , oid , exclude , found_pack , found_offset , found_mtime );
16481721 if (!exclude && want > 0 )
16491722 list_move (& p -> mru ,
16501723 get_packed_git_mru (the_repository ));
@@ -1674,6 +1747,15 @@ static int want_object_in_pack(const struct object_id *oid,
16741747 return 1 ;
16751748}
16761749
1750+ static inline int want_object_in_pack (const struct object_id * oid ,
1751+ int exclude ,
1752+ struct packed_git * * found_pack ,
1753+ off_t * found_offset )
1754+ {
1755+ return want_object_in_pack_mtime (oid , exclude , found_pack , found_offset ,
1756+ 0 );
1757+ }
1758+
16771759static struct object_entry * create_object_entry (const struct object_id * oid ,
16781760 enum object_type type ,
16791761 uint32_t hash ,
@@ -3606,7 +3688,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
36063688 entry -> no_try_delta = no_try_delta (name );
36073689 }
36083690 } else {
3609- if (!want_object_in_pack (oid , 0 , & pack , & offset ))
3691+ if (!want_object_in_pack_mtime (oid , 0 , & pack , & offset , mtime ))
36103692 return ;
36113693 if (!pack && type == OBJ_BLOB && !has_loose_object (oid )) {
36123694 /*
@@ -3680,6 +3762,8 @@ static void mark_pack_kept_in_core(struct string_list *packs, unsigned keep)
36803762 struct packed_git * p = item -> util ;
36813763 if (!p )
36823764 die (_ ("could not find pack '%s'" ), item -> string );
3765+ if (p -> is_cruft && keep )
3766+ ignore_packed_keep_in_core_has_cruft = 1 ;
36833767 p -> pack_keep_in_core = keep ;
36843768 }
36853769}
0 commit comments