Skip to content

Commit 6f22780

Browse files
pks-tgitster
authored andcommitted
refs/files: sort merged worktree and common reflogs
When iterating through reflogs in a worktree we create a merged iterator that merges reflogs from both refdbs. The resulting refs are ordered so that instead we first return all worktree reflogs before we return all common refs. This is the only remaining case where a ref iterator returns entries in a non-lexicographic order. The result would look something like the following (listed with a command we introduce in a subsequent commit): ``` $ git reflog list HEAD refs/worktree/per-worktree refs/heads/main refs/heads/wt ``` So we first print the per-worktree reflogs in lexicographic order, then the common reflogs in lexicographic order. This is confusing and not consistent with how we print per-worktree refs, which are exclusively sorted lexicographically. Sort reflogs lexicographically in the same way as we sort normal refs. As this is already implemented properly by the "reftable" backend via a separate selection function, we simply pull out that logic and reuse it for the "files" backend. As logs are properly sorted now, mark the merged reflog iterator as sorted. Tests will be added in a subsequent commit. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e69e8ff commit 6f22780

File tree

4 files changed

+56
-73
lines changed

4 files changed

+56
-73
lines changed

refs/files-backend.c

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2210,32 +2210,6 @@ static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
22102210
return ref_iterator;
22112211
}
22122212

2213-
static enum iterator_selection reflog_iterator_select(
2214-
struct ref_iterator *iter_worktree,
2215-
struct ref_iterator *iter_common,
2216-
void *cb_data UNUSED)
2217-
{
2218-
if (iter_worktree) {
2219-
/*
2220-
* We're a bit loose here. We probably should ignore
2221-
* common refs if they are accidentally added as
2222-
* per-worktree refs.
2223-
*/
2224-
return ITER_SELECT_0;
2225-
} else if (iter_common) {
2226-
if (parse_worktree_ref(iter_common->refname, NULL, NULL,
2227-
NULL) == REF_WORKTREE_SHARED)
2228-
return ITER_SELECT_1;
2229-
2230-
/*
2231-
* The main ref store may contain main worktree's
2232-
* per-worktree refs, which should be ignored
2233-
*/
2234-
return ITER_SKIP_1;
2235-
} else
2236-
return ITER_DONE;
2237-
}
2238-
22392213
static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store)
22402214
{
22412215
struct files_ref_store *refs =
@@ -2246,9 +2220,9 @@ static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_st
22462220
return reflog_iterator_begin(ref_store, refs->gitcommondir);
22472221
} else {
22482222
return merge_ref_iterator_begin(
2249-
0, reflog_iterator_begin(ref_store, refs->base.gitdir),
2223+
1, reflog_iterator_begin(ref_store, refs->base.gitdir),
22502224
reflog_iterator_begin(ref_store, refs->gitcommondir),
2251-
reflog_iterator_select, refs);
2225+
ref_iterator_select, refs);
22522226
}
22532227
}
22542228

refs/iterator.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,49 @@ struct merge_ref_iterator {
9898
struct ref_iterator **current;
9999
};
100100

101+
enum iterator_selection ref_iterator_select(struct ref_iterator *iter_worktree,
102+
struct ref_iterator *iter_common,
103+
void *cb_data UNUSED)
104+
{
105+
if (iter_worktree && !iter_common) {
106+
/*
107+
* Return the worktree ref if there are no more common refs.
108+
*/
109+
return ITER_SELECT_0;
110+
} else if (iter_common) {
111+
/*
112+
* In case we have pending worktree and common refs we need to
113+
* yield them based on their lexicographical order. Worktree
114+
* refs that have the same name as common refs shadow the
115+
* latter.
116+
*/
117+
if (iter_worktree) {
118+
int cmp = strcmp(iter_worktree->refname,
119+
iter_common->refname);
120+
if (cmp < 0)
121+
return ITER_SELECT_0;
122+
else if (!cmp)
123+
return ITER_SELECT_0_SKIP_1;
124+
}
125+
126+
/*
127+
* We now know that the lexicographically-next ref is a common
128+
* ref. When the common ref is a shared one we return it.
129+
*/
130+
if (parse_worktree_ref(iter_common->refname, NULL, NULL,
131+
NULL) == REF_WORKTREE_SHARED)
132+
return ITER_SELECT_1;
133+
134+
/*
135+
* Otherwise, if the common ref is a per-worktree ref we skip
136+
* it because it would belong to the main worktree, not ours.
137+
*/
138+
return ITER_SKIP_1;
139+
} else {
140+
return ITER_DONE;
141+
}
142+
}
143+
101144
static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
102145
{
103146
struct merge_ref_iterator *iter =

refs/refs-internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,15 @@ typedef enum iterator_selection ref_iterator_select_fn(
386386
struct ref_iterator *iter0, struct ref_iterator *iter1,
387387
void *cb_data);
388388

389+
/*
390+
* An implementation of ref_iterator_select_fn that merges worktree and common
391+
* refs. Per-worktree refs from the common iterator are ignored, worktree refs
392+
* override common refs. Refs are selected lexicographically.
393+
*/
394+
enum iterator_selection ref_iterator_select(struct ref_iterator *iter_worktree,
395+
struct ref_iterator *iter_common,
396+
void *cb_data);
397+
389398
/*
390399
* Iterate over the entries from iter0 and iter1, with the values
391400
* interleaved as directed by the select function. The iterator takes

refs/reftable-backend.c

Lines changed: 2 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -504,49 +504,6 @@ static struct reftable_ref_iterator *ref_iterator_for_stack(struct reftable_ref_
504504
return iter;
505505
}
506506

507-
static enum iterator_selection iterator_select(struct ref_iterator *iter_worktree,
508-
struct ref_iterator *iter_common,
509-
void *cb_data UNUSED)
510-
{
511-
if (iter_worktree && !iter_common) {
512-
/*
513-
* Return the worktree ref if there are no more common refs.
514-
*/
515-
return ITER_SELECT_0;
516-
} else if (iter_common) {
517-
/*
518-
* In case we have pending worktree and common refs we need to
519-
* yield them based on their lexicographical order. Worktree
520-
* refs that have the same name as common refs shadow the
521-
* latter.
522-
*/
523-
if (iter_worktree) {
524-
int cmp = strcmp(iter_worktree->refname,
525-
iter_common->refname);
526-
if (cmp < 0)
527-
return ITER_SELECT_0;
528-
else if (!cmp)
529-
return ITER_SELECT_0_SKIP_1;
530-
}
531-
532-
/*
533-
* We now know that the lexicographically-next ref is a common
534-
* ref. When the common ref is a shared one we return it.
535-
*/
536-
if (parse_worktree_ref(iter_common->refname, NULL, NULL,
537-
NULL) == REF_WORKTREE_SHARED)
538-
return ITER_SELECT_1;
539-
540-
/*
541-
* Otherwise, if the common ref is a per-worktree ref we skip
542-
* it because it would belong to the main worktree, not ours.
543-
*/
544-
return ITER_SKIP_1;
545-
} else {
546-
return ITER_DONE;
547-
}
548-
}
549-
550507
static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_store,
551508
const char *prefix,
552509
const char **exclude_patterns,
@@ -576,7 +533,7 @@ static struct ref_iterator *reftable_be_iterator_begin(struct ref_store *ref_sto
576533
*/
577534
worktree_iter = ref_iterator_for_stack(refs, refs->worktree_stack, prefix, flags);
578535
return merge_ref_iterator_begin(1, &worktree_iter->base, &main_iter->base,
579-
iterator_select, NULL);
536+
ref_iterator_select, NULL);
580537
}
581538

582539
static int reftable_be_read_raw_ref(struct ref_store *ref_store,
@@ -1759,7 +1716,7 @@ static struct ref_iterator *reftable_be_reflog_iterator_begin(struct ref_store *
17591716
worktree_iter = reflog_iterator_for_stack(refs, refs->worktree_stack);
17601717

17611718
return merge_ref_iterator_begin(1, &worktree_iter->base, &main_iter->base,
1762-
iterator_select, NULL);
1719+
ref_iterator_select, NULL);
17631720
}
17641721

17651722
static int yield_log_record(struct reftable_log_record *log,

0 commit comments

Comments
 (0)