diff options
Diffstat (limited to 'revision.c')
-rw-r--r-- | revision.c | 227 |
1 files changed, 190 insertions, 37 deletions
diff --git a/revision.c b/revision.c index d41e59b9cc..2294b16ea2 100644 --- a/revision.c +++ b/revision.c @@ -116,21 +116,27 @@ static void add_pending_object(struct rev_info *revs, struct object *obj, const add_object(obj, &revs->pending_objects, NULL, name); } -static struct commit *get_commit_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags) +static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags) { struct object *object; object = parse_object(sha1); if (!object) die("bad object %s", name); + object->flags |= flags; + return object; +} + +static struct commit *handle_commit(struct rev_info *revs, struct object *object, const char *name) +{ + unsigned long flags = object->flags; /* * Tag object? Look what it points to.. */ while (object->type == tag_type) { struct tag *tag = (struct tag *) object; - object->flags |= flags; - if (revs->tag_objects && !(object->flags & UNINTERESTING)) + if (revs->tag_objects && !(flags & UNINTERESTING)) add_pending_object(revs, object, tag->tag); object = parse_object(tag->tagged->sha1); if (!object) @@ -143,10 +149,10 @@ static struct commit *get_commit_reference(struct rev_info *revs, const char *na */ if (object->type == commit_type) { struct commit *commit = (struct commit *)object; - object->flags |= flags; if (parse_commit(commit) < 0) die("unable to parse commit %s", name); if (flags & UNINTERESTING) { + commit->object.flags |= UNINTERESTING; mark_parents_uninteresting(commit); revs->limited = 1; } @@ -241,7 +247,7 @@ int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2) return REV_TREE_DIFFERENT; tree_difference = REV_TREE_SAME; if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", - &revs->diffopt) < 0) + &revs->pruning) < 0) return REV_TREE_DIFFERENT; return tree_difference; } @@ -264,7 +270,7 @@ int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1) empty.size = 0; tree_difference = 0; - retval = diff_tree(&empty, &real, "", &revs->diffopt); + retval = diff_tree(&empty, &real, "", &revs->pruning); free(tree); return retval >= 0 && !tree_difference; @@ -375,6 +381,9 @@ static void add_parents_to_list(struct rev_info *revs, struct commit *commit, st if (revs->prune_fn) revs->prune_fn(revs, commit); + if (revs->no_walk) + return; + parent = commit->parents; while (parent) { struct commit *p = parent->item; @@ -451,21 +460,13 @@ static void limit_list(struct rev_info *revs) revs->commits = newlist; } -static void add_one_commit(struct commit *commit, struct rev_info *revs) -{ - if (!commit || (commit->object.flags & SEEN)) - return; - commit->object.flags |= SEEN; - commit_list_insert(commit, &revs->commits); -} - static int all_flags; static struct rev_info *all_revs; static int handle_one_ref(const char *path, const unsigned char *sha1) { - struct commit *commit = get_commit_reference(all_revs, path, sha1, all_flags); - add_one_commit(commit, all_revs); + struct object *object = get_reference(all_revs, path, sha1, all_flags); + add_pending_object(all_revs, object, ""); return 0; } @@ -476,12 +477,45 @@ static void handle_all(struct rev_info *revs, unsigned flags) for_each_ref(handle_one_ref); } +static int add_parents_only(struct rev_info *revs, const char *arg, int flags) +{ + unsigned char sha1[20]; + struct object *it; + struct commit *commit; + struct commit_list *parents; + + if (*arg == '^') { + flags ^= UNINTERESTING; + arg++; + } + if (get_sha1(arg, sha1)) + return 0; + while (1) { + it = get_reference(revs, arg, sha1, 0); + if (strcmp(it->type, tag_type)) + break; + memcpy(sha1, ((struct tag*)it)->tagged->sha1, 20); + } + if (strcmp(it->type, commit_type)) + return 0; + commit = (struct commit *)it; + for (parents = commit->parents; parents; parents = parents->next) { + it = &parents->item->object; + it->flags |= flags; + add_pending_object(revs, it, arg); + } + return 1; +} + void init_revisions(struct rev_info *revs) { memset(revs, 0, sizeof(*revs)); - revs->diffopt.recursive = 1; - revs->diffopt.add_remove = file_add_remove; - revs->diffopt.change = file_change; + + revs->abbrev = DEFAULT_ABBREV; + revs->ignore_merges = 1; + revs->pruning.recursive = 1; + revs->pruning.add_remove = file_add_remove; + revs->pruning.change = file_change; revs->lifo = 1; revs->dense = 1; revs->prefix = setup_git_directory(); @@ -494,6 +528,10 @@ void init_revisions(struct rev_info *revs) revs->topo_setter = topo_sort_default_setter; revs->topo_getter = topo_sort_default_getter; + + revs->commit_format = CMIT_FMT_DEFAULT; + + diff_setup(&revs->diffopt); } /* @@ -509,8 +547,6 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch const char **unrecognized = argv + 1; int left = 1; - init_revisions(revs); - /* First, search for "--" */ seen_dashdash = 0; for (i = 1; i < argc; i++) { @@ -526,13 +562,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch flags = 0; for (i = 1; i < argc; i++) { - struct commit *commit; + struct object *object; const char *arg = argv[i]; unsigned char sha1[20]; char *dotdot; int local_flags; if (*arg == '-') { + int opts; if (!strncmp(arg, "--max-count=", 12)) { revs->max_count = atoi(arg + 12); continue; @@ -640,6 +677,77 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch revs->unpacked = 1; continue; } + if (!strcmp(arg, "-r")) { + revs->diff = 1; + revs->diffopt.recursive = 1; + continue; + } + if (!strcmp(arg, "-t")) { + revs->diff = 1; + revs->diffopt.recursive = 1; + revs->diffopt.tree_in_recursive = 1; + continue; + } + if (!strcmp(arg, "-m")) { + revs->ignore_merges = 0; + continue; + } + if (!strcmp(arg, "-c")) { + revs->diff = 1; + revs->dense_combined_merges = 0; + revs->combine_merges = 1; + continue; + } + if (!strcmp(arg, "--cc")) { + revs->diff = 1; + revs->dense_combined_merges = 1; + revs->combine_merges = 1; + continue; + } + if (!strcmp(arg, "-v")) { + revs->verbose_header = 1; + continue; + } + if (!strncmp(arg, "--pretty", 8)) { + revs->verbose_header = 1; + revs->commit_format = get_commit_format(arg+8); + continue; + } + if (!strcmp(arg, "--root")) { + revs->show_root_diff = 1; + continue; + } + if (!strcmp(arg, "--no-commit-id")) { + revs->no_commit_id = 1; + continue; + } + if (!strcmp(arg, "--always")) { + revs->always_show_header = 1; + continue; + } + if (!strcmp(arg, "--no-abbrev")) { + revs->abbrev = 0; + continue; + } + if (!strcmp(arg, "--abbrev")) { + revs->abbrev = DEFAULT_ABBREV; + continue; + } + if (!strcmp(arg, "--abbrev-commit")) { + revs->abbrev_commit = 1; + continue; + } + if (!strcmp(arg, "--full-diff")) { + revs->diff = 1; + revs->full_diff = 1; + continue; + } + opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i); + if (opts > 0) { + revs->diff = 1; + i += opts - 1; + continue; + } *unrecognized++ = arg; left++; continue; @@ -656,19 +764,31 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch this = "HEAD"; if (!get_sha1(this, from_sha1) && !get_sha1(next, sha1)) { - struct commit *exclude; - struct commit *include; + struct object *exclude; + struct object *include; - exclude = get_commit_reference(revs, this, from_sha1, flags ^ UNINTERESTING); - include = get_commit_reference(revs, next, sha1, flags); + exclude = get_reference(revs, this, from_sha1, flags ^ UNINTERESTING); + include = get_reference(revs, next, sha1, flags); if (!exclude || !include) die("Invalid revision range %s..%s", arg, next); - add_one_commit(exclude, revs); - add_one_commit(include, revs); + + if (!seen_dashdash) { + *dotdot = '.'; + verify_non_filename(revs->prefix, arg); + } + add_pending_object(revs, exclude, this); + add_pending_object(revs, include, next); continue; } *dotdot = '.'; } + dotdot = strstr(arg, "^@"); + if (dotdot && !dotdot[2]) { + *dotdot = 0; + if (add_parents_only(revs, arg, flags)) + continue; + *dotdot = '^'; + } local_flags = 0; if (*arg == '^') { local_flags = UNINTERESTING; @@ -680,39 +800,72 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch if (seen_dashdash || local_flags) die("bad revision '%s'", arg); - /* If we didn't have a "--", all filenames must exist */ + /* If we didn't have a "--": + * (1) all filenames must exist; + * (2) all rev-args must not be interpretable + * as a valid filename. + * but the latter we have checked in the main loop. + */ for (j = i; j < argc; j++) verify_filename(revs->prefix, argv[j]); revs->prune_data = get_pathspec(revs->prefix, argv + i); break; } - commit = get_commit_reference(revs, arg, sha1, flags ^ local_flags); - add_one_commit(commit, revs); + if (!seen_dashdash) + verify_non_filename(revs->prefix, arg); + object = get_reference(revs, arg, sha1, flags ^ local_flags); + add_pending_object(revs, object, arg); } - if (def && !revs->commits) { + if (def && !revs->pending_objects) { unsigned char sha1[20]; - struct commit *commit; + struct object *object; if (get_sha1(def, sha1)) die("bad default revision '%s'", def); - commit = get_commit_reference(revs, def, sha1, 0); - add_one_commit(commit, revs); + object = get_reference(revs, def, sha1, 0); + add_pending_object(revs, object, def); } if (revs->topo_order || revs->unpacked) revs->limited = 1; if (revs->prune_data) { - diff_tree_setup_paths(revs->prune_data, &revs->diffopt); + diff_tree_setup_paths(revs->prune_data, &revs->pruning); revs->prune_fn = try_to_simplify_commit; + if (!revs->full_diff) + diff_tree_setup_paths(revs->prune_data, &revs->diffopt); + } + if (revs->combine_merges) { + revs->ignore_merges = 0; + if (revs->dense_combined_merges && + (revs->diffopt.output_format != DIFF_FORMAT_DIFFSTAT)) + revs->diffopt.output_format = DIFF_FORMAT_PATCH; } + revs->diffopt.abbrev = revs->abbrev; + diff_setup_done(&revs->diffopt); return left; } void prepare_revision_walk(struct rev_info *revs) { - sort_by_date(&revs->commits); + struct object_list *list; + + list = revs->pending_objects; + revs->pending_objects = NULL; + while (list) { + struct commit *commit = handle_commit(revs, list->item, list->name); + if (commit) { + if (!(commit->object.flags & SEEN)) { + commit->object.flags |= SEEN; + insert_by_date(commit, &revs->commits); + } + } + list = list->next; + } + + if (revs->no_walk) + return; if (revs->limited) limit_list(revs); if (revs->topo_order) |