Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/reflog.c3
-rw-r--r--reflog.c13
-rw-r--r--refs.c76
-rw-r--r--refs.h33
-rw-r--r--refs/files-backend.c80
-rw-r--r--refs/packed-backend.c2
-rw-r--r--worktree.c59
-rw-r--r--worktree.h10
8 files changed, 126 insertions, 150 deletions
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 57c5c0d061..270681dcdf 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -67,7 +67,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid UNUSED,
* Avoid collecting the same shared ref multiple times because
* they are available via all worktrees.
*/
- if (!worktree->is_current && ref_type(ref) == REF_TYPE_NORMAL)
+ if (!worktree->is_current &&
+ parse_worktree_ref(ref, NULL, NULL, NULL) == REF_WORKTREE_SHARED)
return 0;
strbuf_worktree_ref(worktree, &newref, ref);
diff --git a/reflog.c b/reflog.c
index d258fd3199..78e9350e20 100644
--- a/reflog.c
+++ b/reflog.c
@@ -312,16 +312,9 @@ static int push_tip_to_list(const char *refname UNUSED,
static int is_head(const char *refname)
{
- switch (ref_type(refname)) {
- case REF_TYPE_OTHER_PSEUDOREF:
- case REF_TYPE_MAIN_PSEUDOREF:
- if (parse_worktree_ref(refname, NULL, NULL, &refname))
- BUG("not a worktree ref: %s", refname);
- break;
- default:
- break;
- }
- return !strcmp(refname, "HEAD");
+ const char *stripped_refname;
+ parse_worktree_ref(refname, NULL, NULL, &stripped_refname);
+ return !strcmp(stripped_refname, "HEAD");
}
void reflog_expiry_prepare(const char *refname,
diff --git a/refs.c b/refs.c
index c89d558892..1491ae937e 100644
--- a/refs.c
+++ b/refs.c
@@ -811,7 +811,7 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
return repo_dwim_log(the_repository, str, len, oid, log);
}
-static int is_per_worktree_ref(const char *refname)
+int is_per_worktree_ref(const char *refname)
{
return starts_with(refname, "refs/worktree/") ||
starts_with(refname, "refs/bisect/") ||
@@ -827,37 +827,63 @@ static int is_pseudoref_syntax(const char *refname)
return 0;
}
+ /*
+ * HEAD is not a pseudoref, but it certainly uses the
+ * pseudoref syntax.
+ */
return 1;
}
-static int is_main_pseudoref_syntax(const char *refname)
-{
- return skip_prefix(refname, "main-worktree/", &refname) &&
- *refname &&
- is_pseudoref_syntax(refname);
+static int is_current_worktree_ref(const char *ref) {
+ return is_pseudoref_syntax(ref) || is_per_worktree_ref(ref);
}
-static int is_other_pseudoref_syntax(const char *refname)
+enum ref_worktree_type parse_worktree_ref(const char *maybe_worktree_ref,
+ const char **worktree_name, int *worktree_name_length,
+ const char **bare_refname)
{
- if (!skip_prefix(refname, "worktrees/", &refname))
- return 0;
- refname = strchr(refname, '/');
- if (!refname || !refname[1])
- return 0;
- return is_pseudoref_syntax(refname + 1);
-}
+ const char *name_dummy;
+ int name_length_dummy;
+ const char *ref_dummy;
-enum ref_type ref_type(const char *refname)
-{
- if (is_per_worktree_ref(refname))
- return REF_TYPE_PER_WORKTREE;
- if (is_pseudoref_syntax(refname))
- return REF_TYPE_PSEUDOREF;
- if (is_main_pseudoref_syntax(refname))
- return REF_TYPE_MAIN_PSEUDOREF;
- if (is_other_pseudoref_syntax(refname))
- return REF_TYPE_OTHER_PSEUDOREF;
- return REF_TYPE_NORMAL;
+ if (!worktree_name)
+ worktree_name = &name_dummy;
+ if (!worktree_name_length)
+ worktree_name_length = &name_length_dummy;
+ if (!bare_refname)
+ bare_refname = &ref_dummy;
+
+ if (skip_prefix(maybe_worktree_ref, "worktrees/", bare_refname)) {
+ const char *slash = strchr(*bare_refname, '/');
+
+ *worktree_name = *bare_refname;
+ if (!slash) {
+ *worktree_name_length = strlen(*worktree_name);
+
+ /* This is an error condition, and the caller tell because the bare_refname is "" */
+ *bare_refname = *worktree_name + *worktree_name_length;
+ return REF_WORKTREE_OTHER;
+ }
+
+ *worktree_name_length = slash - *bare_refname;
+ *bare_refname = slash + 1;
+
+ if (is_current_worktree_ref(*bare_refname))
+ return REF_WORKTREE_OTHER;
+ }
+
+ *worktree_name = NULL;
+ *worktree_name_length = 0;
+
+ if (skip_prefix(maybe_worktree_ref, "main-worktree/", bare_refname)
+ && is_current_worktree_ref(*bare_refname))
+ return REF_WORKTREE_MAIN;
+
+ *bare_refname = maybe_worktree_ref;
+ if (is_current_worktree_ref(maybe_worktree_ref))
+ return REF_WORKTREE_CURRENT;
+
+ return REF_WORKTREE_SHARED;
}
long get_files_ref_lock_timeout_ms(void)
diff --git a/refs.h b/refs.h
index d6575b8c2b..8958717a17 100644
--- a/refs.h
+++ b/refs.h
@@ -820,15 +820,34 @@ int parse_hide_refs_config(const char *var, const char *value, const char *);
*/
int ref_is_hidden(const char *, const char *);
-enum ref_type {
- REF_TYPE_PER_WORKTREE, /* refs inside refs/ but not shared */
- REF_TYPE_PSEUDOREF, /* refs outside refs/ in current worktree */
- REF_TYPE_MAIN_PSEUDOREF, /* pseudo refs from the main worktree */
- REF_TYPE_OTHER_PSEUDOREF, /* pseudo refs from other worktrees */
- REF_TYPE_NORMAL, /* normal/shared refs inside refs/ */
+/* Is this a per-worktree ref living in the refs/ namespace? */
+int is_per_worktree_ref(const char *refname);
+
+/* Describes how a refname relates to worktrees */
+enum ref_worktree_type {
+ REF_WORKTREE_CURRENT, /* implicitly per worktree, eg. HEAD or
+ refs/bisect/SOMETHING */
+ REF_WORKTREE_MAIN, /* explicitly in main worktree, eg.
+ main-worktree/HEAD */
+ REF_WORKTREE_OTHER, /* explicitly in named worktree, eg.
+ worktrees/bla/HEAD */
+ REF_WORKTREE_SHARED, /* the default, eg. refs/heads/main */
};
-enum ref_type ref_type(const char *refname);
+/*
+ * Parse a `maybe_worktree_ref` as a ref that possibly refers to a worktree ref
+ * (ie. either REFNAME, main-worktree/REFNAME or worktree/WORKTREE/REFNAME). It
+ * returns what kind of ref was found, and in case of REF_WORKTREE_OTHER, the
+ * worktree name is returned in `worktree_name` (pointing into
+ * `maybe_worktree_ref`) and `worktree_name_length`. The bare refname (the
+ * refname stripped of prefixes) is returned in `bare_refname`. The
+ * `worktree_name`, `worktree_name_length` and `bare_refname` arguments may be
+ * NULL.
+ */
+enum ref_worktree_type parse_worktree_ref(const char *maybe_worktree_ref,
+ const char **worktree_name,
+ int *worktree_name_length,
+ const char **bare_refname);
enum expire_reflog_flags {
EXPIRE_REFLOGS_DRY_RUN = 1 << 0,
diff --git a/refs/files-backend.c b/refs/files-backend.c
index e4009b3c42..b89954355d 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -138,44 +138,30 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
return refs;
}
-static void files_reflog_path_other_worktrees(struct files_ref_store *refs,
- struct strbuf *sb,
- const char *refname)
-{
- const char *real_ref;
- const char *worktree_name;
- int length;
-
- if (parse_worktree_ref(refname, &worktree_name, &length, &real_ref))
- BUG("refname %s is not a other-worktree ref", refname);
-
- if (worktree_name)
- strbuf_addf(sb, "%s/worktrees/%.*s/logs/%s", refs->gitcommondir,
- length, worktree_name, real_ref);
- else
- strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir,
- real_ref);
-}
-
static void files_reflog_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
{
- switch (ref_type(refname)) {
- case REF_TYPE_PER_WORKTREE:
- case REF_TYPE_PSEUDOREF:
+ const char *bare_refname;
+ const char *wtname;
+ int wtname_len;
+ enum ref_worktree_type wt_type = parse_worktree_ref(
+ refname, &wtname, &wtname_len, &bare_refname);
+
+ switch (wt_type) {
+ case REF_WORKTREE_CURRENT:
strbuf_addf(sb, "%s/logs/%s", refs->base.gitdir, refname);
break;
- case REF_TYPE_OTHER_PSEUDOREF:
- case REF_TYPE_MAIN_PSEUDOREF:
- files_reflog_path_other_worktrees(refs, sb, refname);
+ case REF_WORKTREE_SHARED:
+ case REF_WORKTREE_MAIN:
+ strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, bare_refname);
break;
- case REF_TYPE_NORMAL:
- strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
+ case REF_WORKTREE_OTHER:
+ strbuf_addf(sb, "%s/worktrees/%.*s/logs/%s", refs->gitcommondir,
+ wtname_len, wtname, bare_refname);
break;
default:
- BUG("unknown ref type %d of ref %s",
- ref_type(refname), refname);
+ BUG("unknown ref type %d of ref %s", wt_type, refname);
}
}
@@ -183,22 +169,25 @@ static void files_ref_path(struct files_ref_store *refs,
struct strbuf *sb,
const char *refname)
{
- switch (ref_type(refname)) {
- case REF_TYPE_PER_WORKTREE:
- case REF_TYPE_PSEUDOREF:
+ const char *bare_refname;
+ const char *wtname;
+ int wtname_len;
+ enum ref_worktree_type wt_type = parse_worktree_ref(
+ refname, &wtname, &wtname_len, &bare_refname);
+ switch (wt_type) {
+ case REF_WORKTREE_CURRENT:
strbuf_addf(sb, "%s/%s", refs->base.gitdir, refname);
break;
- case REF_TYPE_MAIN_PSEUDOREF:
- if (!skip_prefix(refname, "main-worktree/", &refname))
- BUG("ref %s is not a main pseudoref", refname);
- /* fallthrough */
- case REF_TYPE_OTHER_PSEUDOREF:
- case REF_TYPE_NORMAL:
- strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
+ case REF_WORKTREE_OTHER:
+ strbuf_addf(sb, "%s/worktrees/%.*s/%s", refs->gitcommondir,
+ wtname_len, wtname, bare_refname);
+ break;
+ case REF_WORKTREE_SHARED:
+ case REF_WORKTREE_MAIN:
+ strbuf_addf(sb, "%s/%s", refs->gitcommondir, bare_refname);
break;
default:
- BUG("unknown ref type %d of ref %s",
- ref_type(refname), refname);
+ BUG("unknown ref type %d of ref %s", wt_type, refname);
}
}
@@ -771,7 +760,8 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
- ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)
+ parse_worktree_ref(iter->iter0->refname, NULL, NULL,
+ NULL) != REF_WORKTREE_CURRENT)
continue;
if ((iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS) &&
@@ -1178,7 +1168,8 @@ static int should_pack_ref(const char *refname,
unsigned int pack_flags)
{
/* Do not pack per-worktree refs: */
- if (ref_type(refname) != REF_TYPE_NORMAL)
+ if (parse_worktree_ref(refname, NULL, NULL, NULL) !=
+ REF_WORKTREE_SHARED)
return 0;
/* Do not pack non-tags unless PACK_REFS_ALL is set: */
@@ -2267,7 +2258,8 @@ static enum iterator_selection reflog_iterator_select(
*/
return ITER_SELECT_0;
} else if (iter_common) {
- if (ref_type(iter_common->refname) == REF_TYPE_NORMAL)
+ if (parse_worktree_ref(iter_common->refname, NULL, NULL,
+ NULL) == REF_WORKTREE_SHARED)
return ITER_SELECT_1;
/*
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 43cdb97f8b..c1c71d183e 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -862,7 +862,7 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
while ((ok = next_record(iter)) == ITER_OK) {
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
- ref_type(iter->base.refname) != REF_TYPE_PER_WORKTREE)
+ !is_per_worktree_ref(iter->base.refname))
continue;
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
diff --git a/worktree.c b/worktree.c
index 257ba4cf1e..aa43c64119 100644
--- a/worktree.c
+++ b/worktree.c
@@ -489,62 +489,17 @@ int submodule_uses_worktrees(const char *path)
return ret;
}
-int parse_worktree_ref(const char *worktree_ref, const char **name,
- int *name_length, const char **ref)
-{
- if (skip_prefix(worktree_ref, "main-worktree/", &worktree_ref)) {
- if (!*worktree_ref)
- return -1;
- if (name)
- *name = NULL;
- if (name_length)
- *name_length = 0;
- if (ref)
- *ref = worktree_ref;
- return 0;
- }
- if (skip_prefix(worktree_ref, "worktrees/", &worktree_ref)) {
- const char *slash = strchr(worktree_ref, '/');
-
- if (!slash || slash == worktree_ref || !slash[1])
- return -1;
- if (name)
- *name = worktree_ref;
- if (name_length)
- *name_length = slash - worktree_ref;
- if (ref)
- *ref = slash + 1;
- return 0;
- }
- return -1;
-}
-
void strbuf_worktree_ref(const struct worktree *wt,
struct strbuf *sb,
const char *refname)
{
- switch (ref_type(refname)) {
- case REF_TYPE_PSEUDOREF:
- case REF_TYPE_PER_WORKTREE:
- if (wt && !wt->is_current) {
- if (is_main_worktree(wt))
- strbuf_addstr(sb, "main-worktree/");
- else
- strbuf_addf(sb, "worktrees/%s/", wt->id);
- }
- break;
-
- case REF_TYPE_MAIN_PSEUDOREF:
- case REF_TYPE_OTHER_PSEUDOREF:
- break;
-
- case REF_TYPE_NORMAL:
- /*
- * For shared refs, don't prefix worktrees/ or
- * main-worktree/. It's not necessary and
- * files-backend.c can't handle it anyway.
- */
- break;
+ if (parse_worktree_ref(refname, NULL, NULL, NULL) ==
+ REF_WORKTREE_CURRENT &&
+ wt && !wt->is_current) {
+ if (is_main_worktree(wt))
+ strbuf_addstr(sb, "main-worktree/");
+ else
+ strbuf_addf(sb, "worktrees/%s/", wt->id);
}
strbuf_addstr(sb, refname);
}
diff --git a/worktree.h b/worktree.h
index e9e839926b..9dcea6fc8c 100644
--- a/worktree.h
+++ b/worktree.h
@@ -167,16 +167,6 @@ const char *worktree_git_path(const struct worktree *wt,
__attribute__((format (printf, 2, 3)));
/*
- * Parse a worktree ref (i.e. with prefix main-worktree/ or
- * worktrees/) and return the position of the worktree's name and
- * length (or NULL and zero if it's main worktree), and ref.
- *
- * All name, name_length and ref arguments could be NULL.
- */
-int parse_worktree_ref(const char *worktree_ref, const char **name,
- int *name_length, const char **ref);
-
-/*
* Return a refname suitable for access from the current ref store.
*/
void strbuf_worktree_ref(const struct worktree *wt,