die("unable to parse commit %s", name);
if (flags & UNINTERESTING) {
mark_parents_uninteresting(commit);
- revs->limited = 1;
+
+ if (!revs->topo_order || !generation_numbers_enabled(the_repository))
+ revs->limited = 1;
}
if (revs->sources) {
char **slot = revision_sources_at(revs->sources, commit);
commit->object.flags |= TREESAME;
}
-static void commit_list_insert_by_date_cached(struct commit *p, struct commit_list **head,
- struct commit_list *cached_base, struct commit_list **cache)
-{
- struct commit_list *new_entry;
-
- if (cached_base && p->date < cached_base->item->date)
- new_entry = commit_list_insert_by_date(p, &cached_base->next);
- else
- new_entry = commit_list_insert_by_date(p, head);
-
- if (cache && (!*cache || p->date < (*cache)->item->date))
- *cache = new_entry;
-}
-
static int process_parents(struct rev_info *revs, struct commit *commit,
- struct commit_list **list, struct commit_list **cache_ptr)
+ struct commit_list **list, struct prio_queue *queue)
{
struct commit_list *parent = commit->parents;
unsigned left_flag;
- struct commit_list *cached_base = cache_ptr ? *cache_ptr : NULL;
if (commit->object.flags & ADDED)
return 0;
continue;
p->object.flags |= SEEN;
if (list)
- commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr);
+ commit_list_insert_by_date(p, list);
+ if (queue)
+ prio_queue_put(queue, p);
}
return 0;
}
if (!(p->object.flags & SEEN)) {
p->object.flags |= SEEN;
if (list)
- commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr);
+ commit_list_insert_by_date(p, list);
+ if (queue)
+ prio_queue_put(queue, p);
}
if (revs->first_parent_only)
break;
free_worktrees(worktrees);
}
+struct add_alternate_refs_data {
+ struct rev_info *revs;
+ unsigned int flags;
+};
+
+static void add_one_alternate_ref(const struct object_id *oid,
+ void *vdata)
+{
+ const char *name = ".alternate";
+ struct add_alternate_refs_data *data = vdata;
+ struct object *obj;
+
+ obj = get_reference(data->revs, name, oid, data->flags);
+ add_rev_cmdline(data->revs, obj, name, REV_CMD_REV, data->flags);
+ add_pending_object(data->revs, obj, name);
+}
+
+static void add_alternate_refs_to_pending(struct rev_info *revs,
+ unsigned int flags)
+{
+ struct add_alternate_refs_data data;
+ data.revs = revs;
+ data.flags = flags;
+ for_each_alternate_ref(add_one_alternate_ref, &data);
+}
+
static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
int exclude_parent)
{
return 0;
}
-static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,
+static void read_pathspec_from_stdin(struct strbuf *sb,
struct argv_array *prune)
{
while (strbuf_getline(sb, stdin) != EOF)
die("bad revision '%s'", sb.buf);
}
if (seen_dashdash)
- read_pathspec_from_stdin(revs, &sb, prune);
+ read_pathspec_from_stdin(&sb, prune);
strbuf_release(&sb);
warn_on_object_refname_ambiguity = save_warning;
!strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
!strcmp(arg, "--bisect") || starts_with(arg, "--glob=") ||
!strcmp(arg, "--indexed-objects") ||
+ !strcmp(arg, "--alternate-refs") ||
starts_with(arg, "--exclude=") ||
starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
add_reflogs_to_pending(revs, *flags);
} else if (!strcmp(arg, "--indexed-objects")) {
add_index_objects_to_pending(revs, *flags);
+ } else if (!strcmp(arg, "--alternate-refs")) {
+ add_alternate_refs_to_pending(revs, *flags);
} else if (!strcmp(arg, "--not")) {
*flags ^= UNINTERESTING | BOTTOM;
} else if (!strcmp(arg, "--no-walk")) {
int i, flags, left, seen_dashdash, got_rev_arg = 0, revarg_opt;
struct argv_array prune_data = ARGV_ARRAY_INIT;
const char *submodule = NULL;
+ int seen_end_of_options = 0;
if (opt)
submodule = opt->submodule;
revarg_opt |= REVARG_CANNOT_BE_FILENAME;
for (left = i = 1; i < argc; i++) {
const char *arg = argv[i];
- if (*arg == '-') {
+ if (!seen_end_of_options && *arg == '-') {
int opts;
opts = handle_revision_pseudo_opt(submodule,
continue;
}
+ if (!strcmp(arg, "--end-of-options")) {
+ seen_end_of_options = 1;
+ continue;
+ }
+
opts = handle_revision_opt(revs, argc - i, argv + i,
&left, argv, opt);
if (opts > 0) {
if (revs->first_parent_only && revs->bisect)
die(_("--first-parent is incompatible with --bisect"));
+ if (revs->line_level_traverse &&
+ (revs->diffopt.output_format & ~(DIFF_FORMAT_PATCH | DIFF_FORMAT_NO_OUTPUT)))
+ die(_("-L does not yet support diff formats besides -p and -s"));
+
if (revs->expand_tabs_in_log < 0)
revs->expand_tabs_in_log = revs->expand_tabs_in_log_default;
return st;
}
-static int mark_redundant_parents(struct rev_info *revs, struct commit *commit)
+static int mark_redundant_parents(struct commit *commit)
{
struct commit_list *h = reduce_heads(commit->parents);
int i = 0, marked = 0;
return marked;
}
-static int mark_treesame_root_parents(struct rev_info *revs, struct commit *commit)
+static int mark_treesame_root_parents(struct commit *commit)
{
struct commit_list *p;
int marked = 0;
* Detect and simplify both cases.
*/
if (1 < cnt) {
- int marked = mark_redundant_parents(revs, commit);
- marked += mark_treesame_root_parents(revs, commit);
+ int marked = mark_redundant_parents(commit);
+ marked += mark_treesame_root_parents(commit);
if (marked)
marked -= leave_one_treesame_to_parent(revs, commit);
if (marked)
struct commit *parent = p->item;
int *pi;
+ if (parent->object.flags & UNINTERESTING)
+ continue;
+
if (parse_commit_gently(parent, 1) < 0)
continue;
return 0;
}
-static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp)
+static enum rewrite_result rewrite_one_1(struct rev_info *revs,
+ struct commit **pp,
+ struct prio_queue *queue)
{
- struct commit_list *cache = NULL;
-
for (;;) {
struct commit *p = *pp;
if (!revs->limited)
- if (process_parents(revs, p, &revs->commits, &cache) < 0)
+ if (process_parents(revs, p, NULL, queue) < 0)
return rewrite_one_error;
if (p->object.flags & UNINTERESTING)
return rewrite_one_ok;
}
}
+static void merge_queue_into_list(struct prio_queue *q, struct commit_list **list)
+{
+ while (q->nr) {
+ struct commit *item = prio_queue_peek(q);
+ struct commit_list *p = *list;
+
+ if (p && p->item->date >= item->date)
+ list = &p->next;
+ else {
+ p = commit_list_insert(item, list);
+ list = &p->next; /* skip newly added item */
+ prio_queue_get(q); /* pop item */
+ }
+ }
+}
+
+static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp)
+{
+ struct prio_queue queue = { compare_commits_by_commit_date };
+ enum rewrite_result ret = rewrite_one_1(revs, pp, &queue);
+ merge_queue_into_list(&queue, &revs->commits);
+ clear_prio_queue(&queue);
+ return ret;
+}
+
int rewrite_parents(struct rev_info *revs, struct commit *commit,
rewrite_parent_fn_t rewrite_parent)
{