BreakingChanges: announce switch to "reftable" format

The "reftable" format has come a long way and has matured nicely since it has been merged into git via 57db2a094d5 (refs: introduce reftable backend, 2024-02-07). It fixes longstanding issues that cannot be fixed with the "files" format in a backwards-compatible way and performs significantly better in many use cases. Announce that we will switch to the "reftable" format in Git 3.0 for newly created repositories and wire up the change, hidden behind the WITH_BREAKING_CHANGES preprocessor define. This switch is dependent on support in the larger Git ecosystem. Most importantly, libraries like JGit, libgit2 and Gitoxide should support the reftable backend so that we don't break all applications and tools built on top of those libraries. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jul 4, 2025 at 11:42 UTC d0b94577dda3a50c1833626a70ebefd478bfcbf9
5 files changed +68
Documentation/BreakingChanges.adoc
+47
@@ -118,6 +118,53 @@ Cf. <2f5de416-04ba-c23d-1e0b-83bb655829a7@zombino.com>,
118 <20170223155046.e7nxivfwqqoprsqj@LykOS.localdomain>,
119 <CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@mail.gmail.com>.
120
121 +* The default storage format for references in newly created repositories will
122 + be changed from "files" to "reftable". The "reftable" format provides
123 + multiple advantages over the "files" format:
124 ++
125 + ** It is impossible to store two references that only differ in casing on
126 + case-insensitive filesystems with the "files" format. This issue is common
127 + on Windows and macOS platforms. As the "reftable" backend does not use
128 + filesystem paths to encode reference names this problem goes away.
129 + ** Similarly, macOS normalizes path names that contain unicode characters,
130 + which has the consequence that you cannot store two names with unicode
131 + characters that are encoded differently with the "files" backend. Again,
132 + this is not an issue with the "reftable" backend.
133 + ** Deleting references with the "files" backend requires Git to rewrite the
134 + complete "packed-refs" file. In large repositories with many references
135 + this file can easily be dozens of megabytes in size, in extreme cases it
136 + may be gigabytes. The "reftable" backend uses tombstone markers for
137 + deleted references and thus does not have to rewrite all of its data.
138 + ** Repository housekeeping with the "files" backend typically performs
139 + all-into-one repacks of references. This can be quite expensive, and
140 + consequently housekeeping is a tradeoff between the number of loose
141 + references that accumulate and slow down operations that read references,
142 + and compressing those loose references into the "packed-refs" file. The
143 + "reftable" backend uses geometric compaction after every write, which
144 + amortizes costs and ensures that the backend is always in a
145 + well-maintained state.
146 + ** Operations that write multiple references at once are not atomic with the
147 + "files" backend. Consequently, Git may see in-between states when it reads
148 + references while a reference transaction is in the process of being
149 + committed to disk.
150 + ** Writing many references at once is slow with the "files" backend because
151 + every reference is created as a separate file. The "reftable" backend
152 + significantly outperforms the "files" backend by multiple orders of
153 + magnitude.
154 + ** The reftable backend uses a binary format with prefix compression for
155 + reference names. As a result, the format uses less space compared to the
156 + "packed-refs" file.
157 ++
158 +Users that get immediate benefit from the "reftable" backend could continue to
159 +opt-in to the "reftable" format manually by setting the "init.defaultRefFormat"
160 +config. But defaults matter, and we think that overall users will have a better
161 +experience with less platform-specific quirks when they use the new backend by
162 +default.
163 ++
164 +A prerequisite for this change is that the ecosystem is ready to support the
165 +"reftable" format. Most importantly, alternative implementations of Git like
166 +JGit, libgit2 and Gitoxide need to support it.
167 +
168 === Removals
169
170 * Support for grafting commits has long been superseded by git-replace(1).
help.c
+2
@@ -810,6 +810,8 @@ void get_version_info(struct strbuf *buf, int show_build_options)
810 SHA1_UNSAFE_BACKEND);
811 #endif
812 strbuf_addf(buf, "SHA-256: %s\n", SHA256_BACKEND);
813 + strbuf_addf(buf, "default-ref-format: %s\n",
814 + ref_storage_format_to_name(REF_STORAGE_FORMAT_DEFAULT));
815 }
816 }
817
repository.h
+6
@@ -20,6 +20,12 @@ enum ref_storage_format {
20 REF_STORAGE_FORMAT_REFTABLE,
21 };
22
23 +#ifdef WITH_BREAKING_CHANGES /* Git 3.0 */
24 +# define REF_STORAGE_FORMAT_DEFAULT REF_STORAGE_FORMAT_REFTABLE
25 +#else
26 +# define REF_STORAGE_FORMAT_DEFAULT REF_STORAGE_FORMAT_FILES
27 +#endif
28 +
29 struct repo_path_cache {
30 char *squash_msg;
31 char *merge_msg;
setup.c
+2
@@ -2541,6 +2541,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,
2541 repo_fmt->ref_storage_format = ref_format;
2542 } else if (cfg.ref_format != REF_STORAGE_FORMAT_UNKNOWN) {
2543 repo_fmt->ref_storage_format = cfg.ref_format;
2544 + } else {
2545 + repo_fmt->ref_storage_format = REF_STORAGE_FORMAT_DEFAULT;
2546 }
2547 repo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);
2548 }
t/t0001-init.sh
+11
@@ -658,6 +658,17 @@ test_expect_success 'init warns about invalid init.defaultRefFormat' '
658 test_cmp expected actual
659 '
660
661 +test_expect_success 'default ref format' '
662 + test_when_finished "rm -rf refformat" &&
663 + (
664 + sane_unset GIT_DEFAULT_REF_FORMAT &&
665 + git init refformat
666 + ) &&
667 + git version --build-options | sed -ne "s/^default-ref-format: //p" >expect &&
668 + git -C refformat rev-parse --show-ref-format >actual &&
669 + test_cmp expect actual
670 +'
671 +
672 backends="files reftable"
673 for format in $backends
674 do