On 04/19/2017 01:01 PM, Nguyễn Thái Ngọc Duy wrote:
> 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.
> 
> Ideally we should have something like merge_ref_iterator_begin (and
> maybe with a predicate), but for dir_iterator. Since there's only one
> use case for this pattern, let's not add a bunch more code for
> merge_dir_iterator_begin just yet.
> 
> 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 <pclo...@gmail.com>
> ---
>  refs/files-backend.c          | 46 
> ++++++++++++++++++++++++++++++++-----------
>  t/t1407-worktree-ref-store.sh | 30 ++++++++++++++++++++++++++++
>  2 files changed, 65 insertions(+), 11 deletions(-)
> 
> diff --git a/refs/files-backend.c b/refs/files-backend.c
> index 4149943a6e..fce380679c 100644
> --- a/refs/files-backend.c
> +++ b/refs/files-backend.c
> @@ -1171,15 +1171,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:
> @@ -3368,6 +3359,7 @@ struct files_reflog_iterator {
>  
>       struct ref_store *ref_store;
>       struct dir_iterator *dir_iterator;
> +     struct dir_iterator *worktree_dir_iterator;
>       struct object_id oid;
>  };
>  
> @@ -3388,6 +3380,21 @@ static int files_reflog_iterator_advance(struct 
> ref_iterator *ref_iterator)
>               if (ends_with(diter->basename, ".lock"))
>                       continue;
>  
> +             if (iter->worktree_dir_iterator) {
> +                     const char *refname = diter->relative_path;
> +
> +                     switch (ref_type(refname)) {
> +                     case REF_TYPE_PER_WORKTREE:
> +                     case REF_TYPE_PSEUDOREF:
> +                             continue;
> +                     case REF_TYPE_NORMAL:
> +                             break;
> +                     default:
> +                             die("BUG: unknown ref type %d of ref %s",
> +                                 ref_type(refname), refname);
> +                     }
> +             }
> +
>               if (refs_read_ref_full(iter->ref_store,
>                                      diter->relative_path, 0,
>                                      iter->oid.hash, &flags)) {
> @@ -3401,7 +3408,11 @@ static int files_reflog_iterator_advance(struct 
> ref_iterator *ref_iterator)
>               return ITER_OK;
>       }
>  
> -     iter->dir_iterator = NULL;
> +     iter->dir_iterator = iter->worktree_dir_iterator;
> +     if (iter->worktree_dir_iterator) {
> +             iter->worktree_dir_iterator = NULL;
> +             return files_reflog_iterator_advance(ref_iterator);
> +     }

I find this implementation confusing:

* `if (iter->worktree_dir_iterator)` sounds like it should mean
  that we are iterating over worktree references but it really means
  that we are iterating over the common references in a repository
  that is a linked worktree.
* `files_reflog_iterator_advance()` is called recursively, but only
  for the first worktree reference.
* `iter->worktree_dir_iterator` is moved over to `iter->dir_iterator`
  when the common refs are exhausted.

Do you find it more readable as follows?:

static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
{
        struct files_reflog_iterator *iter =
                (struct files_reflog_iterator *)ref_iterator;
        int ok;

        while (1) {
                struct dir_iterator **diter;
                int normal_only, flags;

                if (iter->dir_iterator) {
                        diter = &iter->dir_iterator;
                        /*
                         * If we are in a worktree, then we only
                         * include "normal" common references:
                         */
                        normal_only = !!iter->worktree_dir_iterator;
                } else if (iter->worktree_dir_iterator) {
                        diter = &iter->worktree_dir_iterator;
                        normal_only = 0;
                } else {
                        ok = ITER_DONE;
                        break;
                }

                ok = dir_iterator_advance(*diter);
                if (ok == ITER_ERROR) {
                        *diter = NULL;
                        break;
                } else if (ok == ITER_DONE) {
                        *diter = NULL;
                        /* There might still be worktree refs left: */
                        continue;
                }

                if (!S_ISREG((*diter)->st.st_mode))
                        continue;
                if ((*diter)->basename[0] == '.')
                        continue;
                if (ends_with((*diter)->basename, ".lock"))
                        continue;

                iter->base.refname = (*diter)->relative_path;

                if (normal_only &&
                    ref_type(iter->base.refname) != REF_TYPE_NORMAL)
                        continue;

                if (refs_read_ref_full(iter->ref_store,
                                       iter->base.refname, 0,
                                       iter->oid.hash, &flags)) {
                        error("bad ref for %s", (*diter)->path.buf);
                        continue;
                }

                iter->base.oid = &iter->oid;
                iter->base.flags = flags;
                return ITER_OK;
        }

        if (ref_iterator_abort(ref_iterator) == ITER_ERROR)
                return ITER_ERROR;

        return ok;
}

>       if (ref_iterator_abort(ref_iterator) == ITER_ERROR)
>               ok = ITER_ERROR;
>       return ok;
> [...]

Michael

Reply via email to