@@ -25,9 +25,84 @@ This edition covers what happened during the months of January and February 2026
2525### Reviews
2626-->
2727
28- <!-- -
28+
2929### Support
30- -->
30+
31+ * [ Slow git pack-refs --all] ( https://www.google.com/search?q=https://lore.kernel.org/git/CH3PR12MB9026B5872FD42F031970074BC2B3A%40CH3PR12MB9026.namprd12.prod.outlook.com )
32+
33+ Martin Fick started the discussion by reporting a significant
34+ performance issue where ` git pack-refs --all ` was taking over five
35+ minutes to complete on a large repository (~ 3M refs) hosted on an
36+ NFS filesystem. This delay was particularly problematic for Gerrit
37+ servers because Git holds the ` packed-refs.lock ` for nearly the
38+ entire duration, blocking other reference updates. Martin noted that
39+ JGit was able to perform the same operation in under 20 seconds on
40+ the same repository, suggesting the bottleneck was specific to the
41+ Git implementation.
42+
43+ The ` packed-refs ` file is used by Git to store a large number of
44+ references in a single sorted file to avoid the overhead of many
45+ small "loose" reference files. However, updating this file requires
46+ rewriting it entirely, and Git typically verifies that objects exist
47+ and "peels" tags (finding the underlying object a tag points to)
48+ during this process.
49+
50+ brian m. carlson replied to Martin, suggesting that the slowdown
51+ might be occurring in ` should_pack_ref() ` because Git needs to
52+ verify that the object at the end of a reference actually
53+ exists. Brian also pointed out that NFS was likely a major factor,
54+ as the network latency involved in opening many pack files and
55+ checking loose objects can be substantial. He suggested setting
56+ ` receive.unpackLimit ` to 1 to reduce the number of loose objects
57+ created in the first place.
58+
59+ Peff (alias Jeff King) explained that the ` packed-refs ` file stores
60+ "tag-peeling" information, which requires Git to open each object
61+ for newly written refs via ` peel_object() ` to read its header and
62+ determine its type. Peff noted that this logic resides in
63+ ` write_with_updates() ` within ` packed-backend.c ` .
64+
65+ Martin conducted further testing using ` strace ` and ` drop_caches ` to
66+ eliminate filesystem caching interference. He discovered that while
67+ the actual ` write() ` calls were fast, there were long gaps—up to
68+ four minutes in total—where the program was not making any system
69+ calls. Martin hypothesized that this "hidden" time was spent by the
70+ kernel handling page faults for ` mmap() ` ed memory over NFS.
71+
72+ Patrick Steinhardt concurred that NFS was frequently a source of
73+ such performance issues, mentioning that GitLab had eventually
74+ sunsetted the use of NFS for this reason. Patrick suggested using
75+ ` perf(1) ` to generate a flame graph to see exactly where the CPU was
76+ spending time.
77+
78+ Martin provided a summary of a flame graph, which showed about
79+ one-third of the time spent in ` _memcmp_sse4_1 ` and another third in
80+ ` unpack_object_header_buffer() ` , both accompanied by high page fault
81+ rates. He also noticed significant time spent in a function he
82+ identified as ` packed_refs_store_create() ` .
83+
84+ Peff corrected the function name to ` packed_ref_store_create() ` and
85+ noted that Git might be performing an extra linear pass through the
86+ ` packed-refs ` file if it lacks certain header tags. He discovered
87+ that JGit-generated files were missing the ` sorted ` and
88+ ` fully-peeled ` traits in the header. Without the ` sorted ` tag, Git
89+ reads the entire file linearly to verify its order before it can
90+ perform binary searches. Peff suggested that JGit should be updated
91+ to write these markers.
92+
93+ In a final breakthrough, Martin tested adding these tags
94+ manually. He found that while the ` sorted ` tag did not provide a
95+ major boost, adding the ` fully-peeled ` tag was the "trigger" that
96+ dropped the execution time from over five minutes to under four
97+ seconds. The absence of the ` fully-peeled ` tag was forcing Git to
98+ re-peel every reference by looking up the objects in the pack files
99+ over the slow NFS connection.
100+
101+ The discussion concluded with the identification of a specific
102+ interoperability issue between JGit and Git. By identifying that the
103+ missing ` fully-peeled ` header was causing redundant, expensive I/O
104+ operations, Martin was able to plan a fix for JGit that would
105+ resolve the performance bottleneck on his production servers.
31106
32107<!-- -
33108## Developer Spotlight:
0 commit comments