Merge branch 'ps/worktree-refdb-initialization'
Instead of manually creating refs/ hierarchy on disk upon a creation of a secondary worktree, which is only usable via the files backend, use the refs API to populate it. * ps/worktree-refdb-initialization: builtin/worktree: create refdb via ref backend worktree: expose interface to look up worktree by name builtin/worktree: move setup of commondir file earlier refs/files: skip creation of "refs/{heads,tags}" for worktrees setup: move creation of "refs/" into the files backend refs: prepare `refs_init_db()` for initializing worktree refs
This commit is contained in:
@ -416,7 +416,6 @@ static int add_worktree(const char *path, const char *refname,
|
|||||||
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
|
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
|
||||||
struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
|
||||||
const char *name;
|
const char *name;
|
||||||
struct child_process cp = CHILD_PROCESS_INIT;
|
|
||||||
struct strvec child_env = STRVEC_INIT;
|
struct strvec child_env = STRVEC_INIT;
|
||||||
unsigned int counter = 0;
|
unsigned int counter = 0;
|
||||||
int len, ret;
|
int len, ret;
|
||||||
@ -424,7 +423,8 @@ static int add_worktree(const char *path, const char *refname,
|
|||||||
struct commit *commit = NULL;
|
struct commit *commit = NULL;
|
||||||
int is_branch = 0;
|
int is_branch = 0;
|
||||||
struct strbuf sb_name = STRBUF_INIT;
|
struct strbuf sb_name = STRBUF_INIT;
|
||||||
struct worktree **worktrees;
|
struct worktree **worktrees, *wt = NULL;
|
||||||
|
struct ref_store *wt_refs;
|
||||||
|
|
||||||
worktrees = get_worktrees();
|
worktrees = get_worktrees();
|
||||||
check_candidate_path(path, opts->force, worktrees, "add");
|
check_candidate_path(path, opts->force, worktrees, "add");
|
||||||
@ -495,20 +495,32 @@ static int add_worktree(const char *path, const char *refname,
|
|||||||
strbuf_realpath(&realpath, get_git_common_dir(), 1);
|
strbuf_realpath(&realpath, get_git_common_dir(), 1);
|
||||||
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
|
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
|
||||||
realpath.buf, name);
|
realpath.buf, name);
|
||||||
/*
|
|
||||||
* This is to keep resolve_ref() happy. We need a valid HEAD
|
|
||||||
* or is_git_directory() will reject the directory. Any value which
|
|
||||||
* looks like an object ID will do since it will be immediately
|
|
||||||
* replaced by the symbolic-ref or update-ref invocation in the new
|
|
||||||
* worktree.
|
|
||||||
*/
|
|
||||||
strbuf_reset(&sb);
|
|
||||||
strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
|
|
||||||
write_file(sb.buf, "%s", oid_to_hex(null_oid()));
|
|
||||||
strbuf_reset(&sb);
|
strbuf_reset(&sb);
|
||||||
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
|
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
|
||||||
write_file(sb.buf, "../..");
|
write_file(sb.buf, "../..");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the ref store of the worktree and create the HEAD reference.
|
||||||
|
*/
|
||||||
|
wt = get_linked_worktree(name, 1);
|
||||||
|
if (!wt) {
|
||||||
|
ret = error(_("could not find created worktree '%s'"), name);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
wt_refs = get_worktree_ref_store(wt);
|
||||||
|
|
||||||
|
ret = refs_init_db(wt_refs, REFS_INIT_DB_IS_WORKTREE, &sb);
|
||||||
|
if (ret)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (!is_branch && commit)
|
||||||
|
ret = refs_update_ref(wt_refs, NULL, "HEAD", &commit->object.oid,
|
||||||
|
NULL, 0, UPDATE_REFS_MSG_ON_ERR);
|
||||||
|
else
|
||||||
|
ret = refs_create_symref(wt_refs, "HEAD", symref.buf, NULL);
|
||||||
|
if (ret)
|
||||||
|
goto done;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the current worktree has sparse-checkout enabled, then copy
|
* If the current worktree has sparse-checkout enabled, then copy
|
||||||
* the sparse-checkout patterns from the current worktree.
|
* the sparse-checkout patterns from the current worktree.
|
||||||
@ -526,22 +538,6 @@ static int add_worktree(const char *path, const char *refname,
|
|||||||
|
|
||||||
strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
|
strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
|
||||||
strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
|
strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
|
||||||
cp.git_cmd = 1;
|
|
||||||
|
|
||||||
if (!is_branch && commit) {
|
|
||||||
strvec_pushl(&cp.args, "update-ref", "HEAD",
|
|
||||||
oid_to_hex(&commit->object.oid), NULL);
|
|
||||||
} else {
|
|
||||||
strvec_pushl(&cp.args, "symbolic-ref", "HEAD",
|
|
||||||
symref.buf, NULL);
|
|
||||||
if (opts->quiet)
|
|
||||||
strvec_push(&cp.args, "--quiet");
|
|
||||||
}
|
|
||||||
|
|
||||||
strvec_pushv(&cp.env, child_env.v);
|
|
||||||
ret = run_command(&cp);
|
|
||||||
if (ret)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (opts->orphan &&
|
if (opts->orphan &&
|
||||||
(ret = make_worktree_orphan(refname, opts, &child_env)))
|
(ret = make_worktree_orphan(refname, opts, &child_env)))
|
||||||
@ -587,6 +583,7 @@ done:
|
|||||||
strbuf_release(&sb_git);
|
strbuf_release(&sb_git);
|
||||||
strbuf_release(&sb_name);
|
strbuf_release(&sb_name);
|
||||||
strbuf_release(&realpath);
|
strbuf_release(&realpath);
|
||||||
|
free_worktree(wt);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
refs.c
6
refs.c
@ -1997,11 +1997,9 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* backend functions */
|
/* backend functions */
|
||||||
int refs_init_db(struct strbuf *err)
|
int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err)
|
||||||
{
|
{
|
||||||
struct ref_store *refs = get_main_ref_store(the_repository);
|
return refs->be->init_db(refs, flags, err);
|
||||||
|
|
||||||
return refs->be->init_db(refs, err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
|
const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
|
||||||
|
4
refs.h
4
refs.h
@ -126,7 +126,9 @@ int should_autocreate_reflog(const char *refname);
|
|||||||
|
|
||||||
int is_branch(const char *refname);
|
int is_branch(const char *refname);
|
||||||
|
|
||||||
int refs_init_db(struct strbuf *err);
|
#define REFS_INIT_DB_IS_WORKTREE (1 << 0)
|
||||||
|
|
||||||
|
int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the peeled value of the oid currently being iterated via
|
* Return the peeled value of the oid currently being iterated via
|
||||||
|
@ -33,10 +33,10 @@ struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_stor
|
|||||||
return (struct ref_store *)res;
|
return (struct ref_store *)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int debug_init_db(struct ref_store *refs, struct strbuf *err)
|
static int debug_init_db(struct ref_store *refs, int flags, struct strbuf *err)
|
||||||
{
|
{
|
||||||
struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
|
struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
|
||||||
int res = drefs->refs->be->init_db(drefs->refs, err);
|
int res = drefs->refs->be->init_db(drefs->refs, flags, err);
|
||||||
trace_printf_key(&trace_refs, "init_db: %d\n", res);
|
trace_printf_key(&trace_refs, "init_db: %d\n", res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -3218,21 +3218,46 @@ static int files_reflog_expire(struct ref_store *ref_store,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int files_init_db(struct ref_store *ref_store, struct strbuf *err UNUSED)
|
static int files_init_db(struct ref_store *ref_store,
|
||||||
|
int flags,
|
||||||
|
struct strbuf *err UNUSED)
|
||||||
{
|
{
|
||||||
struct files_ref_store *refs =
|
struct files_ref_store *refs =
|
||||||
files_downcast(ref_store, REF_STORE_WRITE, "init_db");
|
files_downcast(ref_store, REF_STORE_WRITE, "init_db");
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create .git/refs/{heads,tags}
|
* We need to create a "refs" dir in any case so that older versions of
|
||||||
|
* Git can tell that this is a repository. This serves two main purposes:
|
||||||
|
*
|
||||||
|
* - Clients will know to stop walking the parent-directory chain when
|
||||||
|
* detecting the Git repository. Otherwise they may end up detecting
|
||||||
|
* a Git repository in a parent directory instead.
|
||||||
|
*
|
||||||
|
* - Instead of failing to detect a repository with unknown reference
|
||||||
|
* format altogether, old clients will print an error saying that
|
||||||
|
* they do not understand the reference format extension.
|
||||||
*/
|
*/
|
||||||
files_ref_path(refs, &sb, "refs/heads");
|
strbuf_addf(&sb, "%s/refs", ref_store->gitdir);
|
||||||
safe_create_dir(sb.buf, 1);
|
safe_create_dir(sb.buf, 1);
|
||||||
|
adjust_shared_perm(sb.buf);
|
||||||
|
|
||||||
strbuf_reset(&sb);
|
/*
|
||||||
files_ref_path(refs, &sb, "refs/tags");
|
* There is no need to create directories for common refs when creating
|
||||||
safe_create_dir(sb.buf, 1);
|
* a worktree ref store.
|
||||||
|
*/
|
||||||
|
if (!(flags & REFS_INIT_DB_IS_WORKTREE)) {
|
||||||
|
/*
|
||||||
|
* Create .git/refs/{heads,tags}
|
||||||
|
*/
|
||||||
|
strbuf_reset(&sb);
|
||||||
|
files_ref_path(refs, &sb, "refs/heads");
|
||||||
|
safe_create_dir(sb.buf, 1);
|
||||||
|
|
||||||
|
strbuf_reset(&sb);
|
||||||
|
files_ref_path(refs, &sb, "refs/tags");
|
||||||
|
safe_create_dir(sb.buf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
strbuf_release(&sb);
|
strbuf_release(&sb);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1245,6 +1245,7 @@ static const char PACKED_REFS_HEADER[] =
|
|||||||
"# pack-refs with: peeled fully-peeled sorted \n";
|
"# pack-refs with: peeled fully-peeled sorted \n";
|
||||||
|
|
||||||
static int packed_init_db(struct ref_store *ref_store UNUSED,
|
static int packed_init_db(struct ref_store *ref_store UNUSED,
|
||||||
|
int flags UNUSED,
|
||||||
struct strbuf *err UNUSED)
|
struct strbuf *err UNUSED)
|
||||||
{
|
{
|
||||||
/* Nothing to do. */
|
/* Nothing to do. */
|
||||||
|
@ -529,7 +529,9 @@ typedef struct ref_store *ref_store_init_fn(struct repository *repo,
|
|||||||
const char *gitdir,
|
const char *gitdir,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
|
||||||
typedef int ref_init_db_fn(struct ref_store *refs, struct strbuf *err);
|
typedef int ref_init_db_fn(struct ref_store *refs,
|
||||||
|
int flags,
|
||||||
|
struct strbuf *err);
|
||||||
|
|
||||||
typedef int ref_transaction_prepare_fn(struct ref_store *refs,
|
typedef int ref_transaction_prepare_fn(struct ref_store *refs,
|
||||||
struct ref_transaction *transaction,
|
struct ref_transaction *transaction,
|
||||||
|
17
setup.c
17
setup.c
@ -1926,23 +1926,8 @@ void create_reference_database(unsigned int ref_storage_format,
|
|||||||
struct strbuf err = STRBUF_INIT;
|
struct strbuf err = STRBUF_INIT;
|
||||||
int reinit = is_reinit();
|
int reinit = is_reinit();
|
||||||
|
|
||||||
/*
|
|
||||||
* We need to create a "refs" dir in any case so that older versions of
|
|
||||||
* Git can tell that this is a repository. This serves two main purposes:
|
|
||||||
*
|
|
||||||
* - Clients will know to stop walking the parent-directory chain when
|
|
||||||
* detecting the Git repository. Otherwise they may end up detecting
|
|
||||||
* a Git repository in a parent directory instead.
|
|
||||||
*
|
|
||||||
* - Instead of failing to detect a repository with unknown reference
|
|
||||||
* format altogether, old clients will print an error saying that
|
|
||||||
* they do not understand the reference format extension.
|
|
||||||
*/
|
|
||||||
safe_create_dir(git_path("refs"), 1);
|
|
||||||
adjust_shared_perm(git_path("refs"));
|
|
||||||
|
|
||||||
repo_set_ref_storage_format(the_repository, ref_storage_format);
|
repo_set_ref_storage_format(the_repository, ref_storage_format);
|
||||||
if (refs_init_db(&err))
|
if (refs_init_db(get_main_ref_store(the_repository), 0, &err))
|
||||||
die("failed to set up refs db: %s", err.buf);
|
die("failed to set up refs db: %s", err.buf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
27
worktree.c
27
worktree.c
@ -12,18 +12,23 @@
|
|||||||
#include "wt-status.h"
|
#include "wt-status.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
void free_worktree(struct worktree *worktree)
|
||||||
|
{
|
||||||
|
if (!worktree)
|
||||||
|
return;
|
||||||
|
free(worktree->path);
|
||||||
|
free(worktree->id);
|
||||||
|
free(worktree->head_ref);
|
||||||
|
free(worktree->lock_reason);
|
||||||
|
free(worktree->prune_reason);
|
||||||
|
free(worktree);
|
||||||
|
}
|
||||||
|
|
||||||
void free_worktrees(struct worktree **worktrees)
|
void free_worktrees(struct worktree **worktrees)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
for (i = 0; worktrees[i]; i++)
|
||||||
for (i = 0; worktrees[i]; i++) {
|
free_worktree(worktrees[i]);
|
||||||
free(worktrees[i]->path);
|
|
||||||
free(worktrees[i]->id);
|
|
||||||
free(worktrees[i]->head_ref);
|
|
||||||
free(worktrees[i]->lock_reason);
|
|
||||||
free(worktrees[i]->prune_reason);
|
|
||||||
free(worktrees[i]);
|
|
||||||
}
|
|
||||||
free (worktrees);
|
free (worktrees);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,8 +80,8 @@ static struct worktree *get_main_worktree(int skip_reading_head)
|
|||||||
return worktree;
|
return worktree;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct worktree *get_linked_worktree(const char *id,
|
struct worktree *get_linked_worktree(const char *id,
|
||||||
int skip_reading_head)
|
int skip_reading_head)
|
||||||
{
|
{
|
||||||
struct worktree *worktree = NULL;
|
struct worktree *worktree = NULL;
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
|
12
worktree.h
12
worktree.h
@ -57,6 +57,13 @@ struct worktree *find_worktree(struct worktree **list,
|
|||||||
const char *prefix,
|
const char *prefix,
|
||||||
const char *arg);
|
const char *arg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up the worktree corresponding to `id`, or NULL of no such worktree
|
||||||
|
* exists.
|
||||||
|
*/
|
||||||
|
struct worktree *get_linked_worktree(const char *id,
|
||||||
|
int skip_reading_head);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the worktree corresponding to `path`, or NULL if no such worktree
|
* Return the worktree corresponding to `path`, or NULL if no such worktree
|
||||||
* exists.
|
* exists.
|
||||||
@ -134,6 +141,11 @@ void repair_worktrees(worktree_repair_fn, void *cb_data);
|
|||||||
*/
|
*/
|
||||||
void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);
|
void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free up the memory for a worktree.
|
||||||
|
*/
|
||||||
|
void free_worktree(struct worktree *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free up the memory for worktree(s)
|
* Free up the memory for worktree(s)
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user