refs: implement logic to migrate between ref storage formats

With the introduction of the new "reftable" backend, users may want to
migrate repositories between the backends without having to recreate the
whole repository. Add the logic to do so.

The implementation is generic and works with arbitrary ref storage
formats so that a backend does not need to implement any migration
logic. It does have a few limitations though:

  - We do not migrate repositories with worktrees, because worktrees
    have separate ref storages. It makes the overall affair more complex
    if we have to migrate multiple storages at once.

  - We do not migrate reflogs, because we have no interfaces to write
    many reflog entries.

  - We do not lock the repository for concurrent access, and thus
    concurrent writes may end up with weird in-between states. There is
    no way to fully lock the "files" backend for writes due to its
    format, and thus we punt on this topic altogether and defer to the
    user to avoid those from happening.

In other words, this version is a minimum viable product for migrating a
repository's ref storage format. It works alright for bare repos, which
often have neither worktrees nor reflogs. But it will not work for many
other repositories without some preparations. These limitations are not
set into stone though, and ideally we will eventually address them over
time.

The logic is not yet used by anything, and thus there are no tests for
it. Those will be added in the next commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2024-06-06 07:29:45 +02:00
committed by Junio C Hamano
parent 64a6dd8ffc
commit 6d6a3a99c7
2 changed files with 326 additions and 0 deletions

18
refs.h
View File

@ -1070,6 +1070,24 @@ int is_root_ref(const char *refname);
*/
int is_pseudo_ref(const char *refname);
/*
* The following flags can be passed to `repo_migrate_ref_storage_format()`:
*
* - REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN: perform a dry-run migration
* without touching the main repository. The result will be written into a
* temporary ref storage directory.
*/
#define REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN (1 << 0)
/*
* Migrate the ref storage format used by the repository to the
* specified one.
*/
int repo_migrate_ref_storage_format(struct repository *repo,
enum ref_storage_format format,
unsigned int flags,
struct strbuf *err);
/*
* The following functions have been removed in Git v2.45 in favor of functions
* that receive a `ref_store` as parameter. The intent of this section is