Skip to content

Commit dc8ce99

Browse files
committed
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
2 parents f95bafb + 8f4c00d commit dc8ce99

File tree

10 files changed

+96
-69
lines changed

10 files changed

+96
-69
lines changed

Diff for: builtin/worktree.c

+25-28
Original file line numberDiff line numberDiff line change
@@ -416,15 +416,15 @@ static int add_worktree(const char *path, const char *refname,
416416
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
417417
struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
418418
const char *name;
419-
struct child_process cp = CHILD_PROCESS_INIT;
420419
struct strvec child_env = STRVEC_INIT;
421420
unsigned int counter = 0;
422421
int len, ret;
423422
struct strbuf symref = STRBUF_INIT;
424423
struct commit *commit = NULL;
425424
int is_branch = 0;
426425
struct strbuf sb_name = STRBUF_INIT;
427-
struct worktree **worktrees;
426+
struct worktree **worktrees, *wt = NULL;
427+
struct ref_store *wt_refs;
428428

429429
worktrees = get_worktrees();
430430
check_candidate_path(path, opts->force, worktrees, "add");
@@ -495,20 +495,32 @@ static int add_worktree(const char *path, const char *refname,
495495
strbuf_realpath(&realpath, get_git_common_dir(), 1);
496496
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
497497
realpath.buf, name);
498-
/*
499-
* This is to keep resolve_ref() happy. We need a valid HEAD
500-
* or is_git_directory() will reject the directory. Any value which
501-
* looks like an object ID will do since it will be immediately
502-
* replaced by the symbolic-ref or update-ref invocation in the new
503-
* worktree.
504-
*/
505-
strbuf_reset(&sb);
506-
strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
507-
write_file(sb.buf, "%s", oid_to_hex(null_oid()));
508498
strbuf_reset(&sb);
509499
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
510500
write_file(sb.buf, "../..");
511501

502+
/*
503+
* Set up the ref store of the worktree and create the HEAD reference.
504+
*/
505+
wt = get_linked_worktree(name, 1);
506+
if (!wt) {
507+
ret = error(_("could not find created worktree '%s'"), name);
508+
goto done;
509+
}
510+
wt_refs = get_worktree_ref_store(wt);
511+
512+
ret = refs_init_db(wt_refs, REFS_INIT_DB_IS_WORKTREE, &sb);
513+
if (ret)
514+
goto done;
515+
516+
if (!is_branch && commit)
517+
ret = refs_update_ref(wt_refs, NULL, "HEAD", &commit->object.oid,
518+
NULL, 0, UPDATE_REFS_MSG_ON_ERR);
519+
else
520+
ret = refs_create_symref(wt_refs, "HEAD", symref.buf, NULL);
521+
if (ret)
522+
goto done;
523+
512524
/*
513525
* If the current worktree has sparse-checkout enabled, then copy
514526
* the sparse-checkout patterns from the current worktree.
@@ -526,22 +538,6 @@ static int add_worktree(const char *path, const char *refname,
526538

527539
strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
528540
strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
529-
cp.git_cmd = 1;
530-
531-
if (!is_branch && commit) {
532-
strvec_pushl(&cp.args, "update-ref", "HEAD",
533-
oid_to_hex(&commit->object.oid), NULL);
534-
} else {
535-
strvec_pushl(&cp.args, "symbolic-ref", "HEAD",
536-
symref.buf, NULL);
537-
if (opts->quiet)
538-
strvec_push(&cp.args, "--quiet");
539-
}
540-
541-
strvec_pushv(&cp.env, child_env.v);
542-
ret = run_command(&cp);
543-
if (ret)
544-
goto done;
545541

546542
if (opts->orphan &&
547543
(ret = make_worktree_orphan(refname, opts, &child_env)))
@@ -587,6 +583,7 @@ static int add_worktree(const char *path, const char *refname,
587583
strbuf_release(&sb_git);
588584
strbuf_release(&sb_name);
589585
strbuf_release(&realpath);
586+
free_worktree(wt);
590587
return ret;
591588
}
592589

Diff for: refs.c

+2-4
Original file line numberDiff line numberDiff line change
@@ -1997,11 +1997,9 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
19971997
}
19981998

19991999
/* backend functions */
2000-
int refs_init_db(struct strbuf *err)
2000+
int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err)
20012001
{
2002-
struct ref_store *refs = get_main_ref_store(the_repository);
2003-
2004-
return refs->be->init_db(refs, err);
2002+
return refs->be->init_db(refs, flags, err);
20052003
}
20062004

20072005
const char *resolve_ref_unsafe(const char *refname, int resolve_flags,

Diff for: refs.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ int should_autocreate_reflog(const char *refname);
126126

127127
int is_branch(const char *refname);
128128

129-
int refs_init_db(struct strbuf *err);
129+
#define REFS_INIT_DB_IS_WORKTREE (1 << 0)
130+
131+
int refs_init_db(struct ref_store *refs, int flags, struct strbuf *err);
130132

131133
/*
132134
* Return the peeled value of the oid currently being iterated via

Diff for: refs/debug.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ struct ref_store *maybe_debug_wrap_ref_store(const char *gitdir, struct ref_stor
3333
return (struct ref_store *)res;
3434
}
3535

36-
static int debug_init_db(struct ref_store *refs, struct strbuf *err)
36+
static int debug_init_db(struct ref_store *refs, int flags, struct strbuf *err)
3737
{
3838
struct debug_ref_store *drefs = (struct debug_ref_store *)refs;
39-
int res = drefs->refs->be->init_db(drefs->refs, err);
39+
int res = drefs->refs->be->init_db(drefs->refs, flags, err);
4040
trace_printf_key(&trace_refs, "init_db: %d\n", res);
4141
return res;
4242
}

Diff for: refs/files-backend.c

+31-6
Original file line numberDiff line numberDiff line change
@@ -3218,21 +3218,46 @@ static int files_reflog_expire(struct ref_store *ref_store,
32183218
return -1;
32193219
}
32203220

3221-
static int files_init_db(struct ref_store *ref_store, struct strbuf *err UNUSED)
3221+
static int files_init_db(struct ref_store *ref_store,
3222+
int flags,
3223+
struct strbuf *err UNUSED)
32223224
{
32233225
struct files_ref_store *refs =
32243226
files_downcast(ref_store, REF_STORE_WRITE, "init_db");
32253227
struct strbuf sb = STRBUF_INIT;
32263228

32273229
/*
3228-
* Create .git/refs/{heads,tags}
3230+
* We need to create a "refs" dir in any case so that older versions of
3231+
* Git can tell that this is a repository. This serves two main purposes:
3232+
*
3233+
* - Clients will know to stop walking the parent-directory chain when
3234+
* detecting the Git repository. Otherwise they may end up detecting
3235+
* a Git repository in a parent directory instead.
3236+
*
3237+
* - Instead of failing to detect a repository with unknown reference
3238+
* format altogether, old clients will print an error saying that
3239+
* they do not understand the reference format extension.
32293240
*/
3230-
files_ref_path(refs, &sb, "refs/heads");
3241+
strbuf_addf(&sb, "%s/refs", ref_store->gitdir);
32313242
safe_create_dir(sb.buf, 1);
3243+
adjust_shared_perm(sb.buf);
32323244

3233-
strbuf_reset(&sb);
3234-
files_ref_path(refs, &sb, "refs/tags");
3235-
safe_create_dir(sb.buf, 1);
3245+
/*
3246+
* There is no need to create directories for common refs when creating
3247+
* a worktree ref store.
3248+
*/
3249+
if (!(flags & REFS_INIT_DB_IS_WORKTREE)) {
3250+
/*
3251+
* Create .git/refs/{heads,tags}
3252+
*/
3253+
strbuf_reset(&sb);
3254+
files_ref_path(refs, &sb, "refs/heads");
3255+
safe_create_dir(sb.buf, 1);
3256+
3257+
strbuf_reset(&sb);
3258+
files_ref_path(refs, &sb, "refs/tags");
3259+
safe_create_dir(sb.buf, 1);
3260+
}
32363261

32373262
strbuf_release(&sb);
32383263
return 0;

Diff for: refs/packed-backend.c

+1
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,7 @@ static const char PACKED_REFS_HEADER[] =
12451245
"# pack-refs with: peeled fully-peeled sorted \n";
12461246

12471247
static int packed_init_db(struct ref_store *ref_store UNUSED,
1248+
int flags UNUSED,
12481249
struct strbuf *err UNUSED)
12491250
{
12501251
/* Nothing to do. */

Diff for: refs/refs-internal.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,9 @@ typedef struct ref_store *ref_store_init_fn(struct repository *repo,
529529
const char *gitdir,
530530
unsigned int flags);
531531

532-
typedef int ref_init_db_fn(struct ref_store *refs, struct strbuf *err);
532+
typedef int ref_init_db_fn(struct ref_store *refs,
533+
int flags,
534+
struct strbuf *err);
533535

534536
typedef int ref_transaction_prepare_fn(struct ref_store *refs,
535537
struct ref_transaction *transaction,

Diff for: setup.c

+1-16
Original file line numberDiff line numberDiff line change
@@ -1926,23 +1926,8 @@ void create_reference_database(unsigned int ref_storage_format,
19261926
struct strbuf err = STRBUF_INIT;
19271927
int reinit = is_reinit();
19281928

1929-
/*
1930-
* We need to create a "refs" dir in any case so that older versions of
1931-
* Git can tell that this is a repository. This serves two main purposes:
1932-
*
1933-
* - Clients will know to stop walking the parent-directory chain when
1934-
* detecting the Git repository. Otherwise they may end up detecting
1935-
* a Git repository in a parent directory instead.
1936-
*
1937-
* - Instead of failing to detect a repository with unknown reference
1938-
* format altogether, old clients will print an error saying that
1939-
* they do not understand the reference format extension.
1940-
*/
1941-
safe_create_dir(git_path("refs"), 1);
1942-
adjust_shared_perm(git_path("refs"));
1943-
19441929
repo_set_ref_storage_format(the_repository, ref_storage_format);
1945-
if (refs_init_db(&err))
1930+
if (refs_init_db(get_main_ref_store(the_repository), 0, &err))
19461931
die("failed to set up refs db: %s", err.buf);
19471932

19481933
/*

Diff for: worktree.c

+16-11
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,23 @@
1212
#include "wt-status.h"
1313
#include "config.h"
1414

15+
void free_worktree(struct worktree *worktree)
16+
{
17+
if (!worktree)
18+
return;
19+
free(worktree->path);
20+
free(worktree->id);
21+
free(worktree->head_ref);
22+
free(worktree->lock_reason);
23+
free(worktree->prune_reason);
24+
free(worktree);
25+
}
26+
1527
void free_worktrees(struct worktree **worktrees)
1628
{
1729
int i = 0;
18-
19-
for (i = 0; worktrees[i]; i++) {
20-
free(worktrees[i]->path);
21-
free(worktrees[i]->id);
22-
free(worktrees[i]->head_ref);
23-
free(worktrees[i]->lock_reason);
24-
free(worktrees[i]->prune_reason);
25-
free(worktrees[i]);
26-
}
30+
for (i = 0; worktrees[i]; i++)
31+
free_worktree(worktrees[i]);
2732
free (worktrees);
2833
}
2934

@@ -75,8 +80,8 @@ static struct worktree *get_main_worktree(int skip_reading_head)
7580
return worktree;
7681
}
7782

78-
static struct worktree *get_linked_worktree(const char *id,
79-
int skip_reading_head)
83+
struct worktree *get_linked_worktree(const char *id,
84+
int skip_reading_head)
8085
{
8186
struct worktree *worktree = NULL;
8287
struct strbuf path = STRBUF_INIT;

Diff for: worktree.h

+12
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ struct worktree *find_worktree(struct worktree **list,
5757
const char *prefix,
5858
const char *arg);
5959

60+
/*
61+
* Look up the worktree corresponding to `id`, or NULL of no such worktree
62+
* exists.
63+
*/
64+
struct worktree *get_linked_worktree(const char *id,
65+
int skip_reading_head);
66+
6067
/*
6168
* Return the worktree corresponding to `path`, or NULL if no such worktree
6269
* exists.
@@ -134,6 +141,11 @@ void repair_worktrees(worktree_repair_fn, void *cb_data);
134141
*/
135142
void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);
136143

144+
/*
145+
* Free up the memory for a worktree.
146+
*/
147+
void free_worktree(struct worktree *);
148+
137149
/*
138150
* Free up the memory for worktree(s)
139151
*/

0 commit comments

Comments
 (0)