#include "cache.h"
+#include "object-store.h"
#include "tag.h"
#include "blob.h"
#include "tree.h"
#include "diff.h"
#include "refs.h"
#include "revision.h"
+#include "repository.h"
#include "graph.h"
#include "grep.h"
#include "reflog-walk.h"
#include "packfile.h"
#include "worktree.h"
#include "argv-array.h"
+#include "commit-reach.h"
volatile show_early_output_fn_t show_early_output;
static const char *term_bad;
static const char *term_good;
+implement_shared_commit_slab(revision_sources, char *);
+
void show_object_with_name(FILE *out, struct object *obj, const char *name)
{
const char *p;
blob->object.flags |= UNINTERESTING;
}
-static void mark_tree_contents_uninteresting(struct tree *tree)
+static void mark_tree_contents_uninteresting(struct repository *r,
+ struct tree *tree)
{
struct tree_desc desc;
struct name_entry entry;
- struct object *obj = &tree->object;
- if (!has_object_file(&obj->oid))
+ if (parse_tree_gently(tree, 1) < 0)
return;
- if (parse_tree(tree) < 0)
- die("bad tree %s", oid_to_hex(&obj->oid));
init_tree_desc(&desc, tree->buffer, tree->size);
while (tree_entry(&desc, &entry)) {
switch (object_type(entry.mode)) {
case OBJ_TREE:
- mark_tree_uninteresting(lookup_tree(entry.oid));
+ mark_tree_uninteresting(r, lookup_tree(r, entry.oid));
break;
case OBJ_BLOB:
- mark_blob_uninteresting(lookup_blob(entry.oid));
+ mark_blob_uninteresting(lookup_blob(r, entry.oid));
break;
default:
/* Subproject commit - not in this repository */
free_tree_buffer(tree);
}
-void mark_tree_uninteresting(struct tree *tree)
+void mark_tree_uninteresting(struct repository *r, struct tree *tree)
{
struct object *obj;
if (obj->flags & UNINTERESTING)
return;
obj->flags |= UNINTERESTING;
- mark_tree_contents_uninteresting(tree);
+ mark_tree_contents_uninteresting(r, tree);
}
-void mark_parents_uninteresting(struct commit *commit)
+struct commit_stack {
+ struct commit **items;
+ size_t nr, alloc;
+};
+#define COMMIT_STACK_INIT { NULL, 0, 0 }
+
+static void commit_stack_push(struct commit_stack *stack, struct commit *commit)
{
- struct commit_list *parents = NULL, *l;
+ ALLOC_GROW(stack->items, stack->nr + 1, stack->alloc);
+ stack->items[stack->nr++] = commit;
+}
- for (l = commit->parents; l; l = l->next)
- commit_list_insert(l->item, &parents);
+static struct commit *commit_stack_pop(struct commit_stack *stack)
+{
+ return stack->nr ? stack->items[--stack->nr] : NULL;
+}
- while (parents) {
- struct commit *commit = pop_commit(&parents);
+static void commit_stack_clear(struct commit_stack *stack)
+{
+ FREE_AND_NULL(stack->items);
+ stack->nr = stack->alloc = 0;
+}
- while (commit) {
- /*
- * A missing commit is ok iff its parent is marked
- * uninteresting.
- *
- * We just mark such a thing parsed, so that when
- * it is popped next time around, we won't be trying
- * to parse it and get an error.
- */
- if (!commit->object.parsed &&
- !has_object_file(&commit->object.oid))
- commit->object.parsed = 1;
+static void mark_one_parent_uninteresting(struct commit *commit,
+ struct commit_stack *pending)
+{
+ struct commit_list *l;
- if (commit->object.flags & UNINTERESTING)
- break;
+ if (commit->object.flags & UNINTERESTING)
+ return;
+ commit->object.flags |= UNINTERESTING;
- commit->object.flags |= UNINTERESTING;
+ /*
+ * Normally we haven't parsed the parent
+ * yet, so we won't have a parent of a parent
+ * here. However, it may turn out that we've
+ * reached this commit some other way (where it
+ * wasn't uninteresting), in which case we need
+ * to mark its parents recursively too..
+ */
+ for (l = commit->parents; l; l = l->next)
+ commit_stack_push(pending, l->item);
+}
- /*
- * Normally we haven't parsed the parent
- * yet, so we won't have a parent of a parent
- * here. However, it may turn out that we've
- * reached this commit some other way (where it
- * wasn't uninteresting), in which case we need
- * to mark its parents recursively too..
- */
- if (!commit->parents)
- break;
+void mark_parents_uninteresting(struct commit *commit)
+{
+ struct commit_stack pending = COMMIT_STACK_INIT;
+ struct commit_list *l;
- for (l = commit->parents->next; l; l = l->next)
- commit_list_insert(l->item, &parents);
- commit = commit->parents->item;
- }
- }
+ for (l = commit->parents; l; l = l->next)
+ mark_one_parent_uninteresting(l->item, &pending);
+
+ while (pending.nr > 0)
+ mark_one_parent_uninteresting(commit_stack_pop(&pending),
+ &pending);
+
+ commit_stack_clear(&pending);
}
static void add_pending_object_with_path(struct rev_info *revs,
struct object *obj;
if (get_oid("HEAD", &oid))
return;
- obj = parse_object(&oid);
+ obj = parse_object(revs->repo, &oid);
if (!obj)
return;
add_pending_object(revs, obj, "HEAD");
{
struct object *object;
- object = parse_object(oid);
+ object = parse_object(revs->repo, oid);
if (!object) {
if (revs->ignore_missing)
return object;
add_pending_object(revs, object, tag->tag);
if (!tag->tagged)
die("bad tag");
- object = parse_object(&tag->tagged->oid);
+ object = parse_object(revs->repo, &tag->tagged->oid);
if (!object) {
if (revs->ignore_missing_links || (flags & UNINTERESTING))
return NULL;
+ if (revs->exclude_promisor_objects &&
+ is_promisor_object(&tag->tagged->oid))
+ return NULL;
die("bad object %s", oid_to_hex(&tag->tagged->oid));
}
object->flags |= flags;
*/
if (object->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *)object;
+
if (parse_commit(commit) < 0)
die("unable to parse commit %s", name);
if (flags & UNINTERESTING) {
mark_parents_uninteresting(commit);
revs->limited = 1;
}
- if (revs->show_source && !commit->util)
- commit->util = xstrdup(name);
+ if (revs->sources) {
+ char **slot = revision_sources_at(revs->sources, commit);
+
+ if (!*slot)
+ *slot = xstrdup(name);
+ }
return commit;
}
if (!revs->tree_objects)
return NULL;
if (flags & UNINTERESTING) {
- mark_tree_contents_uninteresting(tree);
+ mark_tree_contents_uninteresting(revs->repo, tree);
return NULL;
}
add_pending_object_with_path(revs, object, name, mode, path);
static int rev_compare_tree(struct rev_info *revs,
struct commit *parent, struct commit *commit)
{
- struct tree *t1 = parent->tree;
- struct tree *t2 = commit->tree;
+ struct tree *t1 = get_commit_tree(parent);
+ struct tree *t2 = get_commit_tree(commit);
if (!t1)
return REV_TREE_NEW;
static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
{
int retval;
- struct tree *t1 = commit->tree;
+ struct tree *t1 = get_commit_tree(commit);
if (!t1)
return 0;
if (!revs->prune)
return;
- if (!commit->tree)
+ if (!get_commit_tree(commit))
return;
if (!commit->parents) {
}
return -1;
}
- if (revs->show_source && !p->util)
- p->util = commit->util;
+ if (revs->sources) {
+ char **slot = revision_sources_at(revs->sources, p);
+
+ if (!*slot)
+ *slot = *revision_sources_at(revs->sources, commit);
+ }
p->object.flags |= left_flag;
if (!(p->object.flags & SEEN)) {
p->object.flags |= SEEN;
return;
left_first = left_count < right_count;
- init_patch_ids(&ids);
+ init_patch_ids(revs->repo, &ids);
ids.diffopts.pathspec = revs->diffopt.pathspec;
/* Compute patch-ids for one side */
{
struct all_refs_cb *cb = cb_data;
if (!is_null_oid(oid)) {
- struct object *o = parse_object(oid);
+ struct object *o = parse_object(cb->all_revs->repo, oid);
if (o) {
o->flags |= cb->all_flags;
/* ??? CMDLINEFLAGS ??? */
cb.all_revs = revs;
cb.all_flags = flags;
- cb.refs = get_main_ref_store();
+ cb.refs = get_main_ref_store(revs->repo);
for_each_reflog(handle_one_reflog, &cb);
if (!revs->single_worktree)
int i;
if (it->entry_count >= 0) {
- struct tree *tree = lookup_tree(&it->oid);
+ struct tree *tree = lookup_tree(revs->repo, &it->oid);
add_pending_object_with_path(revs, &tree->object, "",
040000, path->buf);
}
if (S_ISGITLINK(ce->ce_mode))
continue;
- blob = lookup_blob(&ce->oid);
+ blob = lookup_blob(revs->repo, &ce->oid);
if (!blob)
die("unable to add index blob to traversal");
add_pending_object_with_path(revs, &blob->object, "",
{
struct worktree **worktrees, **p;
- read_cache();
- do_add_index_objects_to_pending(revs, &the_index);
+ read_index(revs->repo->index);
+ do_add_index_objects_to_pending(revs, revs->repo->index);
if (revs->single_worktree)
return;
return 1;
}
-void init_revisions(struct rev_info *revs, const char *prefix)
+void repo_init_revisions(struct repository *r,
+ struct rev_info *revs,
+ const char *prefix)
{
memset(revs, 0, sizeof(*revs));
+ revs->repo = r;
revs->abbrev = DEFAULT_ABBREV;
revs->ignore_merges = 1;
revs->simplify_history = 1;
revs->commit_format = CMIT_FMT_DEFAULT;
revs->expand_tabs_in_log_default = 8;
- init_grep_defaults();
- grep_init(&revs->grep_filter, prefix);
+ init_grep_defaults(revs->repo);
+ grep_init(&revs->grep_filter, revs->repo, prefix);
revs->grep_filter.status_only = 1;
- diff_setup(&revs->diffopt);
+ repo_diff_setup(revs->repo, &revs->diffopt);
if (prefix && !revs->diffopt.prefix) {
revs->diffopt.prefix = prefix;
revs->diffopt.prefix_length = strlen(prefix);
struct object_id oid;
const char **prune = NULL;
int i, prune_num = 1; /* counting terminating NULL */
+ struct index_state *istate = revs->repo->index;
if (get_oid("HEAD", &oid))
die("--merge without HEAD?");
free_commit_list(bases);
head->object.flags |= SYMMETRIC_LEFT;
- if (!active_nr)
- read_cache();
- for (i = 0; i < active_nr; i++) {
- const struct cache_entry *ce = active_cache[i];
+ if (!istate->cache_nr)
+ read_index(istate);
+ for (i = 0; i < istate->cache_nr; i++) {
+ const struct cache_entry *ce = istate->cache[i];
if (!ce_stage(ce))
continue;
- if (ce_path_match(ce, &revs->prune_data, NULL)) {
+ if (ce_path_match(istate, ce, &revs->prune_data, NULL)) {
prune_num++;
REALLOC_ARRAY(prune, prune_num);
prune[prune_num-2] = ce->name;
prune[prune_num-1] = NULL;
}
- while ((i+1 < active_nr) &&
- ce_same_name(ce, active_cache[i+1]))
+ while ((i+1 < istate->cache_nr) &&
+ ce_same_name(ce, istate->cache[i+1]))
i++;
}
clear_pathspec(&revs->prune_data);
*dotdot = '\0';
}
- a_obj = parse_object(&a_oid);
- b_obj = parse_object(&b_oid);
+ a_obj = parse_object(revs->repo, &a_oid);
+ b_obj = parse_object(revs->repo, &b_oid);
if (!a_obj || !b_obj)
return dotdot_missing(arg, dotdot, revs, symmetric);
struct commit *a, *b;
struct commit_list *exclude;
- a = lookup_commit_reference(&a_obj->oid);
- b = lookup_commit_reference(&b_obj->oid);
+ a = lookup_commit_reference(revs->repo, &a_obj->oid);
+ b = lookup_commit_reference(revs->repo, &b_obj->oid);
if (!a || !b)
return dotdot_missing(arg, dotdot, revs, symmetric);
const char *arg = argv[0];
const char *optarg;
int argcount;
+ const unsigned hexsz = the_hash_algo->hexsz;
/* pseudo revision arguments */
if (!strcmp(arg, "--all") || !strcmp(arg, "--branches") ||
revs->abbrev = strtoul(optarg, NULL, 10);
if (revs->abbrev < MINIMUM_ABBREV)
revs->abbrev = MINIMUM_ABBREV;
- else if (revs->abbrev > 40)
- revs->abbrev = 40;
+ else if (revs->abbrev > hexsz)
+ revs->abbrev = hexsz;
} else if (!strcmp(arg, "--abbrev-commit")) {
revs->abbrev_commit = 1;
revs->abbrev_commit_given = 1;
revs->ignore_missing = 1;
} else if (!strcmp(arg, "--exclude-promisor-objects")) {
if (fetch_if_missing)
- die("BUG: exclude_promisor_objects can only be used when fetch_if_missing is 0");
+ BUG("exclude_promisor_objects can only be used when fetch_if_missing is 0");
revs->exclude_promisor_objects = 1;
} else {
int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix);
* supported right now, so stick to single worktree.
*/
if (!revs->single_worktree)
- die("BUG: --single-worktree cannot be used together with submodule");
+ BUG("--single-worktree cannot be used together with submodule");
refs = get_submodule_ref_store(submodule);
} else
- refs = get_main_ref_store();
+ refs = get_main_ref_store(revs->repo);
/*
* NOTE!
*/
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;
+ int i, flags, left, seen_dashdash, got_rev_arg = 0, revarg_opt;
struct argv_array prune_data = ARGV_ARRAY_INIT;
const char *submodule = NULL;
revarg_opt = opt ? opt->revarg_opt : 0;
if (seen_dashdash)
revarg_opt |= REVARG_CANNOT_BE_FILENAME;
- read_from_stdin = 0;
for (left = i = 1; i < argc; i++) {
const char *arg = argv[i];
if (*arg == '-') {
argv[left++] = arg;
continue;
}
- if (read_from_stdin++)
+ if (revs->read_from_stdin++)
die("--stdin given twice?");
read_revisions_from_stdin(revs, &prune_data);
continue;
static int mark_uninteresting(const struct object_id *oid,
struct packed_git *pack,
uint32_t pos,
- void *unused)
+ void *cb)
{
- struct object *o = parse_object(oid);
+ struct rev_info *revs = cb;
+ struct object *o = parse_object(revs->repo, oid);
o->flags |= UNINTERESTING | SEEN;
return 0;
}
revs->treesame.name = "treesame";
if (revs->exclude_promisor_objects) {
- for_each_packed_object(mark_uninteresting, NULL,
+ for_each_packed_object(mark_uninteresting, revs,
FOR_EACH_OBJECT_PROMISOR_ONLY);
}
{
if (commit->object.flags & SHOWN)
return commit_ignore;
- if (revs->unpacked && has_sha1_pack(commit->object.oid.hash))
+ if (revs->unpacked && has_object_pack(&commit->object.oid))
return commit_ignore;
if (commit->object.flags & UNINTERESTING)
return commit_ignore;
struct commit_list *p;
for (p = revs->previous_parents; p; p = p->next)
if (p->item == NULL || /* first commit */
- !oidcmp(&p->item->object.oid, &commit->object.oid))
+ oideq(&p->item->object.oid, &commit->object.oid))
break;
revs->linear = p != NULL;
}