@@ -49,9 +49,260 @@ This edition covers what happened during the months of April and May 2026.
4949### Reviews
5050-->
5151
52- <!-- -
5352### Support
54- -->
53+
54+ + [ MIDX woes, was Re: [ ANNOUNCE] Git v2.54.0-rc2] ( https://lore.kernel.org/git/8c1def10-9039-aecd-4ce4-fb4676b47e9b@gmx.de )
55+
56+ Shortly after the ` v2.54.0-rc2 ` release candidate was announced,
57+ Johannes Schindelin, the Git for Windows maintainer who is usually
58+ called Dscho, wrote a follow-up to the announcement, retitled "MIDX
59+ woes", to report an unpleasant discovery: fetching with
60+ ` v2.54.0-rc2 ` into an existing repository made that repository
61+ unusable for Git ` v2.53.0 ` , which would now bail out with:
62+
63+ ```
64+ fatal: multi-pack-index version 2 not recognized
65+ ```
66+
67+ Dscho asked whether ` v2.54.0-rc2 ` was forcefully writing a brand-new
68+ MIDX version that the immediately preceding release could not even
69+ read. He pointed out that, if so, this would cause "substantial
70+ problems" in setups where libgit2 or JGit is used interchangeably
71+ with Git, when users need to downgrade Git, or when several Git
72+ versions live side by side on the same system, for instance through
73+ GitHub Desktop, which bundles its own copy of Git.
74+
75+ The multi-pack-index (MIDX) is an on-disk file at
76+ ` .git/objects/pack/multi-pack-index ` (and possibly chained files)
77+ that indexes objects across several pack files at once. It is meant
78+ to be a purely optional acceleration layer: when present and
79+ readable, lookups can avoid scanning each pack's own ` .idx ` index
80+ file; when absent or unreadable, Git is supposed to fall back to the
81+ underlying ` .idx ` files. Several high-impact features (auto
82+ maintenance, ` git multi-pack-index ` , reachability bitmaps, geometric
83+ repack, etc.) build on top of it, and modern Git distributions
84+ write or update it as part of routine operations, including the
85+ maintenance step that runs after a ` git fetch ` .
86+
87+ The "version 2 not recognized" error came from ` b2ec8e90c2 ` (`midx:
88+ do not require packs to be sorted in lexicographic order`,
89+ 2026-02-24). That commit relaxed an internal ordering constraint
90+ and, because the relaxation makes the on-disk file unreadable by
91+ other tools that still expect the older invariant, guarded the new
92+ behaviour behind a bump in the MIDX on-disk format version (from v1
93+ to v2). The commit message explicitly justified the bump by claiming
94+ that "older versions of Git know how to gracefully degrade and
95+ ignore any MIDX(s) they consider corrupt". As the discussion would
96+ reveal, this assumption turned out to be too optimistic.
97+
98+ Junio Hamano, the Git maintainer, picked up the thread and pointed
99+ directly at ` b2ec8e90c2 ` as the likely culprit. Reading the commit
100+ message back to itself, he observed that the format-version bump
101+ "seems to be doing more harm to 'older versions of Git' that 'know
102+ how to gracefully degrade' by not allowing them to degrade", and he
103+ asked Taylor Blau (the author of the MIDX v2 work and the area's
104+ principal maintainer) whether the release notes should at least
105+ carry recovery instructions, such as ` rm -f .git/objects/pack/*.midx ` .
106+
107+ Jeff King, alias Peff, replied within hours with a deeper
108+ diagnosis. The MIDX * should* be optional, he wrote. If loading the
109+ file returns an error, callers should silently fall back to the
110+ regular ` .idx ` files, but that property is not actually held by the
111+ load path, which contains a few ` die() ` calls instead. He
112+ demonstrated by applying a small patch on top of v2.53.0 that
113+ replaces the two relevant ` die() ` calls in
114+ ` load_multi_pack_index_one() ` (one for the signature mismatch, one
115+ for the unknown version) with ` error() ` plus a ` goto cleanup_fail ` ,
116+ producing the desired behaviour: the user sees `version 2 not
117+ recognized` printed once and then everything works anyway. "But of
118+ course we can't go back in time now to fix it (and earlier
119+ versions)", he noted.
120+
121+ Peff also surveyed the third-party implementations Dscho had worried
122+ about:
123+
124+ - JGit, on inspection of its source, throws an exception that is
125+ apparently caught and handled correctly (he verified with the
126+ ` jgit ` CLI on hand).
127+ - libgit2 returns from a helper called ` midx_error() ` when the
128+ signature or version do not match. Reading the code, Peff
129+ believed it would quietly fall back to the underlying packs.
130+
131+ His conclusion: "it really is just our old versions that are the
132+ problem".
133+
134+ He then asked the natural follow-up question: how hard would it be
135+ to revert the default written MIDX version back to v1? In a second
136+ message a few minutes later he answered himself with a
137+ near-one-liner in ` midx-write.c ` changing the default initializer of
138+ ` write_midx_context.version ` from ` MIDX_VERSION_V2 ` to
139+ ` MIDX_VERSION_V1 ` , plus minor adjustments to the test suite: in
140+ ` t/t5319-multi-pack-index.sh ` , the expected header would once again
141+ say "header: ... 1 ..." rather than "header: ... 2 ..."; and in
142+ ` t/t5335-compact-multi-pack-index.sh ` , since MIDX compaction
143+ * requires* the v2 format, the test would now opt back into v2
144+ explicitly via ` git config --global midx.version 2 ` . Peff observed
145+ that an existing ` midx.version ` config knob lets users opt into v2
146+ manually, and he left the strategic decision to Taylor.
147+
148+ Derrick Stolee underlined the part of Dscho's report that he
149+ considered most striking: the bad file is written automatically as
150+ part of normal maintenance after a fetch, so removing the broken
151+ MIDX by hand "will not keep the repo in a good state". The next
152+ fetch will simply regenerate it. He agreed that a graceful fallback
153+ (with a visible warning) belongs in Git too, and that the immediate
154+ fix should be to stop writing v2 by default so that a 2.53/2.54
155+ mixed deployment stops poisoning the repository at every fetch.
156+
157+ Junio, after asking Derrick to clarify the "good state" sentence (he
158+ initially read it as "the MIDX is no longer optional"), eventually
159+ agreed: defaulting back to v1 * and* leaving the more thorough
160+ graceful-degradation work for later was the right split for the
161+ remaining rc window. In a later round of the same sub-thread,
162+ Derrick clarified that what he had meant was that the deletion was
163+ not a * durable* fix on its own. The maintenance step would keep
164+ regenerating the v2 file unless the default version was also lowered
165+ (or ` midx.version ` set to ` 1 ` ).
166+
167+ Taylor Blau then weighed in, apologetic about the "trouble here", and
168+ laid out a clean three-step plan for the project:
169+
170+ 1 . ** Immediate (before 2.54)** : revert the default MIDX format to
171+ V1, so a 2.54.0 release does not regress the case where multiple
172+ Git versions are used against the same repository.
173+ 2 . ** Medium term (after 2.54)** : implement the graceful-degradation
174+ idea Peff sketched in ` load_multi_pack_index_one() ` , so that
175+ unknown versions cause Git to ignore the MIDX instead of dying.
176+ This won't help current 2.53 and earlier users, but it would
177+ make a future flip from V1 to V2 by default truly painless from
178+ 2.55 onward.
179+ 3 . ** Long term (2.56 or later)** : make V2 the default once enough
180+ versions in the field can already cope with it.
181+
182+ Peff acknowledged the plan, only adding a caveat: two releases may
183+ be "not very long, especially for people who are using OS packages",
184+ e.g. people moving across Debian stable releases. But that could be
185+ sorted out later.
186+
187+ To make sure something concrete was in the rc, Junio took Peff's
188+ near-one-liner, polished the commit message, and proposed
189+ [ a first version] ( https://lore.kernel.org/git/xmqq8qam217m.fsf_-_@gitster.g )
190+ titled "MIDX: keep the default version to MIDX v1" (later renamed
191+ "MIDX: revert the default version to v1"). The patch simply
192+ initialised ` write_midx_context.version ` to ` MIDX_VERSION_V1 ` , fixed
193+ up the expected on-disk header in ` t/t5319-multi-pack-index.sh ` , and
194+ opted ` t/t5335-compact-multi-pack-index.sh ` into V2 explicitly via
195+ ` git config --global midx.version 2 ` so the compaction tests
196+ continued to exercise the new format.
197+
198+ In parallel, Junio also floated
199+ [ a second patch] ( https://lore.kernel.org/git/xmqqh5pa22h0.fsf@gitster.g )
200+ that would have weakened the two ` die() ` calls in
201+ ` load_multi_pack_index_one() ` to ` error() ` + ` goto cleanup_fail ` ,
202+ implementing Peff's earlier suggestion. He himself was unsure about
203+ that one, though, observing that doing so during the rc period would
204+ effectively promise that the MIDX is forever an optional component,
205+ and that the error messages should at least be reworded to make
206+ clear that they mean "we are ignoring this corrupt file" rather than
207+ "this is a fatal corruption". After a follow-up exchange with Peff
208+ about how dense the rest of ` load_multi_pack_index_one() ` is with
209+ ` die() ` calls (Peff confessed he had not actually looked past the
210+ two lines he had touched, and Junio confessed he had not either
211+ until he had to reply), they agreed that the right fix is * at the
212+ caller side* . The loader function genuinely is reporting "this MIDX
213+ is broken", and it is the caller's responsibility to decide whether
214+ to continue without it. The reword-and-soften idea was put aside as
215+ "an issue for much later".
216+
217+ Peff replied to Junio's first patch with a small but elegant
218+ counter-proposal: rather than defaulting to V1 * always* (which would
219+ force users of the new ` git multi-pack-index compact ` feature to set
220+ ` midx.version=2 ` manually), make ` write_midx_internal() ` pick V1 by
221+ default but switch to V2 automatically when the caller has set the
222+ ` MIDX_WRITE_COMPACT ` flag. Concretely, in
223+ [ his refined version of the patch] ( https://lore.kernel.org/git/20260416200659.GB1887222@coredump.intra.peff.net ) ,
224+ he removed the V2 initialiser from the ` write_midx_context `
225+ declaration, and inserted the following just below, and just above
226+ the existing
227+ ` repo_config_get_int(ctx.repo, "midx.version", &ctx.version) `
228+ lookup that lets a user override the choice:
229+
230+ ```
231+ ctx.version = opts->flags & MIDX_WRITE_COMPACT ?
232+ MIDX_VERSION_V2 :
233+ MIDX_VERSION_V1;
234+ ```
235+
236+ The companion documentation update in
237+ ` Documentation/git-multi-pack-index.adoc ` adds a single sentence to
238+ the ` compact:: ` description noting that compaction "requires writing
239+ a version-2 midx that cannot be read by versions of Git prior to
240+ v2.54", and the only test fallout is in
241+ ` t/t5319-multi-pack-index.sh ` , where the expected header version
242+ flips back from ` 2 ` to ` 1 ` . Notably,
243+ ` t/t5335-compact-multi-pack-index.sh ` needs no change. Compaction
244+ continues to "just work" because the new auto-select picks V2 for
245+ it.
246+
247+ Peff also confessed there are probably some gaps in V2 testing in
248+ ` t5319 ` left behind by this flip (the bulk of those tests now
249+ exercise V1 again), but argued that filling them in could be done
250+ post-release.
251+
252+ Junio said he had already merged the original "revert" version into
253+ his ` jch ` and ` next ` integration branches, but had not pushed ` next `
254+ out for external testing yet, so he chucked the original and applied
255+ this version instead, agreeing that "compact is the only thing that
256+ needs v2" was a better workaround.
257+
258+ The only remaining nit was stylistic: Junio preferred writing the
259+ ternary as
260+
261+ ```
262+ ctx.version = ((opts->flags & MIDX_WRITE_COMPACT)
263+ ? MIDX_VERSION_V2
264+ : MIDX_VERSION_V1);
265+ ```
266+
267+ so that the extra parentheses make the precedence of ` & ` vs ` ?: `
268+ obvious, and so that a multi-line ternary is easier to spot when ` ? `
269+ and ` : ` are aligned at the start of the line. Peff replied that he
270+ liked keeping the ` ? ` at the end of the first line, because then it
271+ is clear from the first line alone that it is a conditional rather
272+ than a direct assignment, but said he did not strongly care and that
273+ Junio could mark it up while applying. By the time Peff fetched
274+ ` next ` to send that reply, Junio had already done exactly that.
275+
276+ Taylor reviewed Peff's refined patch in parallel: he acked the
277+ short- and medium-term plan ("sorry again for the mess here"),
278+ suggested a small wording tweak ("Git 2.53 and earlier" rather than
279+ "Git 2.53" in the log message), and noted that he found the
280+ "auto-select V2 only when the feature requires it" behaviour a
281+ little "magical", though "less magical and more 'do the sensible
282+ thing by default'" once you remember that anyone running compaction
283+ already knows the trade-offs. Peff agreed about the wording but
284+ noted that the patch had already been pushed to ` next ` . They also
285+ exchanged a short note about extending the V2-specific coverage in
286+ ` t5319 ` going forward, which Peff suggested Taylor could pick up
287+ post-2.54.
288+
289+ The next day, Junio
290+ [ announced an update to ` master ` ] ( https://lore.kernel.org/git/xmqq5x5py5ql.fsf@gitster.g ) ,
291+ containing Peff's "MIDX: revert the default version to v1", along
292+ with a batch of documentation typo and grammar fixes from Elijah
293+ Newren and a CodeQL CI bump from Dscho. He also announced that 2.54
294+ final would be tagged on Monday, April 20th, and that he would be
295+ offline for a week or two afterwards. Elijah replied to flag a
296+ separate pair of bugs (NULL pointer dereference and read past end of
297+ string in the diffstat code path) that had just come up in
298+ [ a separate thread] ( https://lore.kernel.org/git/pull.2093.git.1776443163041.gitgitgadget@gmail.com/ ) ,
299+ in case Junio wanted to consider squeezing the fix into the release
300+ or holding it for 2.54.1.
301+
302+ The story of v2.54 thus closed with a near-miss compatibility break
303+ caught before release, fixed in a way that keeps the new
304+ infrastructure available to those who actually need it, and
305+ documented for everyone who will read the release notes later.
55306
56307## Developer Spotlight: Matthias Aßhauer
57308
0 commit comments