X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=rev-list.c;h=63391fc1136d4d4045db6406face4c53915cd5bf;hb=a348ab702a84983c258e4961a58b1b9502f428c8;hp=e00e6fc76df8236c925e904fa270a2293099d6cf;hpb=767e130915015f897fb87b939843b4882212574b;p=git.git diff --git a/rev-list.c b/rev-list.c index e00e6fc7..63391fc1 100644 --- a/rev-list.c +++ b/rev-list.c @@ -12,6 +12,7 @@ #define COUNTED (1u << 2) #define SHOWN (1u << 3) #define TREECHANGE (1u << 4) +#define TMP_MARK (1u << 5) /* for isolated cases; clean after use */ static const char rev_list_usage[] = "git-rev-list [OPTION] ... [ -- paths... ]\n" @@ -21,6 +22,7 @@ static const char rev_list_usage[] = " --min-age=epoch\n" " --sparse\n" " --no-merges\n" +" --remove-empty\n" " --all\n" " ordering output:\n" " --merge-order [ --show-breaks ]\n" @@ -30,6 +32,7 @@ static const char rev_list_usage[] = " --objects\n" " --unpacked\n" " --header | --pretty\n" +" --abbrev=nr | --no-abbrev\n" " special purpose:\n" " --bisect" ; @@ -41,6 +44,7 @@ static int tag_objects = 0; static int tree_objects = 0; static int blob_objects = 0; static int verbose_header = 0; +static int abbrev = DEFAULT_ABBREV; static int show_parents = 0; static int hdr_termination = 0; static const char *commit_prefix = ""; @@ -54,6 +58,7 @@ static int stop_traversal = 0; static int topo_order = 0; static int no_merges = 0; static const char **paths = NULL; +static int remove_empty_trees = 0; static void show_commit(struct commit *commit) { @@ -70,9 +75,21 @@ static void show_commit(struct commit *commit) if (show_parents) { struct commit_list *parents = commit->parents; while (parents) { - printf(" %s", sha1_to_hex(parents->item->object.sha1)); + struct object *o = &(parents->item->object); parents = parents->next; + if (o->flags & TMP_MARK) + continue; + printf(" %s", sha1_to_hex(o->sha1)); + o->flags |= TMP_MARK; } + /* TMP_MARK is a general purpose flag that can + * be used locally, but the user should clean + * things up after it is done with them. + */ + for (parents = commit->parents; + parents; + parents = parents->next) + parents->item->object.flags &= ~TMP_MARK; } if (commit_format == CMIT_FMT_ONELINE) putchar(' '); @@ -81,7 +98,7 @@ static void show_commit(struct commit *commit) if (verbose_header) { static char pretty_header[16384]; - pretty_print_commit(commit_format, commit->buffer, ~0, pretty_header, sizeof(pretty_header)); + pretty_print_commit(commit_format, commit, ~0, pretty_header, sizeof(pretty_header), abbrev); printf("%s%c", pretty_header, hdr_termination); } fflush(stdout); @@ -424,14 +441,33 @@ static void mark_edges_uninteresting(struct commit_list *list) } } -static int is_different = 0; +#define TREE_SAME 0 +#define TREE_NEW 1 +#define TREE_DIFFERENT 2 +static int tree_difference = TREE_SAME; static void file_add_remove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, const char *base, const char *path) { - is_different = 1; + int diff = TREE_DIFFERENT; + + /* + * Is it an add of a new file? It means that + * the old tree didn't have it at all, so we + * will turn "TREE_SAME" -> "TREE_NEW", but + * leave any "TREE_DIFFERENT" alone (and if + * it already was "TREE_NEW", we'll keep it + * "TREE_NEW" of course). + */ + if (addremove == '+') { + diff = tree_difference; + if (diff != TREE_SAME) + return; + diff = TREE_NEW; + } + tree_difference = diff; } static void file_change(struct diff_options *options, @@ -440,7 +476,7 @@ static void file_change(struct diff_options *options, const unsigned char *new_sha1, const char *base, const char *path) { - is_different = 1; + tree_difference = TREE_DIFFERENT; } static struct diff_options diff_opt = { @@ -449,12 +485,16 @@ static struct diff_options diff_opt = { .change = file_change, }; -static int same_tree(struct tree *t1, struct tree *t2) +static int compare_tree(struct tree *t1, struct tree *t2) { - is_different = 0; + if (!t1) + return TREE_NEW; + if (!t2) + return TREE_DIFFERENT; + tree_difference = TREE_SAME; if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", &diff_opt) < 0) - return 0; - return !is_different; + return TREE_DIFFERENT; + return tree_difference; } static int same_tree_as_empty(struct tree *t1) @@ -474,28 +514,55 @@ static int same_tree_as_empty(struct tree *t1) empty.buf = ""; empty.size = 0; - is_different = 0; + tree_difference = 0; retval = diff_tree(&empty, &real, "", &diff_opt); free(tree); - return retval >= 0 && !is_different; + return retval >= 0 && !tree_difference; } -static struct commit *try_to_simplify_merge(struct commit *commit, struct commit_list *parent) +static void try_to_simplify_commit(struct commit *commit) { + struct commit_list **pp, *parent; + if (!commit->tree) - return NULL; + return; - while (parent) { + if (!commit->parents) { + if (!same_tree_as_empty(commit->tree)) + commit->object.flags |= TREECHANGE; + return; + } + + pp = &commit->parents; + while ((parent = *pp) != NULL) { struct commit *p = parent->item; - parent = parent->next; + + if (p->object.flags & UNINTERESTING) { + pp = &parent->next; + continue; + } + parse_commit(p); - if (!p->tree) + switch (compare_tree(p->tree, commit->tree)) { + case TREE_SAME: + parent->next = NULL; + commit->parents = parent; + return; + + case TREE_NEW: + if (remove_empty_trees && same_tree_as_empty(p->tree)) { + *pp = parent->next; + continue; + } + /* fallthrough */ + case TREE_DIFFERENT: + pp = &parent->next; continue; - if (same_tree(commit->tree, p->tree)) - return p; + } + die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1)); } - return NULL; + commit->object.flags |= TREECHANGE; } static void add_parents_to_list(struct commit *commit, struct commit_list **list) @@ -531,20 +598,14 @@ static void add_parents_to_list(struct commit *commit, struct commit_list **list } /* - * Ok, the commit wasn't uninteresting. If it - * is a merge, try to find the parent that has - * no differences in the path set if one exists. + * Ok, the commit wasn't uninteresting. Try to + * simplify the commit history and find the parent + * that has no differences in the path set if one exists. */ - if (paths && parent && parent->next) { - struct commit *preferred; - - preferred = try_to_simplify_merge(commit, parent); - if (preferred) { - parent->item = preferred; - parent->next = NULL; - } - } + if (paths) + try_to_simplify_commit(commit); + parent = commit->parents; while (parent) { struct commit *p = parent->item; @@ -558,33 +619,6 @@ static void add_parents_to_list(struct commit *commit, struct commit_list **list } } -static void compress_list(struct commit_list *list) -{ - while (list) { - struct commit *commit = list->item; - struct commit_list *parent = commit->parents; - list = list->next; - - if (!parent) { - if (!same_tree_as_empty(commit->tree)) - commit->object.flags |= TREECHANGE; - continue; - } - - /* - * Exactly one parent? Check if it leaves the tree - * unchanged - */ - if (!parent->next) { - struct tree *t1 = commit->tree; - struct tree *t2 = parent->item->tree; - if (!t1 || !t2 || same_tree(t1, t2)) - continue; - } - commit->object.flags |= TREECHANGE; - } -} - static struct commit_list *limit_list(struct commit_list *list) { struct commit_list *newlist = NULL; @@ -614,8 +648,6 @@ static struct commit_list *limit_list(struct commit_list *list) } if (tree_objects) mark_edges_uninteresting(newlist); - if (paths && dense) - compress_list(newlist); if (bisect_list) newlist = find_bisection(newlist); return newlist; @@ -732,6 +764,21 @@ int main(int argc, const char **argv) struct commit *commit; unsigned char sha1[20]; + /* accept -, like traditilnal "head" */ + if ((*arg == '-') && isdigit(arg[1])) { + max_count = atoi(arg + 1); + continue; + } + if (!strcmp(arg, "-n")) { + if (++i >= argc) + die("-n requires an argument"); + max_count = atoi(argv[i]); + continue; + } + if (!strncmp(arg,"-n",2)) { + max_count = atoi(arg + 2); + continue; + } if (!strncmp(arg, "--max-count=", 12)) { max_count = atoi(arg + 12); continue; @@ -750,6 +797,18 @@ int main(int argc, const char **argv) verbose_header = 1; continue; } + if (!strcmp(arg, "--no-abbrev")) { + abbrev = 0; + continue; + } + if (!strncmp(arg, "--abbrev=", 9)) { + abbrev = strtoul(arg + 9, NULL, 10); + if (abbrev && abbrev < MINIMUM_ABBREV) + abbrev = MINIMUM_ABBREV; + else if (40 < abbrev) + abbrev = 40; + continue; + } if (!strncmp(arg, "--pretty", 8)) { commit_format = get_commit_format(arg+8); verbose_header = 1; @@ -808,6 +867,10 @@ int main(int argc, const char **argv) dense = 0; continue; } + if (!strcmp(arg, "--remove-empty")) { + remove_empty_trees = 1; + continue; + } if (!strcmp(arg, "--")) { i++; break;