diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2017-08-23 19:37:00 +0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2017-08-24 14:57:56 -0700 |
commit | 944b4e3013d6e21b1ecd2f2579395341f2cc8b7b (patch) | |
tree | 85c0edfc4b223a251324b7ece3023cd25152f378 /refs | |
parent | revision.c: --all adds HEAD from all worktrees (diff) | |
download | tgif-944b4e3013d6e21b1ecd2f2579395341f2cc8b7b.tar.xz |
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>
Diffstat (limited to 'refs')
-rw-r--r-- | refs/files-backend.c | 59 |
1 files changed, 45 insertions, 14 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c index 5cca55510b..d4d22882ef 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -106,15 +106,6 @@ static void files_reflog_path(struct files_ref_store *refs, struct strbuf *sb, const char *refname) { - if (!refname) { - /* - * FIXME: of course this is wrong in multi worktree - * setting. To be fixed real soon. - */ - strbuf_addf(sb, "%s/logs", refs->gitcommondir); - return; - } - switch (ref_type(refname)) { case REF_TYPE_PER_WORKTREE: case REF_TYPE_PSEUDOREF: @@ -2055,23 +2046,63 @@ static struct ref_iterator_vtable files_reflog_iterator_vtable = { files_reflog_iterator_abort }; -static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store) +static struct ref_iterator *reflog_iterator_begin(struct ref_store *ref_store, + const char *gitdir) { - struct files_ref_store *refs = - files_downcast(ref_store, REF_STORE_READ, - "reflog_iterator_begin"); struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter)); struct ref_iterator *ref_iterator = &iter->base; struct strbuf sb = STRBUF_INIT; base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable); - files_reflog_path(refs, &sb, NULL); + strbuf_addf(&sb, "%s/logs", gitdir); iter->dir_iterator = dir_iterator_begin(sb.buf); iter->ref_store = ref_store; strbuf_release(&sb); + return ref_iterator; } +static enum iterator_selection reflog_iterator_select( + struct ref_iterator *iter_worktree, + struct ref_iterator *iter_common, + void *cb_data) +{ + if (iter_worktree) { + /* + * We're a bit loose here. We probably should ignore + * common refs if they are accidentally added as + * per-worktree refs. + */ + return ITER_SELECT_0; + } else if (iter_common) { + if (ref_type(iter_common->refname) == REF_TYPE_NORMAL) + return ITER_SELECT_1; + + /* + * The main ref store may contain main worktree's + * per-worktree refs, which should be ignored + */ + return ITER_SKIP_1; + } else + return ITER_DONE; +} + +static struct ref_iterator *files_reflog_iterator_begin(struct ref_store *ref_store) +{ + struct files_ref_store *refs = + files_downcast(ref_store, REF_STORE_READ, + "reflog_iterator_begin"); + + if (!strcmp(refs->gitdir, refs->gitcommondir)) { + return reflog_iterator_begin(ref_store, refs->gitcommondir); + } else { + return merge_ref_iterator_begin( + reflog_iterator_begin(ref_store, refs->gitdir), + reflog_iterator_begin(ref_store, refs->gitcommondir), + reflog_iterator_select, refs); + } +} + /* * If update is a direct update of head_ref (the reference pointed to * by HEAD), then add an extra REF_LOG_ONLY update for HEAD. |