@@ -206,6 +206,7 @@ static int have_non_local_packs;
206
206
static int incremental ;
207
207
static int ignore_packed_keep_on_disk ;
208
208
static int ignore_packed_keep_in_core ;
209
+ static int ignore_packed_keep_in_core_has_cruft ;
209
210
static int allow_ofs_delta ;
210
211
static struct pack_idx_option pack_idx_opts ;
211
212
static const char * base_name ;
@@ -1502,8 +1503,60 @@ static int have_duplicate_entry(const struct object_id *oid,
1502
1503
return 1 ;
1503
1504
}
1504
1505
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
+
1505
1558
static int want_found_object (const struct object_id * oid , int exclude ,
1506
- struct packed_git * p )
1559
+ struct packed_git * p , uint32_t mtime )
1507
1560
{
1508
1561
if (exclude )
1509
1562
return 1 ;
@@ -1553,12 +1606,29 @@ static int want_found_object(const struct object_id *oid, int exclude,
1553
1606
if (ignore_packed_keep_in_core )
1554
1607
flags |= IN_CORE_KEEP_PACKS ;
1555
1608
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
+ }
1562
1632
}
1563
1633
1564
1634
/*
@@ -1577,7 +1647,8 @@ static int want_object_in_pack_one(struct packed_git *p,
1577
1647
const struct object_id * oid ,
1578
1648
int exclude ,
1579
1649
struct packed_git * * found_pack ,
1580
- off_t * found_offset )
1650
+ off_t * found_offset ,
1651
+ uint32_t found_mtime )
1581
1652
{
1582
1653
off_t offset ;
1583
1654
@@ -1593,7 +1664,7 @@ static int want_object_in_pack_one(struct packed_git *p,
1593
1664
* found_offset = offset ;
1594
1665
* found_pack = p ;
1595
1666
}
1596
- return want_found_object (oid , exclude , p );
1667
+ return want_found_object (oid , exclude , p , found_mtime );
1597
1668
}
1598
1669
return -1 ;
1599
1670
}
@@ -1607,10 +1678,11 @@ static int want_object_in_pack_one(struct packed_git *p,
1607
1678
* function finds if there is any pack that has the object and returns the pack
1608
1679
* and its offset in these variables.
1609
1680
*/
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 )
1614
1686
{
1615
1687
int want ;
1616
1688
struct list_head * pos ;
@@ -1625,7 +1697,8 @@ static int want_object_in_pack(const struct object_id *oid,
1625
1697
* are present we will determine the answer right now.
1626
1698
*/
1627
1699
if (* found_pack ) {
1628
- want = want_found_object (oid , exclude , * found_pack );
1700
+ want = want_found_object (oid , exclude , * found_pack ,
1701
+ found_mtime );
1629
1702
if (want != -1 )
1630
1703
return want ;
1631
1704
@@ -1636,15 +1709,15 @@ static int want_object_in_pack(const struct object_id *oid,
1636
1709
for (m = get_multi_pack_index (the_repository ); m ; m = m -> next ) {
1637
1710
struct pack_entry e ;
1638
1711
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 );
1640
1713
if (want != -1 )
1641
1714
return want ;
1642
1715
}
1643
1716
}
1644
1717
1645
1718
list_for_each (pos , get_packed_git_mru (the_repository )) {
1646
1719
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 );
1648
1721
if (!exclude && want > 0 )
1649
1722
list_move (& p -> mru ,
1650
1723
get_packed_git_mru (the_repository ));
@@ -1674,6 +1747,15 @@ static int want_object_in_pack(const struct object_id *oid,
1674
1747
return 1 ;
1675
1748
}
1676
1749
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
+
1677
1759
static struct object_entry * create_object_entry (const struct object_id * oid ,
1678
1760
enum object_type type ,
1679
1761
uint32_t hash ,
@@ -3606,7 +3688,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
3606
3688
entry -> no_try_delta = no_try_delta (name );
3607
3689
}
3608
3690
} else {
3609
- if (!want_object_in_pack (oid , 0 , & pack , & offset ))
3691
+ if (!want_object_in_pack_mtime (oid , 0 , & pack , & offset , mtime ))
3610
3692
return ;
3611
3693
if (!pack && type == OBJ_BLOB && !has_loose_object (oid )) {
3612
3694
/*
@@ -3680,6 +3762,8 @@ static void mark_pack_kept_in_core(struct string_list *packs, unsigned keep)
3680
3762
struct packed_git * p = item -> util ;
3681
3763
if (!p )
3682
3764
die (_ ("could not find pack '%s'" ), item -> string );
3765
+ if (p -> is_cruft && keep )
3766
+ ignore_packed_keep_in_core_has_cruft = 1 ;
3683
3767
p -> pack_keep_in_core = keep ;
3684
3768
}
3685
3769
}
0 commit comments