files-backend: make reflog iterator go through per-worktree reflog
refs/bisect is unfortunately per-worktree, so we need to look in per-worktree logs/refs/bisect in addition to per-repo logs/refs. The current iterator only goes through per-repo logs/refs. Use merge iterator to walk two ref stores at the same time and pick per-worktree refs from the right iterator. PS. Note the unsorted order of for_each_reflog in the test. This is supposed to be OK, for now. If we enforce order on for_each_reflog() then some more work will be required. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nguyễn Thái Ngọc Duy committed
Aug 23, 2017 at 19:37 UTC
944b4e3013d6e21b1ecd2f2579395341f2cc8b7b
2 files changed
+75
-14
refs/files-backend.c
+45
-14
@@ -106,15 +106,6 @@ static void files_reflog_path(struct files_ref_store *refs,
106
struct strbuf *sb,
107
const char *refname)
108
{
109
- if (!refname) {
110
- /*
111
- * FIXME: of course this is wrong in multi worktree
112
- * setting. To be fixed real soon.
113
- */
114
- strbuf_addf(sb, "%s/logs", refs->gitcommondir);
115
- return;
116
- }
117
-
109
switch (ref_type(refname)) {
110
case REF_TYPE_PER_WORKTREE:
111
case REF_TYPE_PSEUDOREF:
@@ -2055,23 +2046,63 @@ static struct ref_iterator_vtable files_reflog_iterator_vtable = {
2046
files_reflog_iterator_abort
2047
};
2048
2058
-static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store)
2049
+static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store,
2050
+ const char *gitdir)
2051
{
2060
- struct files_ref_store *refs =
2061
- files_downcast(ref_store, REF_STORE_READ,
2062
- "reflog_iterator_begin");
2052
struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter));
2053
struct ref_iterator *ref_iterator = &iter->base;
2054
struct strbuf sb = STRBUF_INIT;
2055
2056
base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable);
2068
- files_reflog_path(refs, &sb, NULL);
2057
+ strbuf_addf(&sb, "%s/logs", gitdir);
2058
iter->dir_iterator = dir_iterator_begin(sb.buf);
2059
iter->ref_store = ref_store;
2060
strbuf_release(&sb);
2061
+
2062
return ref_iterator;
2063
}
2064
2065
+static enum iterator_selection reflog_iterator_select(
2066
+ struct ref_iterator *iter_worktree,
2067
+ struct ref_iterator *iter_common,
2068
+ void *cb_data)
2069
+{
2070
+ if (iter_worktree) {
2071
+ /*
2072
+ * We're a bit loose here. We probably should ignore
2073
+ * common refs if they are accidentally added as
2074
+ * per-worktree refs.
2075
+ */
2076
+ return ITER_SELECT_0;
2077
+ } else if (iter_common) {
2078
+ if (ref_type(iter_common->refname) == REF_TYPE_NORMAL)
2079
+ return ITER_SELECT_1;
2080
+
2081
+ /*
2082
+ * The main ref store may contain main worktree's
2083
+ * per-worktree refs, which should be ignored
2084
+ */
2085
+ return ITER_SKIP_1;
2086
+ } else
2087
+ return ITER_DONE;
2088
+}
2089
+
2090
+static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store)
2091
+{
2092
+ struct files_ref_store *refs =
2093
+ files_downcast(ref_store, REF_STORE_READ,
2094
+ "reflog_iterator_begin");
2095
+
2096
+ if (!strcmp(refs->gitdir, refs->gitcommondir)) {
2097
+ return reflog_iterator_begin(ref_store, refs->gitcommondir);
2098
+ } else {
2099
+ return merge_ref_iterator_begin(
2100
+ reflog_iterator_begin(ref_store, refs->gitdir),
2101
+ reflog_iterator_begin(ref_store, refs->gitcommondir),
2102
+ reflog_iterator_select, refs);
2103
+ }
2104
+}
2105
+
2106
/*
2107
* If update is a direct update of head_ref (the reference pointed to
2108
* by HEAD), then add an extra REF_LOG_ONLY update for HEAD.
t/t1407-worktree-ref-store.sh
+30
@@ -49,4 +49,34 @@ test_expect_success 'create_symref(FOO, refs/heads/master)' '
49
test_cmp expected actual
50
'
51
52
+test_expect_success 'for_each_reflog()' '
53
+ echo $_z40 > .git/logs/PSEUDO-MAIN &&
54
+ mkdir -p .git/logs/refs/bisect &&
55
+ echo $_z40 > .git/logs/refs/bisect/random &&
56
+
57
+ echo $_z40 > .git/worktrees/wt/logs/PSEUDO-WT &&
58
+ mkdir -p .git/worktrees/wt/logs/refs/bisect &&
59
+ echo $_z40 > .git/worktrees/wt/logs/refs/bisect/wt-random &&
60
+
61
+ $RWT for-each-reflog | cut -c 42- | sort >actual &&
62
+ cat >expected <<-\EOF &&
63
+ HEAD 0x1
64
+ PSEUDO-WT 0x0
65
+ refs/bisect/wt-random 0x0
66
+ refs/heads/master 0x0
67
+ refs/heads/wt-master 0x0
68
+ EOF
69
+ test_cmp expected actual &&
70
+
71
+ $RMAIN for-each-reflog | cut -c 42- | sort >actual &&
72
+ cat >expected <<-\EOF &&
73
+ HEAD 0x1
74
+ PSEUDO-MAIN 0x0
75
+ refs/bisect/random 0x0
76
+ refs/heads/master 0x0
77
+ refs/heads/wt-master 0x0
78
+ EOF
79
+ test_cmp expected actual
80
+'
81
+
82
test_done