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