Merge branch 'pc/submodule-helper'
[gitweb.git] / revision.c
index f032ab2e5c5c73c691338cdaf99d5b3b3d16b674..d167223e694e54626786740954454d4973e28752 100644 (file)
@@ -19,6 +19,9 @@
 #include "dir.h"
 #include "cache-tree.h"
 #include "bisect.h"
+#include "packfile.h"
+#include "worktree.h"
+#include "argv-array.h"
 
 volatile show_early_output_fn_t show_early_output;
 
@@ -1103,7 +1106,7 @@ static void add_rev_cmdline(struct rev_info *revs,
                            unsigned flags)
 {
        struct rev_cmdline_info *info = &revs->cmdline;
-       int nr = info->nr;
+       unsigned int nr = info->nr;
 
        ALLOC_GROW(info->rev, nr + 1, info->alloc);
        info->rev[nr].item = item;
@@ -1131,6 +1134,7 @@ struct all_refs_cb {
        int warned_bad_reflog;
        struct rev_info *all_revs;
        const char *name_for_errormsg;
+       struct ref_store *refs;
 };
 
 int ref_excluded(struct string_list *ref_excludes, const char *path)
@@ -1167,6 +1171,7 @@ static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,
        cb->all_revs = revs;
        cb->all_flags = flags;
        revs->rev_input_given = 1;
+       cb->refs = NULL;
 }
 
 void clear_ref_exclusion(struct string_list **ref_excludes_p)
@@ -1187,12 +1192,19 @@ void add_ref_exclusion(struct string_list **ref_excludes_p, const char *exclude)
        string_list_append(*ref_excludes_p, exclude);
 }
 
-static void handle_refs(const char *submodule, struct rev_info *revs, unsigned flags,
-               int (*for_each)(const char *, each_ref_fn, void *))
+static void handle_refs(struct ref_store *refs,
+                       struct rev_info *revs, unsigned flags,
+                       int (*for_each)(struct ref_store *, each_ref_fn, void *))
 {
        struct all_refs_cb cb;
+
+       if (!refs) {
+               /* this could happen with uninitialized submodules */
+               return;
+       }
+
        init_all_refs_cb(&cb, revs, flags);
-       for_each(submodule, handle_one_ref, &cb);
+       for_each(refs, handle_one_ref, &cb);
 }
 
 static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)
@@ -1228,17 +1240,41 @@ static int handle_one_reflog(const char *path, const struct object_id *oid,
        struct all_refs_cb *cb = cb_data;
        cb->warned_bad_reflog = 0;
        cb->name_for_errormsg = path;
-       for_each_reflog_ent(path, handle_one_reflog_ent, cb_data);
+       refs_for_each_reflog_ent(cb->refs, path,
+                                handle_one_reflog_ent, cb_data);
        return 0;
 }
 
+static void add_other_reflogs_to_pending(struct all_refs_cb *cb)
+{
+       struct worktree **worktrees, **p;
+
+       worktrees = get_worktrees(0);
+       for (p = worktrees; *p; p++) {
+               struct worktree *wt = *p;
+
+               if (wt->is_current)
+                       continue;
+
+               cb->refs = get_worktree_ref_store(wt);
+               refs_for_each_reflog(cb->refs,
+                                    handle_one_reflog,
+                                    cb);
+       }
+       free_worktrees(worktrees);
+}
+
 void add_reflogs_to_pending(struct rev_info *revs, unsigned flags)
 {
        struct all_refs_cb cb;
 
        cb.all_revs = revs;
        cb.all_flags = flags;
+       cb.refs = get_main_ref_store();
        for_each_reflog(handle_one_reflog, &cb);
+
+       if (!revs->single_worktree)
+               add_other_reflogs_to_pending(&cb);
 }
 
 static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
@@ -1262,13 +1298,13 @@ static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
 
 }
 
-void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)
+static void do_add_index_objects_to_pending(struct rev_info *revs,
+                                           struct index_state *istate)
 {
        int i;
 
-       read_cache();
-       for (i = 0; i < active_nr; i++) {
-               struct cache_entry *ce = active_cache[i];
+       for (i = 0; i < istate->cache_nr; i++) {
+               struct cache_entry *ce = istate->cache[i];
                struct blob *blob;
 
                if (S_ISGITLINK(ce->ce_mode))
@@ -1281,13 +1317,39 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned flags)
                                             ce->ce_mode, ce->name);
        }
 
-       if (active_cache_tree) {
+       if (istate->cache_tree) {
                struct strbuf path = STRBUF_INIT;
-               add_cache_tree(active_cache_tree, revs, &path);
+               add_cache_tree(istate->cache_tree, revs, &path);
                strbuf_release(&path);
        }
 }
 
+void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
+{
+       struct worktree **worktrees, **p;
+
+       read_cache();
+       do_add_index_objects_to_pending(revs, &the_index);
+
+       if (revs->single_worktree)
+               return;
+
+       worktrees = get_worktrees(0);
+       for (p = worktrees; *p; p++) {
+               struct worktree *wt = *p;
+               struct index_state istate = { NULL };
+
+               if (wt->is_current)
+                       continue; /* current index already taken care of */
+
+               if (read_index_from(&istate,
+                                   worktree_git_path(wt, "index")) > 0)
+                       do_add_index_objects_to_pending(revs, &istate);
+               discard_index(&istate);
+       }
+       free_worktrees(worktrees);
+}
+
 static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
                            int exclude_parent)
 {
@@ -1302,7 +1364,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
                flags ^= UNINTERESTING | BOTTOM;
                arg++;
        }
-       if (get_sha1_committish(arg, oid.hash))
+       if (get_oid_committish(arg, &oid))
                return 0;
        while (1) {
                it = get_reference(revs, arg, &oid, 0);
@@ -1451,7 +1513,7 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
        unsigned int a_flags, b_flags;
        int symmetric = 0;
        unsigned int flags_exclude = flags ^ (UNINTERESTING | BOTTOM);
-       unsigned int oc_flags = GET_SHA1_COMMITTISH | GET_SHA1_RECORD_PATH;
+       unsigned int oc_flags = GET_OID_COMMITTISH | GET_OID_RECORD_PATH;
 
        a_name = arg;
        if (!*a_name)
@@ -1465,8 +1527,8 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
        if (!*b_name)
                b_name = "HEAD";
 
-       if (get_sha1_with_context(a_name, oc_flags, a_oid.hash, a_oc) ||
-           get_sha1_with_context(b_name, oc_flags, b_oid.hash, b_oc))
+       if (get_oid_with_context(a_name, oc_flags, &a_oid, a_oc) ||
+           get_oid_with_context(b_name, oc_flags, &b_oid, b_oc))
                return -1;
 
        if (!cant_be_filename) {
@@ -1547,7 +1609,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
        int local_flags;
        const char *arg = arg_;
        int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
-       unsigned get_sha1_flags = GET_SHA1_RECORD_PATH;
+       unsigned get_sha1_flags = GET_OID_RECORD_PATH;
 
        flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM;
 
@@ -1598,9 +1660,9 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
        }
 
        if (revarg_opt & REVARG_COMMITTISH)
-               get_sha1_flags |= GET_SHA1_COMMITTISH;
+               get_sha1_flags |= GET_OID_COMMITTISH;
 
-       if (get_sha1_with_context(arg, get_sha1_flags, oid.hash, &oc))
+       if (get_oid_with_context(arg, get_sha1_flags, &oid, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
@@ -1611,31 +1673,15 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
        return 0;
 }
 
-struct cmdline_pathspec {
-       int alloc;
-       int nr;
-       const char **path;
-};
-
-static void append_prune_data(struct cmdline_pathspec *prune, const char **av)
-{
-       while (*av) {
-               ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);
-               prune->path[prune->nr++] = *(av++);
-       }
-}
-
 static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,
-                                    struct cmdline_pathspec *prune)
+                                    struct argv_array *prune)
 {
-       while (strbuf_getline(sb, stdin) != EOF) {
-               ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);
-               prune->path[prune->nr++] = xstrdup(sb->buf);
-       }
+       while (strbuf_getline(sb, stdin) != EOF)
+               argv_array_push(prune, sb->buf);
 }
 
 static void read_revisions_from_stdin(struct rev_info *revs,
-                                     struct cmdline_pathspec *prune)
+                                     struct argv_array *prune)
 {
        struct strbuf sb;
        int seen_dashdash = 0;
@@ -2068,23 +2114,25 @@ void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
        ctx->argc -= n;
 }
 
-static int for_each_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data, const char *term) {
+static int for_each_bisect_ref(struct ref_store *refs, each_ref_fn fn,
+                              void *cb_data, const char *term)
+{
        struct strbuf bisect_refs = STRBUF_INIT;
        int status;
        strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
-       status = for_each_fullref_in_submodule(submodule, bisect_refs.buf, fn, cb_data, 0);
+       status = refs_for_each_fullref_in(refs, bisect_refs.buf, fn, cb_data, 0);
        strbuf_release(&bisect_refs);
        return status;
 }
 
-static int for_each_bad_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
+static int for_each_bad_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
 {
-       return for_each_bisect_ref(submodule, fn, cb_data, term_bad);
+       return for_each_bisect_ref(refs, fn, cb_data, term_bad);
 }
 
-static int for_each_good_bisect_ref(const char *submodule, each_ref_fn fn, void *cb_data)
+static int for_each_good_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
 {
-       return for_each_bisect_ref(submodule, fn, cb_data, term_good);
+       return for_each_bisect_ref(refs, fn, cb_data, term_good);
 }
 
 static int handle_revision_pseudo_opt(const char *submodule,
@@ -2093,8 +2141,22 @@ static int handle_revision_pseudo_opt(const char *submodule,
 {
        const char *arg = argv[0];
        const char *optarg;
+       struct ref_store *refs;
        int argcount;
 
+       if (submodule) {
+               /*
+                * We need some something like get_submodule_worktrees()
+                * before we can go through all worktrees of a submodule,
+                * .e.g with adding all HEADs from --all, which is not
+                * supported right now, so stick to single worktree.
+                */
+               if (!revs->single_worktree)
+                       die("BUG: --single-worktree cannot be used together with submodule");
+               refs = get_submodule_ref_store(submodule);
+       } else
+               refs = get_main_ref_store();
+
        /*
         * NOTE!
         *
@@ -2106,22 +2168,29 @@ static int handle_revision_pseudo_opt(const char *submodule,
         * register it in the list at the top of handle_revision_opt.
         */
        if (!strcmp(arg, "--all")) {
-               handle_refs(submodule, revs, *flags, for_each_ref_submodule);
-               handle_refs(submodule, revs, *flags, head_ref_submodule);
+               handle_refs(refs, revs, *flags, refs_for_each_ref);
+               handle_refs(refs, revs, *flags, refs_head_ref);
+               if (!revs->single_worktree) {
+                       struct all_refs_cb cb;
+
+                       init_all_refs_cb(&cb, revs, *flags);
+                       other_head_refs(handle_one_ref, &cb);
+               }
                clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--branches")) {
-               handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule);
+               handle_refs(refs, revs, *flags, refs_for_each_branch_ref);
                clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--bisect")) {
                read_bisect_terms(&term_bad, &term_good);
-               handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref);
-               handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref);
+               handle_refs(refs, revs, *flags, for_each_bad_bisect_ref);
+               handle_refs(refs, revs, *flags ^ (UNINTERESTING | BOTTOM),
+                           for_each_good_bisect_ref);
                revs->bisect = 1;
        } else if (!strcmp(arg, "--tags")) {
-               handle_refs(submodule, revs, *flags, for_each_tag_ref_submodule);
+               handle_refs(refs, revs, *flags, refs_for_each_tag_ref);
                clear_ref_exclusion(&revs->ref_excludes);
        } else if (!strcmp(arg, "--remotes")) {
-               handle_refs(submodule, revs, *flags, for_each_remote_ref_submodule);
+               handle_refs(refs, revs, *flags, refs_for_each_remote_ref);
                clear_ref_exclusion(&revs->ref_excludes);
        } else if ((argcount = parse_long_opt("glob", argv, &optarg))) {
                struct all_refs_cb cb;
@@ -2168,6 +2237,8 @@ static int handle_revision_pseudo_opt(const char *submodule,
                        return error("invalid argument to --no-walk");
        } else if (!strcmp(arg, "--do-walk")) {
                revs->no_walk = 0;
+       } else if (!strcmp(arg, "--single-worktree")) {
+               revs->single_worktree = 1;
        } else {
                return 0;
        }
@@ -2177,11 +2248,10 @@ static int handle_revision_pseudo_opt(const char *submodule,
 
 static void NORETURN diagnose_missing_default(const char *def)
 {
-       unsigned char sha1[20];
        int flags;
        const char *refname;
 
-       refname = resolve_ref_unsafe(def, 0, sha1, &flags);
+       refname = resolve_ref_unsafe(def, 0, NULL, &flags);
        if (!refname || !(flags & REF_ISSYMREF) || (flags & REF_ISBROKEN))
                die(_("your current branch appears to be broken"));
 
@@ -2200,10 +2270,9 @@ static void NORETURN diagnose_missing_default(const char *def)
 int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
 {
        int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt;
-       struct cmdline_pathspec prune_data;
+       struct argv_array prune_data = ARGV_ARRAY_INIT;
        const char *submodule = NULL;
 
-       memset(&prune_data, 0, sizeof(prune_data));
        if (opt)
                submodule = opt->submodule;
 
@@ -2219,7 +2288,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                        argv[i] = NULL;
                        argc = i;
                        if (argv[i + 1])
-                               append_prune_data(&prune_data, argv + i + 1);
+                               argv_array_pushv(&prune_data, argv + i + 1);
                        seen_dashdash = 1;
                        break;
                }
@@ -2280,14 +2349,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                        for (j = i; j < argc; j++)
                                verify_filename(revs->prefix, argv[j], j == i);
 
-                       append_prune_data(&prune_data, argv + i);
+                       argv_array_pushv(&prune_data, argv + i);
                        break;
                }
                else
                        got_rev_arg = 1;
        }
 
-       if (prune_data.nr) {
+       if (prune_data.argc) {
                /*
                 * If we need to introduce the magic "a lone ':' means no
                 * pathspec whatsoever", here is the place to do so.
@@ -2302,11 +2371,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                 *      call init_pathspec() to set revs->prune_data here.
                 * }
                 */
-               ALLOC_GROW(prune_data.path, prune_data.nr + 1, prune_data.alloc);
-               prune_data.path[prune_data.nr++] = NULL;
                parse_pathspec(&revs->prune_data, 0, 0,
-                              revs->prefix, prune_data.path);
+                              revs->prefix, prune_data.argv);
        }
+       argv_array_clear(&prune_data);
 
        if (revs->def == NULL)
                revs->def = opt ? opt->def : NULL;
@@ -2318,7 +2386,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                struct object_id oid;
                struct object *object;
                struct object_context oc;
-               if (get_sha1_with_context(revs->def, 0, oid.hash, &oc))
+               if (get_oid_with_context(revs->def, 0, &oid, &oc))
                        diagnose_missing_default(revs->def);
                object = get_reference(revs, revs->def, &oid, 0);
                add_pending_object_with_mode(revs, object, revs->def, oc.mode);