Merge branch 'hn/parse-worktree-ref'
Code and semantics cleaning. * hn/parse-worktree-ref: refs: unify parse_worktree_ref() and ref_type()
This commit is contained in:
commit
38bb92cf46
@ -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
|
* Avoid collecting the same shared ref multiple times because
|
||||||
* they are available via all worktrees.
|
* 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;
|
return 0;
|
||||||
|
|
||||||
strbuf_worktree_ref(worktree, &newref, ref);
|
strbuf_worktree_ref(worktree, &newref, ref);
|
||||||
|
13
reflog.c
13
reflog.c
@ -312,16 +312,9 @@ static int push_tip_to_list(const char *refname UNUSED,
|
|||||||
|
|
||||||
static int is_head(const char *refname)
|
static int is_head(const char *refname)
|
||||||
{
|
{
|
||||||
switch (ref_type(refname)) {
|
const char *stripped_refname;
|
||||||
case REF_TYPE_OTHER_PSEUDOREF:
|
parse_worktree_ref(refname, NULL, NULL, &stripped_refname);
|
||||||
case REF_TYPE_MAIN_PSEUDOREF:
|
return !strcmp(stripped_refname, "HEAD");
|
||||||
if (parse_worktree_ref(refname, NULL, NULL, &refname))
|
|
||||||
BUG("not a worktree ref: %s", refname);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return !strcmp(refname, "HEAD");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reflog_expiry_prepare(const char *refname,
|
void reflog_expiry_prepare(const char *refname,
|
||||||
|
76
refs.c
76
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);
|
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/") ||
|
return starts_with(refname, "refs/worktree/") ||
|
||||||
starts_with(refname, "refs/bisect/") ||
|
starts_with(refname, "refs/bisect/") ||
|
||||||
@ -827,37 +827,63 @@ static int is_pseudoref_syntax(const char *refname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HEAD is not a pseudoref, but it certainly uses the
|
||||||
|
* pseudoref syntax.
|
||||||
|
*/
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_main_pseudoref_syntax(const char *refname)
|
static int is_current_worktree_ref(const char *ref) {
|
||||||
{
|
return is_pseudoref_syntax(ref) || is_per_worktree_ref(ref);
|
||||||
return skip_prefix(refname, "main-worktree/", &refname) &&
|
|
||||||
*refname &&
|
|
||||||
is_pseudoref_syntax(refname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
const char *name_dummy;
|
||||||
return 0;
|
int name_length_dummy;
|
||||||
refname = strchr(refname, '/');
|
const char *ref_dummy;
|
||||||
if (!refname || !refname[1])
|
|
||||||
return 0;
|
|
||||||
return is_pseudoref_syntax(refname + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ref_type ref_type(const char *refname)
|
if (!worktree_name)
|
||||||
{
|
worktree_name = &name_dummy;
|
||||||
if (is_per_worktree_ref(refname))
|
if (!worktree_name_length)
|
||||||
return REF_TYPE_PER_WORKTREE;
|
worktree_name_length = &name_length_dummy;
|
||||||
if (is_pseudoref_syntax(refname))
|
if (!bare_refname)
|
||||||
return REF_TYPE_PSEUDOREF;
|
bare_refname = &ref_dummy;
|
||||||
if (is_main_pseudoref_syntax(refname))
|
|
||||||
return REF_TYPE_MAIN_PSEUDOREF;
|
if (skip_prefix(maybe_worktree_ref, "worktrees/", bare_refname)) {
|
||||||
if (is_other_pseudoref_syntax(refname))
|
const char *slash = strchr(*bare_refname, '/');
|
||||||
return REF_TYPE_OTHER_PSEUDOREF;
|
|
||||||
return REF_TYPE_NORMAL;
|
*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)
|
long get_files_ref_lock_timeout_ms(void)
|
||||||
|
33
refs.h
33
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 *);
|
int ref_is_hidden(const char *, const char *);
|
||||||
|
|
||||||
enum ref_type {
|
/* Is this a per-worktree ref living in the refs/ namespace? */
|
||||||
REF_TYPE_PER_WORKTREE, /* refs inside refs/ but not shared */
|
int is_per_worktree_ref(const char *refname);
|
||||||
REF_TYPE_PSEUDOREF, /* refs outside refs/ in current worktree */
|
|
||||||
REF_TYPE_MAIN_PSEUDOREF, /* pseudo refs from the main worktree */
|
/* Describes how a refname relates to worktrees */
|
||||||
REF_TYPE_OTHER_PSEUDOREF, /* pseudo refs from other worktrees */
|
enum ref_worktree_type {
|
||||||
REF_TYPE_NORMAL, /* normal/shared refs inside refs/ */
|
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 {
|
enum expire_reflog_flags {
|
||||||
EXPIRE_REFLOGS_DRY_RUN = 1 << 0,
|
EXPIRE_REFLOGS_DRY_RUN = 1 << 0,
|
||||||
|
@ -138,44 +138,30 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
|
|||||||
return refs;
|
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,
|
static void files_reflog_path(struct files_ref_store *refs,
|
||||||
struct strbuf *sb,
|
struct strbuf *sb,
|
||||||
const char *refname)
|
const char *refname)
|
||||||
{
|
{
|
||||||
switch (ref_type(refname)) {
|
const char *bare_refname;
|
||||||
case REF_TYPE_PER_WORKTREE:
|
const char *wtname;
|
||||||
case REF_TYPE_PSEUDOREF:
|
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);
|
strbuf_addf(sb, "%s/logs/%s", refs->base.gitdir, refname);
|
||||||
break;
|
break;
|
||||||
case REF_TYPE_OTHER_PSEUDOREF:
|
case REF_WORKTREE_SHARED:
|
||||||
case REF_TYPE_MAIN_PSEUDOREF:
|
case REF_WORKTREE_MAIN:
|
||||||
files_reflog_path_other_worktrees(refs, sb, refname);
|
strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, bare_refname);
|
||||||
break;
|
break;
|
||||||
case REF_TYPE_NORMAL:
|
case REF_WORKTREE_OTHER:
|
||||||
strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
|
strbuf_addf(sb, "%s/worktrees/%.*s/logs/%s", refs->gitcommondir,
|
||||||
|
wtname_len, wtname, bare_refname);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG("unknown ref type %d of ref %s",
|
BUG("unknown ref type %d of ref %s", wt_type, refname);
|
||||||
ref_type(refname), refname);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,22 +169,25 @@ static void files_ref_path(struct files_ref_store *refs,
|
|||||||
struct strbuf *sb,
|
struct strbuf *sb,
|
||||||
const char *refname)
|
const char *refname)
|
||||||
{
|
{
|
||||||
switch (ref_type(refname)) {
|
const char *bare_refname;
|
||||||
case REF_TYPE_PER_WORKTREE:
|
const char *wtname;
|
||||||
case REF_TYPE_PSEUDOREF:
|
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);
|
strbuf_addf(sb, "%s/%s", refs->base.gitdir, refname);
|
||||||
break;
|
break;
|
||||||
case REF_TYPE_MAIN_PSEUDOREF:
|
case REF_WORKTREE_OTHER:
|
||||||
if (!skip_prefix(refname, "main-worktree/", &refname))
|
strbuf_addf(sb, "%s/worktrees/%.*s/%s", refs->gitcommondir,
|
||||||
BUG("ref %s is not a main pseudoref", refname);
|
wtname_len, wtname, bare_refname);
|
||||||
/* fallthrough */
|
break;
|
||||||
case REF_TYPE_OTHER_PSEUDOREF:
|
case REF_WORKTREE_SHARED:
|
||||||
case REF_TYPE_NORMAL:
|
case REF_WORKTREE_MAIN:
|
||||||
strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
|
strbuf_addf(sb, "%s/%s", refs->gitcommondir, bare_refname);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG("unknown ref type %d of ref %s",
|
BUG("unknown ref type %d of ref %s", wt_type, refname);
|
||||||
ref_type(refname), 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) {
|
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
|
||||||
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
|
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;
|
continue;
|
||||||
|
|
||||||
if ((iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS) &&
|
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)
|
unsigned int pack_flags)
|
||||||
{
|
{
|
||||||
/* Do not pack per-worktree refs: */
|
/* 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;
|
return 0;
|
||||||
|
|
||||||
/* Do not pack non-tags unless PACK_REFS_ALL is set: */
|
/* 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;
|
return ITER_SELECT_0;
|
||||||
} else if (iter_common) {
|
} 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;
|
return ITER_SELECT_1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -862,7 +862,7 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
|
|||||||
|
|
||||||
while ((ok = next_record(iter)) == ITER_OK) {
|
while ((ok = next_record(iter)) == ITER_OK) {
|
||||||
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
|
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;
|
continue;
|
||||||
|
|
||||||
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
|
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
|
||||||
|
59
worktree.c
59
worktree.c
@ -489,62 +489,17 @@ int submodule_uses_worktrees(const char *path)
|
|||||||
return ret;
|
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,
|
void strbuf_worktree_ref(const struct worktree *wt,
|
||||||
struct strbuf *sb,
|
struct strbuf *sb,
|
||||||
const char *refname)
|
const char *refname)
|
||||||
{
|
{
|
||||||
switch (ref_type(refname)) {
|
if (parse_worktree_ref(refname, NULL, NULL, NULL) ==
|
||||||
case REF_TYPE_PSEUDOREF:
|
REF_WORKTREE_CURRENT &&
|
||||||
case REF_TYPE_PER_WORKTREE:
|
wt && !wt->is_current) {
|
||||||
if (wt && !wt->is_current) {
|
if (is_main_worktree(wt))
|
||||||
if (is_main_worktree(wt))
|
strbuf_addstr(sb, "main-worktree/");
|
||||||
strbuf_addstr(sb, "main-worktree/");
|
else
|
||||||
else
|
strbuf_addf(sb, "worktrees/%s/", wt->id);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
strbuf_addstr(sb, refname);
|
strbuf_addstr(sb, refname);
|
||||||
}
|
}
|
||||||
|
10
worktree.h
10
worktree.h
@ -166,16 +166,6 @@ const char *worktree_git_path(const struct worktree *wt,
|
|||||||
const char *fmt, ...)
|
const char *fmt, ...)
|
||||||
__attribute__((format (printf, 2, 3)));
|
__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.
|
* Return a refname suitable for access from the current ref store.
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user