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 = STRBUF_INIT, realpath = STRBUF_INIT;
|
||||
const char *name;
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
struct strvec child_env = STRVEC_INIT;
|
||||
unsigned int counter = 0;
|
||||
int len, ret;
|
||||
@ -424,7 +423,8 @@ static int add_worktree(const char *path, const char *refname,
|
||||
struct commit *commit = NULL;
|
||||
int is_branch = 0;
|
||||
struct strbuf sb_name = STRBUF_INIT;
|
||||
struct worktree **worktrees;
|
||||
struct worktree **worktrees, *wt = NULL;
|
||||
struct ref_store *wt_refs;
|
||||
|
||||
worktrees = get_worktrees();
|
||||
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);
|
||||
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
|
||||
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_addf(&sb, "%s/commondir", sb_repo.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
|
||||
* 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_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 &&
|
||||
(ret = make_worktree_orphan(refname, opts, &child_env)))
|
||||
@ -587,6 +583,7 @@ done:
|
||||
strbuf_release(&sb_git);
|
||||
strbuf_release(&sb_name);
|
||||
strbuf_release(&realpath);
|
||||
free_worktree(wt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
6
refs.c
6
refs.c
@ -1997,11 +1997,9 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
|
||||
}
|
||||
|
||||
/* 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, err);
|
||||
return refs->be->init_db(refs, flags, err);
|
||||
}
|
||||
|
||||
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 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
|
||||
|
@ -33,10 +33,10 @@ struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_stor
|
||||
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;
|
||||
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);
|
||||
return res;
|
||||
}
|
||||
|
@ -3218,21 +3218,46 @@ static int files_reflog_expire(struct ref_store *ref_store,
|
||||
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 =
|
||||
files_downcast(ref_store, REF_STORE_WRITE, "init_db");
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
strbuf_addf(&sb, "%s/refs", ref_store->gitdir);
|
||||
safe_create_dir(sb.buf, 1);
|
||||
adjust_shared_perm(sb.buf);
|
||||
|
||||
/*
|
||||
* There is no need to create directories for common refs when creating
|
||||
* 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);
|
||||
return 0;
|
||||
|
@ -1245,6 +1245,7 @@ static const char PACKED_REFS_HEADER[] =
|
||||
"# pack-refs with: peeled fully-peeled sorted \n";
|
||||
|
||||
static int packed_init_db(struct ref_store *ref_store UNUSED,
|
||||
int flags UNUSED,
|
||||
struct strbuf *err UNUSED)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
|
@ -529,7 +529,9 @@ typedef struct ref_store *ref_store_init_fn(struct repository *repo,
|
||||
const char *gitdir,
|
||||
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,
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
|
||||
/*
|
||||
|
25
worktree.c
25
worktree.c
@ -12,18 +12,23 @@
|
||||
#include "wt-status.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)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; worktrees[i]; 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]);
|
||||
}
|
||||
for (i = 0; worktrees[i]; i++)
|
||||
free_worktree(worktrees[i]);
|
||||
free (worktrees);
|
||||
}
|
||||
|
||||
@ -75,7 +80,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
|
||||
return worktree;
|
||||
}
|
||||
|
||||
static struct worktree *get_linked_worktree(const char *id,
|
||||
struct worktree *get_linked_worktree(const char *id,
|
||||
int skip_reading_head)
|
||||
{
|
||||
struct worktree *worktree = NULL;
|
||||
|
12
worktree.h
12
worktree.h
@ -57,6 +57,13 @@ struct worktree *find_worktree(struct worktree **list,
|
||||
const char *prefix,
|
||||
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
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Free up the memory for a worktree.
|
||||
*/
|
||||
void free_worktree(struct worktree *);
|
||||
|
||||
/*
|
||||
* Free up the memory for worktree(s)
|
||||
*/
|
||||
|
Reference in New Issue
Block a user