Skip to content

Commit 38bb92c

Browse files
committed
Merge branch 'hn/parse-worktree-ref'
Code and semantics cleaning. * hn/parse-worktree-ref: refs: unify parse_worktree_ref() and ref_type()
2 parents dc154c3 + 71e5473 commit 38bb92c

File tree

8 files changed

+126
-150
lines changed

8 files changed

+126
-150
lines changed

builtin/reflog.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ static int collect_reflog(const char *ref, const struct object_id *oid UNUSED,
6767
* Avoid collecting the same shared ref multiple times because
6868
* they are available via all worktrees.
6969
*/
70-
if (!worktree->is_current && ref_type(ref) == REF_TYPE_NORMAL)
70+
if (!worktree->is_current &&
71+
parse_worktree_ref(ref, NULL, NULL, NULL) == REF_WORKTREE_SHARED)
7172
return 0;
7273

7374
strbuf_worktree_ref(worktree, &newref, ref);

reflog.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -312,16 +312,9 @@ static int push_tip_to_list(const char *refname UNUSED,
312312

313313
static int is_head(const char *refname)
314314
{
315-
switch (ref_type(refname)) {
316-
case REF_TYPE_OTHER_PSEUDOREF:
317-
case REF_TYPE_MAIN_PSEUDOREF:
318-
if (parse_worktree_ref(refname, NULL, NULL, &refname))
319-
BUG("not a worktree ref: %s", refname);
320-
break;
321-
default:
322-
break;
323-
}
324-
return !strcmp(refname, "HEAD");
315+
const char *stripped_refname;
316+
parse_worktree_ref(refname, NULL, NULL, &stripped_refname);
317+
return !strcmp(stripped_refname, "HEAD");
325318
}
326319

327320
void reflog_expiry_prepare(const char *refname,

refs.c

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
811811
return repo_dwim_log(the_repository, str, len, oid, log);
812812
}
813813

814-
static int is_per_worktree_ref(const char *refname)
814+
int is_per_worktree_ref(const char *refname)
815815
{
816816
return starts_with(refname, "refs/worktree/") ||
817817
starts_with(refname, "refs/bisect/") ||
@@ -827,37 +827,63 @@ static int is_pseudoref_syntax(const char *refname)
827827
return 0;
828828
}
829829

830+
/*
831+
* HEAD is not a pseudoref, but it certainly uses the
832+
* pseudoref syntax.
833+
*/
830834
return 1;
831835
}
832836

833-
static int is_main_pseudoref_syntax(const char *refname)
834-
{
835-
return skip_prefix(refname, "main-worktree/", &refname) &&
836-
*refname &&
837-
is_pseudoref_syntax(refname);
837+
static int is_current_worktree_ref(const char *ref) {
838+
return is_pseudoref_syntax(ref) || is_per_worktree_ref(ref);
838839
}
839840

840-
static int is_other_pseudoref_syntax(const char *refname)
841+
enum ref_worktree_type parse_worktree_ref(const char *maybe_worktree_ref,
842+
const char **worktree_name, int *worktree_name_length,
843+
const char **bare_refname)
841844
{
842-
if (!skip_prefix(refname, "worktrees/", &refname))
843-
return 0;
844-
refname = strchr(refname, '/');
845-
if (!refname || !refname[1])
846-
return 0;
847-
return is_pseudoref_syntax(refname + 1);
848-
}
845+
const char *name_dummy;
846+
int name_length_dummy;
847+
const char *ref_dummy;
849848

850-
enum ref_type ref_type(const char *refname)
851-
{
852-
if (is_per_worktree_ref(refname))
853-
return REF_TYPE_PER_WORKTREE;
854-
if (is_pseudoref_syntax(refname))
855-
return REF_TYPE_PSEUDOREF;
856-
if (is_main_pseudoref_syntax(refname))
857-
return REF_TYPE_MAIN_PSEUDOREF;
858-
if (is_other_pseudoref_syntax(refname))
859-
return REF_TYPE_OTHER_PSEUDOREF;
860-
return REF_TYPE_NORMAL;
849+
if (!worktree_name)
850+
worktree_name = &name_dummy;
851+
if (!worktree_name_length)
852+
worktree_name_length = &name_length_dummy;
853+
if (!bare_refname)
854+
bare_refname = &ref_dummy;
855+
856+
if (skip_prefix(maybe_worktree_ref, "worktrees/", bare_refname)) {
857+
const char *slash = strchr(*bare_refname, '/');
858+
859+
*worktree_name = *bare_refname;
860+
if (!slash) {
861+
*worktree_name_length = strlen(*worktree_name);
862+
863+
/* This is an error condition, and the caller tell because the bare_refname is "" */
864+
*bare_refname = *worktree_name + *worktree_name_length;
865+
return REF_WORKTREE_OTHER;
866+
}
867+
868+
*worktree_name_length = slash - *bare_refname;
869+
*bare_refname = slash + 1;
870+
871+
if (is_current_worktree_ref(*bare_refname))
872+
return REF_WORKTREE_OTHER;
873+
}
874+
875+
*worktree_name = NULL;
876+
*worktree_name_length = 0;
877+
878+
if (skip_prefix(maybe_worktree_ref, "main-worktree/", bare_refname)
879+
&& is_current_worktree_ref(*bare_refname))
880+
return REF_WORKTREE_MAIN;
881+
882+
*bare_refname = maybe_worktree_ref;
883+
if (is_current_worktree_ref(maybe_worktree_ref))
884+
return REF_WORKTREE_CURRENT;
885+
886+
return REF_WORKTREE_SHARED;
861887
}
862888

863889
long get_files_ref_lock_timeout_ms(void)

refs.h

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -820,15 +820,34 @@ int parse_hide_refs_config(const char *var, const char *value, const char *);
820820
*/
821821
int ref_is_hidden(const char *, const char *);
822822

823-
enum ref_type {
824-
REF_TYPE_PER_WORKTREE, /* refs inside refs/ but not shared */
825-
REF_TYPE_PSEUDOREF, /* refs outside refs/ in current worktree */
826-
REF_TYPE_MAIN_PSEUDOREF, /* pseudo refs from the main worktree */
827-
REF_TYPE_OTHER_PSEUDOREF, /* pseudo refs from other worktrees */
828-
REF_TYPE_NORMAL, /* normal/shared refs inside refs/ */
823+
/* Is this a per-worktree ref living in the refs/ namespace? */
824+
int is_per_worktree_ref(const char *refname);
825+
826+
/* Describes how a refname relates to worktrees */
827+
enum ref_worktree_type {
828+
REF_WORKTREE_CURRENT, /* implicitly per worktree, eg. HEAD or
829+
refs/bisect/SOMETHING */
830+
REF_WORKTREE_MAIN, /* explicitly in main worktree, eg.
831+
main-worktree/HEAD */
832+
REF_WORKTREE_OTHER, /* explicitly in named worktree, eg.
833+
worktrees/bla/HEAD */
834+
REF_WORKTREE_SHARED, /* the default, eg. refs/heads/main */
829835
};
830836

831-
enum ref_type ref_type(const char *refname);
837+
/*
838+
* Parse a `maybe_worktree_ref` as a ref that possibly refers to a worktree ref
839+
* (ie. either REFNAME, main-worktree/REFNAME or worktree/WORKTREE/REFNAME). It
840+
* returns what kind of ref was found, and in case of REF_WORKTREE_OTHER, the
841+
* worktree name is returned in `worktree_name` (pointing into
842+
* `maybe_worktree_ref`) and `worktree_name_length`. The bare refname (the
843+
* refname stripped of prefixes) is returned in `bare_refname`. The
844+
* `worktree_name`, `worktree_name_length` and `bare_refname` arguments may be
845+
* NULL.
846+
*/
847+
enum ref_worktree_type parse_worktree_ref(const char *maybe_worktree_ref,
848+
const char **worktree_name,
849+
int *worktree_name_length,
850+
const char **bare_refname);
832851

833852
enum expire_reflog_flags {
834853
EXPIRE_REFLOGS_DRY_RUN = 1 << 0,

refs/files-backend.c

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -138,67 +138,56 @@ static struct files_ref_store *files_downcast(struct ref_store *ref_store,
138138
return refs;
139139
}
140140

141-
static void files_reflog_path_other_worktrees(struct files_ref_store *refs,
142-
struct strbuf *sb,
143-
const char *refname)
144-
{
145-
const char *real_ref;
146-
const char *worktree_name;
147-
int length;
148-
149-
if (parse_worktree_ref(refname, &worktree_name, &length, &real_ref))
150-
BUG("refname %s is not a other-worktree ref", refname);
151-
152-
if (worktree_name)
153-
strbuf_addf(sb, "%s/worktrees/%.*s/logs/%s", refs->gitcommondir,
154-
length, worktree_name, real_ref);
155-
else
156-
strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir,
157-
real_ref);
158-
}
159-
160141
static void files_reflog_path(struct files_ref_store *refs,
161142
struct strbuf *sb,
162143
const char *refname)
163144
{
164-
switch (ref_type(refname)) {
165-
case REF_TYPE_PER_WORKTREE:
166-
case REF_TYPE_PSEUDOREF:
145+
const char *bare_refname;
146+
const char *wtname;
147+
int wtname_len;
148+
enum ref_worktree_type wt_type = parse_worktree_ref(
149+
refname, &wtname, &wtname_len, &bare_refname);
150+
151+
switch (wt_type) {
152+
case REF_WORKTREE_CURRENT:
167153
strbuf_addf(sb, "%s/logs/%s", refs->base.gitdir, refname);
168154
break;
169-
case REF_TYPE_OTHER_PSEUDOREF:
170-
case REF_TYPE_MAIN_PSEUDOREF:
171-
files_reflog_path_other_worktrees(refs, sb, refname);
155+
case REF_WORKTREE_SHARED:
156+
case REF_WORKTREE_MAIN:
157+
strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, bare_refname);
172158
break;
173-
case REF_TYPE_NORMAL:
174-
strbuf_addf(sb, "%s/logs/%s", refs->gitcommondir, refname);
159+
case REF_WORKTREE_OTHER:
160+
strbuf_addf(sb, "%s/worktrees/%.*s/logs/%s", refs->gitcommondir,
161+
wtname_len, wtname, bare_refname);
175162
break;
176163
default:
177-
BUG("unknown ref type %d of ref %s",
178-
ref_type(refname), refname);
164+
BUG("unknown ref type %d of ref %s", wt_type, refname);
179165
}
180166
}
181167

182168
static void files_ref_path(struct files_ref_store *refs,
183169
struct strbuf *sb,
184170
const char *refname)
185171
{
186-
switch (ref_type(refname)) {
187-
case REF_TYPE_PER_WORKTREE:
188-
case REF_TYPE_PSEUDOREF:
172+
const char *bare_refname;
173+
const char *wtname;
174+
int wtname_len;
175+
enum ref_worktree_type wt_type = parse_worktree_ref(
176+
refname, &wtname, &wtname_len, &bare_refname);
177+
switch (wt_type) {
178+
case REF_WORKTREE_CURRENT:
189179
strbuf_addf(sb, "%s/%s", refs->base.gitdir, refname);
190180
break;
191-
case REF_TYPE_MAIN_PSEUDOREF:
192-
if (!skip_prefix(refname, "main-worktree/", &refname))
193-
BUG("ref %s is not a main pseudoref", refname);
194-
/* fallthrough */
195-
case REF_TYPE_OTHER_PSEUDOREF:
196-
case REF_TYPE_NORMAL:
197-
strbuf_addf(sb, "%s/%s", refs->gitcommondir, refname);
181+
case REF_WORKTREE_OTHER:
182+
strbuf_addf(sb, "%s/worktrees/%.*s/%s", refs->gitcommondir,
183+
wtname_len, wtname, bare_refname);
184+
break;
185+
case REF_WORKTREE_SHARED:
186+
case REF_WORKTREE_MAIN:
187+
strbuf_addf(sb, "%s/%s", refs->gitcommondir, bare_refname);
198188
break;
199189
default:
200-
BUG("unknown ref type %d of ref %s",
201-
ref_type(refname), refname);
190+
BUG("unknown ref type %d of ref %s", wt_type, refname);
202191
}
203192
}
204193

@@ -771,7 +760,8 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
771760

772761
while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
773762
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
774-
ref_type(iter->iter0->refname) != REF_TYPE_PER_WORKTREE)
763+
parse_worktree_ref(iter->iter0->refname, NULL, NULL,
764+
NULL) != REF_WORKTREE_CURRENT)
775765
continue;
776766

777767
if ((iter->flags & DO_FOR_EACH_OMIT_DANGLING_SYMREFS) &&
@@ -1178,7 +1168,8 @@ static int should_pack_ref(const char *refname,
11781168
unsigned int pack_flags)
11791169
{
11801170
/* Do not pack per-worktree refs: */
1181-
if (ref_type(refname) != REF_TYPE_NORMAL)
1171+
if (parse_worktree_ref(refname, NULL, NULL, NULL) !=
1172+
REF_WORKTREE_SHARED)
11821173
return 0;
11831174

11841175
/* Do not pack non-tags unless PACK_REFS_ALL is set: */
@@ -2267,7 +2258,8 @@ static enum iterator_selection reflog_iterator_select(
22672258
*/
22682259
return ITER_SELECT_0;
22692260
} else if (iter_common) {
2270-
if (ref_type(iter_common->refname) == REF_TYPE_NORMAL)
2261+
if (parse_worktree_ref(iter_common->refname, NULL, NULL,
2262+
NULL) == REF_WORKTREE_SHARED)
22712263
return ITER_SELECT_1;
22722264

22732265
/*

refs/packed-backend.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ static int packed_ref_iterator_advance(struct ref_iterator *ref_iterator)
862862

863863
while ((ok = next_record(iter)) == ITER_OK) {
864864
if (iter->flags & DO_FOR_EACH_PER_WORKTREE_ONLY &&
865-
ref_type(iter->base.refname) != REF_TYPE_PER_WORKTREE)
865+
!is_per_worktree_ref(iter->base.refname))
866866
continue;
867867

868868
if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&

worktree.c

Lines changed: 7 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -489,62 +489,17 @@ int submodule_uses_worktrees(const char *path)
489489
return ret;
490490
}
491491

492-
int parse_worktree_ref(const char *worktree_ref, const char **name,
493-
int *name_length, const char **ref)
494-
{
495-
if (skip_prefix(worktree_ref, "main-worktree/", &worktree_ref)) {
496-
if (!*worktree_ref)
497-
return -1;
498-
if (name)
499-
*name = NULL;
500-
if (name_length)
501-
*name_length = 0;
502-
if (ref)
503-
*ref = worktree_ref;
504-
return 0;
505-
}
506-
if (skip_prefix(worktree_ref, "worktrees/", &worktree_ref)) {
507-
const char *slash = strchr(worktree_ref, '/');
508-
509-
if (!slash || slash == worktree_ref || !slash[1])
510-
return -1;
511-
if (name)
512-
*name = worktree_ref;
513-
if (name_length)
514-
*name_length = slash - worktree_ref;
515-
if (ref)
516-
*ref = slash + 1;
517-
return 0;
518-
}
519-
return -1;
520-
}
521-
522492
void strbuf_worktree_ref(const struct worktree *wt,
523493
struct strbuf *sb,
524494
const char *refname)
525495
{
526-
switch (ref_type(refname)) {
527-
case REF_TYPE_PSEUDOREF:
528-
case REF_TYPE_PER_WORKTREE:
529-
if (wt && !wt->is_current) {
530-
if (is_main_worktree(wt))
531-
strbuf_addstr(sb, "main-worktree/");
532-
else
533-
strbuf_addf(sb, "worktrees/%s/", wt->id);
534-
}
535-
break;
536-
537-
case REF_TYPE_MAIN_PSEUDOREF:
538-
case REF_TYPE_OTHER_PSEUDOREF:
539-
break;
540-
541-
case REF_TYPE_NORMAL:
542-
/*
543-
* For shared refs, don't prefix worktrees/ or
544-
* main-worktree/. It's not necessary and
545-
* files-backend.c can't handle it anyway.
546-
*/
547-
break;
496+
if (parse_worktree_ref(refname, NULL, NULL, NULL) ==
497+
REF_WORKTREE_CURRENT &&
498+
wt && !wt->is_current) {
499+
if (is_main_worktree(wt))
500+
strbuf_addstr(sb, "main-worktree/");
501+
else
502+
strbuf_addf(sb, "worktrees/%s/", wt->id);
548503
}
549504
strbuf_addstr(sb, refname);
550505
}

worktree.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,6 @@ const char *worktree_git_path(const struct worktree *wt,
166166
const char *fmt, ...)
167167
__attribute__((format (printf, 2, 3)));
168168

169-
/*
170-
* Parse a worktree ref (i.e. with prefix main-worktree/ or
171-
* worktrees/) and return the position of the worktree's name and
172-
* length (or NULL and zero if it's main worktree), and ref.
173-
*
174-
* All name, name_length and ref arguments could be NULL.
175-
*/
176-
int parse_worktree_ref(const char *worktree_ref, const char **name,
177-
int *name_length, const char **ref);
178-
179169
/*
180170
* Return a refname suitable for access from the current ref store.
181171
*/

0 commit comments

Comments
 (0)