[PATCH v4 0/4] refs: allow setting the reference directory
STALE220d
From: Karthik Nayak <hidden>
Date: 2026-02-02 12:27:04
Revision v4 of 9 in this series.
Revisions (9)
While Git allows users to select different reference backends, unlike
with objects, there is no flexibility in selecting the reference
directory. Currently, the reference format is obtained from the config
of the repository and the reference directory is set to the $GIT_DIR.
This patch extends the config 'extensions.refStorage' to take in
multiple forms of inputs:
- A format name alone (e.g., `reftable` or `files`) which uses the
default location (the repository's common directory).
- A URI format `<format>://<location>` which explicitly specifies
both the format and location (e.g., `reftable:///foo/bar`).
We also add in a new ENV variable GIT_REFERENCE_BACKEND which can be
used to override the config.
One use case for this is migration between different backends. On the
server side, migrating from the files backend to the newly introduced
reftable backend can be achieved by running 'git refs migrate'. However,
for large repositories with millions of references, this migration can
take from seconds to minutes.
For some background, at GitLab, the criteria for our migration was to
reduce the downtime of the migrate ideally to zero. So running 'git refs
migrate --ref-format=reftable' by itself wouldn't work, since it scales
with the number of references and we have repos with millions of
references, so we need to migrate without loosing any information. We
came up with the following plan:
1. Run git-pack-refs(1) and note timestamp of the generated packed-refs
file.
2. Run git refs migrate –dry-run.
3. If there are no ongoing reference requests (read/write)
a. Lock the repository by blocking incoming requests (done on a
layer above git, in Gitaly [1]).
b. If the timestamp of the packed-refs file has changed, unlock
the repo and repeat from step 1.
c. Apply all the loose refs to the dry-run reftable folder (this
requires support in Git to write refs to arbitrary folder).
d. Move the reftable dry-run folder into the GIT_DIR.
e. Swap the repo config
f. Unlock repo access
Using such a route, scales much better since we only have to worry about
blocking the repository by O(ref written between #1 and #3a) and not
O(refs in repo). But for doing so, we need to be able to write to a
arbitrary reference backend + path. This is to add the missing
references to the dry-run reftable folder. This series, achieves that.
Since there was a long gap between v3 <> v4, the version 4 onward is
based on top of 2258446484 (RelNotes: correct "fast-import" option name,
2026-01-30).
[1]: https://gitlab.com/gitlab-org/gitaly
---
Changes in v4:
- Mostly re-wrote the code to also support worktree. Now, the existing
backends will store worktree references in 'ref_dir/worktrees/wt_id'
and add corresponding stubs in 'git_dir/worktrees/wt_id'.
- We also support relative paths in the reference directories. These
relative paths are resolved relative to the GIT_DIR.
- Link to v3: https://patch.msgid.link/20251201-kn-alternate-ref-dir-v3-0-c11b946bc2fa@gmail.com
Changes in v3:
- Cleanup some stale code which wasn't removed.
- Localize strings which will be output to the user.
- Remove additional defensive checks which are not needed.
- Link to v2: https://patch.msgid.link/20251126-kn-alternate-ref-dir-v2-0-8b9f6f18f635@gmail.com
Changes in v2:
- Added more clarification and proper intent in the cover message.
- Changed the format from '<ref_backend>://<path>' to
`<ref_backend>://<URI-for-resource>` as it much clearer.
- Added logic to check for the '//' in the provided URI and a test for
the same.
- In the tests:
- Use test_must_fail() instead of ! git
- Fix looped tests not using the variables correctly and ensure that
the test description is correct.
- Link to v1: https://patch.msgid.link/20251119-kn-alternate-ref-dir-v1-0-4cf4a94c8bed@gmail.com
---
Documentation/config/extensions.adoc | 16 ++-
Documentation/git.adoc | 5 +
builtin/clone.c | 10 +-
builtin/worktree.c | 35 +++++++
environment.h | 1 +
refs.c | 61 +++++++++++-
refs.h | 13 +++
refs/files-backend.c | 18 +++-
refs/packed-backend.c | 1 +
refs/packed-backend.h | 1 +
refs/refs-internal.h | 15 +++
refs/reftable-backend.c | 38 +++----
repository.c | 9 +-
repository.h | 5 +-
setup.c | 59 ++++++++++-
setup.h | 2 +
t/meson.build | 1 +
t/t1423-ref-backend.sh | 187 +++++++++++++++++++++++++++++++++++
18 files changed, 433 insertions(+), 44 deletions(-)
Karthik Nayak (4):
refs: allow reference location in refstorage config
refs: extract out `refs_create_refdir_stubs()`
refs: parse and use the reference storage payload
refs: add GIT_REFERENCE_BACKEND to specify reference backend
Range-diff versus v3:
1: a91a4d5ba3 < -: ---------- refs: support obtaining ref_store for given dir
2: a9f126d724 < -: ---------- refs: add GIT_REF_URI to specify reference backend and directory
-: ---------- > 1: c8ddb8ec8d refs: allow reference location in refstorage config
-: ---------- > 2: 02acdc16b4 refs: extract out `refs_create_refdir_stubs()`
-: ---------- > 3: 1b0e17e705 refs: parse and use the reference storage payload
-: ---------- > 4: 8ca379edd6 refs: add GIT_REFERENCE_BACKEND to specify reference backend
base-commit: 22584464849815268419fd9d2eba307362360db1
change-id: 20251105-kn-alternate-ref-dir-3e572e8cd0ef
Thanks
- Karthik