aboutsummaryrefslogtreecommitdiff
path: root/builtin/worktree.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/worktree.c')
-rw-r--r--builtin/worktree.c115
1 files changed, 73 insertions, 42 deletions
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 812774a5ca..4fd6f7575f 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -252,7 +252,7 @@ static int prune(int ac, const char **av, const char *prefix,
OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
OPT__VERBOSE(&verbose, N_("report pruned working trees")),
OPT_EXPIRY_DATE(0, "expire", &expire,
- N_("expire working trees older than <time>")),
+ N_("prune missing working trees older than <time>")),
OPT_END()
};
@@ -425,6 +425,39 @@ static int make_worktree_orphan(const char * ref, const struct add_opts *opts,
return run_command(&cp);
}
+/*
+ * References for worktrees are generally stored in '$GIT_DIR/worktrees/<wt_id>'.
+ * But when using alternate reference directories, we want to store the worktree
+ * references in '$ALTERNATE_REFERENCE_DIR/worktrees/<wt_id>'.
+ *
+ * Create the necessary folder structure to facilitate the same. But to ensure
+ * that the former path is still considered a Git directory, add stubs.
+ */
+static void setup_alternate_ref_dir(struct worktree *wt, const char *wt_git_path)
+{
+ struct strbuf sb = STRBUF_INIT;
+ char *path;
+
+ path = wt->repo->ref_storage_payload;
+ if (!path)
+ return;
+
+ if (!is_absolute_path(path))
+ strbuf_addf(&sb, "%s/", wt->repo->commondir);
+
+ strbuf_addf(&sb, "%s/worktrees", path);
+ safe_create_dir(wt->repo, sb.buf, 1);
+ strbuf_addf(&sb, "/%s", wt->id);
+ safe_create_dir(wt->repo, sb.buf, 1);
+ strbuf_reset(&sb);
+
+ strbuf_addf(&sb, "this worktree stores references in %s/worktrees/%s",
+ path, wt->id);
+ refs_create_refdir_stubs(wt->repo, wt_git_path, sb.buf);
+
+ strbuf_release(&sb);
+}
+
static int add_worktree(const char *path, const char *refname,
const struct add_opts *opts)
{
@@ -440,6 +473,7 @@ static int add_worktree(const char *path, const char *refname,
struct strbuf sb_name = STRBUF_INIT;
struct worktree **worktrees, *wt = NULL;
struct ref_store *wt_refs;
+ struct repo_config_values *cfg = repo_config_values(the_repository);
worktrees = get_worktrees();
check_candidate_path(path, opts->force, worktrees, "add");
@@ -505,7 +539,7 @@ static int add_worktree(const char *path, const char *refname,
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
- write_worktree_linking_files(sb_git, sb, opts->relative_paths);
+ write_worktree_linking_files(sb_git.buf, sb.buf, opts->relative_paths);
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
write_file(sb.buf, "../..");
@@ -518,6 +552,7 @@ static int add_worktree(const char *path, const char *refname,
ret = error(_("could not find created worktree '%s'"), name);
goto done;
}
+ setup_alternate_ref_dir(wt, sb_repo.buf);
wt_refs = get_worktree_ref_store(wt);
ret = ref_store_create_on_disk(wt_refs, REF_STORE_CREATE_ON_DISK_IS_WORKTREE, &sb);
@@ -536,7 +571,7 @@ static int add_worktree(const char *path, const char *refname,
* If the current worktree has sparse-checkout enabled, then copy
* the sparse-checkout patterns from the current worktree.
*/
- if (core_apply_sparse_checkout)
+ if (cfg->apply_sparse_checkout)
copy_sparse_checkout(sb_repo.buf);
/*
@@ -635,11 +670,7 @@ static void print_preparing_worktree_line(int detach,
*
* Returns 0 on failure and non-zero on success.
*/
-static int first_valid_ref(const char *refname UNUSED,
- const char *referent UNUSED,
- const struct object_id *oid UNUSED,
- int flags UNUSED,
- void *cb_data UNUSED)
+static int first_valid_ref(const struct reference *ref UNUSED, void *cb_data UNUSED)
{
return 1;
}
@@ -661,25 +692,8 @@ static int can_use_local_refs(const struct add_opts *opts)
if (refs_head_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
return 1;
} else if (refs_for_each_branch_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
- if (!opts->quiet) {
- struct strbuf path = STRBUF_INIT;
- struct strbuf contents = STRBUF_INIT;
- char *wt_gitdir = get_worktree_git_dir(NULL);
-
- strbuf_add_real_path(&path, wt_gitdir);
- strbuf_addstr(&path, "/HEAD");
- strbuf_read_file(&contents, path.buf, 64);
- strbuf_stripspace(&contents, NULL);
- strbuf_strip_suffix(&contents, "\n");
-
- warning(_("HEAD points to an invalid (or orphaned) reference.\n"
- "HEAD path: '%s'\n"
- "HEAD contents: '%s'"),
- path.buf, contents.buf);
- strbuf_release(&path);
- strbuf_release(&contents);
- free(wt_gitdir);
- }
+ if (!opts->quiet)
+ warning(_("HEAD points to an invalid (or orphaned) reference.\n"));
return 1;
}
return 0;
@@ -979,14 +993,18 @@ static void show_worktree_porcelain(struct worktree *wt, int line_terminator)
fputc(line_terminator, stdout);
}
-static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
+struct worktree_display {
+ char *path;
+ int width;
+};
+
+static void show_worktree(struct worktree *wt, struct worktree_display *display,
+ int path_maxwidth, int abbrev_len)
{
struct strbuf sb = STRBUF_INIT;
- int cur_path_len = strlen(wt->path);
- int path_adj = cur_path_len - utf8_strwidth(wt->path);
const char *reason;
- strbuf_addf(&sb, "%-*s ", 1 + path_maxlen + path_adj, wt->path);
+ strbuf_addf(&sb, "%s%*s", display->path, 1 + path_maxwidth - display->width, "");
if (wt->is_bare)
strbuf_addstr(&sb, "(bare)");
else {
@@ -1020,20 +1038,27 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
strbuf_release(&sb);
}
-static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
+static void measure_widths(struct worktree **wt, int *abbrev,
+ struct worktree_display **d, int *maxwidth)
{
- int i;
+ int i, display_alloc = 0;
+ struct worktree_display *display = NULL;
+ struct strbuf buf = STRBUF_INIT;
for (i = 0; wt[i]; i++) {
int sha1_len;
- int path_len = strlen(wt[i]->path);
+ ALLOC_GROW(display, i + 1, display_alloc);
+ quote_path(wt[i]->path, NULL, &buf, 0);
+ display[i].width = utf8_strwidth(buf.buf);
+ display[i].path = strbuf_detach(&buf, NULL);
- if (path_len > *maxlen)
- *maxlen = path_len;
+ if (display[i].width > *maxwidth)
+ *maxwidth = display[i].width;
sha1_len = strlen(repo_find_unique_abbrev(the_repository, &wt[i]->head_oid, *abbrev));
if (sha1_len > *abbrev)
*abbrev = sha1_len;
}
+ *d = display;
}
static int pathcmp(const void *a_, const void *b_)
@@ -1063,7 +1088,7 @@ static int list(int ac, const char **av, const char *prefix,
OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
OPT__VERBOSE(&verbose, N_("show extended annotations and reasons, if available")),
OPT_EXPIRY_DATE(0, "expire", &expire,
- N_("add 'prunable' annotation to worktrees older than <time>")),
+ N_("add 'prunable' annotation to missing worktrees older than <time>")),
OPT_SET_INT('z', NULL, &line_terminator,
N_("terminate records with a NUL character"), '\0'),
OPT_END()
@@ -1079,21 +1104,27 @@ static int list(int ac, const char **av, const char *prefix,
die(_("the option '%s' requires '%s'"), "-z", "--porcelain");
else {
struct worktree **worktrees = get_worktrees();
- int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i;
+ int path_maxwidth = 0, abbrev = DEFAULT_ABBREV, i;
+ struct worktree_display *display = NULL;
/* sort worktrees by path but keep main worktree at top */
pathsort(worktrees + 1);
if (!porcelain)
- measure_widths(worktrees, &abbrev, &path_maxlen);
+ measure_widths(worktrees, &abbrev,
+ &display, &path_maxwidth);
for (i = 0; worktrees[i]; i++) {
if (porcelain)
show_worktree_porcelain(worktrees[i],
line_terminator);
else
- show_worktree(worktrees[i], path_maxlen, abbrev);
+ show_worktree(worktrees[i],
+ &display[i], path_maxwidth, abbrev);
}
+ for (i = 0; display && worktrees[i]; i++)
+ free(display[i].path);
+ free(display);
free_worktrees(worktrees);
}
return 0;
@@ -1178,14 +1209,14 @@ static void validate_no_submodules(const struct worktree *wt)
wt_gitdir = get_worktree_git_dir(wt);
- if (is_directory(worktree_git_path(the_repository, wt, "modules"))) {
+ if (is_directory(worktree_git_path(wt, "modules"))) {
/*
* There could be false positives, e.g. the "modules"
* directory exists but is empty. But it's a rare case and
* this simpler check is probably good enough for now.
*/
found_submodules = 1;
- } else if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"),
+ } else if (read_index_from(&istate, worktree_git_path(wt, "index"),
wt_gitdir) > 0) {
for (i = 0; i < istate.cache_nr; i++) {
struct cache_entry *ce = istate.cache[i];