diff options
author | Patrick Steinhardt <ps@pks.im> | 2024-07-23 14:31:28 +0200 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2024-07-23 17:58:03 +0200 |
commit | 09c817383f56d4bbcfb8089e7c4ed5dd9db0f547 (patch) | |
tree | 4b06423c83910be20a111792d63d0a89d48a4666 /refs.c | |
parent | builtin/refs: new command to migrate ref storage formats (diff) | |
download | git-09c817383f56d4bbcfb8089e7c4ed5dd9db0f547.tar.xz git-09c817383f56d4bbcfb8089e7c4ed5dd9db0f547.zip |
refs: fix format migration on Cygwin
It was reported that t1460-refs-migrate.sh fails when using Cygwin with
errors like the following:
error: could not link file '.git/ref_migration.sr9pEF/reftable' to '.git/reftable': Permission denied
As some debugging surfaced, the root cause of this is that some files of
the newly-initialized ref store are still open when the target format is
the "reftable" format, and Cygwin refuses to rename open files.
Fix this issue by closing the new ref store before renaming its files
into place. This is a slight change in behaviour compared to before,
where we kept the new ref store open and then updated the repository's
ref store to point to it.
While we could re-open the new ref store after we have moved files
around, this is ultimately unnecessary. We know that the only user of
`repo_migrate_ref_storage_format()` is the git-refs(1) command, and it
won't access the ref store after it has been migrated anyway. So
reinitializing the ref store would be a waste of time. Regardless of
that it is still sensible to leave the repository in a consistent state.
But instead of reinitializing the ref store, we can simply unset the
repo's ref store altogether and let `get_main_ref_store()` lazily
initialize the new ref store as required.
Reported-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 22 |
1 files changed, 18 insertions, 4 deletions
@@ -2828,6 +2828,14 @@ int repo_migrate_ref_storage_format(struct repository *repo, } /* + * Release the new ref store such that any potentially-open files will + * be closed. This is required for platforms like Cygwin, where + * renaming an open file results in EPERM. + */ + ref_store_release(new_refs); + FREE_AND_NULL(new_refs); + + /* * Until now we were in the non-destructive phase, where we only * populated the new ref store. From hereon though we are about * to get hands by deleting the old ref store and then moving @@ -2858,10 +2866,14 @@ int repo_migrate_ref_storage_format(struct repository *repo, */ initialize_repository_version(hash_algo_by_ptr(repo->hash_algo), format, 1); - free(new_refs->gitdir); - new_refs->gitdir = xstrdup(old_refs->gitdir); - repo->refs_private = new_refs; + /* + * Unset the old ref store and release it. `get_main_ref_store()` will + * make sure to lazily re-initialize the repository's ref store with + * the new format. + */ ref_store_release(old_refs); + FREE_AND_NULL(old_refs); + repo->refs_private = NULL; ret = 0; @@ -2872,8 +2884,10 @@ done: new_gitdir.buf); } - if (ret && new_refs) + if (new_refs) { ref_store_release(new_refs); + free(new_refs); + } ref_transaction_free(transaction); strbuf_release(&new_gitdir); return ret; |