Skip to content

Commit 5e458c1

Browse files
committed
Merge branch 'ps/use-reftable-as-default-in-3.0'
The reftable ref backend has matured enough; Git 3.0 will make it the default format in a newly created repositories by default. * ps/use-reftable-as-default-in-3.0: setup: use "reftable" format when experimental features are enabled BreakingChanges: announce switch to "reftable" format
2 parents 50d9c34 + 793b14e commit 5e458c1

File tree

6 files changed

+120
-0
lines changed

6 files changed

+120
-0
lines changed

Documentation/BreakingChanges.adoc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,53 @@ Cf. <[email protected]>,
118118
119119
<CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@mail.gmail.com>.
120120

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+
121168
=== Removals
122169

123170
* Support for grafting commits has long been superseded by git-replace(1).

Documentation/config/feature.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ reusing objects from multiple packs instead of just one.
2424
* `pack.usePathWalk` may speed up packfile creation and make the packfiles be
2525
significantly smaller in the presence of certain filename collisions with Git's
2626
default name-hash.
27+
+
28+
* `init.defaultRefFormat=reftable` causes newly initialized repositories to use
29+
the reftable format for storing references. This new format solves issues with
30+
case-insensitive filesystems, compresses better and performs significantly
31+
better with many use cases. Refer to Documentation/technical/reftable.adoc for
32+
more information on this new storage format.
2733
2834
feature.manyFiles::
2935
Enable config options that optimize for repos with many files in the

help.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,8 @@ void get_version_info(struct strbuf *buf, int show_build_options)
810810
SHA1_UNSAFE_BACKEND);
811811
#endif
812812
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));
813815
}
814816
}
815817

repository.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ enum ref_storage_format {
2020
REF_STORAGE_FORMAT_REFTABLE,
2121
};
2222

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+
2329
struct repo_path_cache {
2430
char *squash_msg;
2531
char *merge_msg;

setup.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2484,6 +2484,18 @@ static int read_default_format_config(const char *key, const char *value,
24842484
goto out;
24852485
}
24862486

2487+
/*
2488+
* Enable the reftable format when "features.experimental" is enabled.
2489+
* "init.defaultRefFormat" takes precedence over this setting.
2490+
*/
2491+
if (!strcmp(key, "feature.experimental") &&
2492+
cfg->ref_format == REF_STORAGE_FORMAT_UNKNOWN &&
2493+
git_config_bool(key, value)) {
2494+
cfg->ref_format = REF_STORAGE_FORMAT_REFTABLE;
2495+
ret = 0;
2496+
goto out;
2497+
}
2498+
24872499
ret = 0;
24882500
out:
24892501
free(str);
@@ -2544,6 +2556,8 @@ static void repository_format_configure(struct repository_format *repo_fmt,
25442556
repo_fmt->ref_storage_format = ref_format;
25452557
} else if (cfg.ref_format != REF_STORAGE_FORMAT_UNKNOWN) {
25462558
repo_fmt->ref_storage_format = cfg.ref_format;
2559+
} else {
2560+
repo_fmt->ref_storage_format = REF_STORAGE_FORMAT_DEFAULT;
25472561
}
25482562
repo_set_ref_storage_format(the_repository, repo_fmt->ref_storage_format);
25492563
}

t/t0001-init.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,17 @@ test_expect_success 'init warns about invalid init.defaultRefFormat' '
658658
test_cmp expected actual
659659
'
660660

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+
661672
backends="files reftable"
662673
for format in $backends
663674
do
@@ -738,6 +749,40 @@ test_expect_success "GIT_DEFAULT_REF_FORMAT= overrides init.defaultRefFormat" '
738749
test_cmp expect actual
739750
'
740751

752+
test_expect_success "init with feature.experimental=true" '
753+
test_when_finished "rm -rf refformat" &&
754+
test_config_global feature.experimental true &&
755+
(
756+
sane_unset GIT_DEFAULT_REF_FORMAT &&
757+
git init refformat
758+
) &&
759+
echo reftable >expect &&
760+
git -C refformat rev-parse --show-ref-format >actual &&
761+
test_cmp expect actual
762+
'
763+
764+
test_expect_success "init.defaultRefFormat overrides feature.experimental=true" '
765+
test_when_finished "rm -rf refformat" &&
766+
test_config_global feature.experimental true &&
767+
test_config_global init.defaultRefFormat files &&
768+
(
769+
sane_unset GIT_DEFAULT_REF_FORMAT &&
770+
git init refformat
771+
) &&
772+
echo files >expect &&
773+
git -C refformat rev-parse --show-ref-format >actual &&
774+
test_cmp expect actual
775+
'
776+
777+
test_expect_success "GIT_DEFAULT_REF_FORMAT= overrides feature.experimental=true" '
778+
test_when_finished "rm -rf refformat" &&
779+
test_config_global feature.experimental true &&
780+
GIT_DEFAULT_REF_FORMAT=files git init refformat &&
781+
echo files >expect &&
782+
git -C refformat rev-parse --show-ref-format >actual &&
783+
test_cmp expect actual
784+
'
785+
741786
for from_format in $backends
742787
do
743788
test_expect_success "re-init with same format ($from_format)" '

0 commit comments

Comments
 (0)