Merge lt/revlist,jc/diff,jc/revparse,jc/abbrev
authorJunio C Hamano <junkio@cox.net>
Sat, 28 Jan 2006 08:16:09 +0000 (00:16 -0800)
committerJunio C Hamano <junkio@cox.net>
Sat, 28 Jan 2006 08:16:09 +0000 (00:16 -0800)
12 files changed:
Documentation/git-rev-list.txt
cache.h
commit.c
commit.h
describe.c
diff-tree.c
diff.c
diff.h
rev-list.c
rev-parse.c
sha1_name.c
show-branch.c

index f9146f1..1c6146c 100644 (file)
@@ -14,6 +14,7 @@ SYNOPSIS
             [ \--min-age=timestamp ]
             [ \--sparse ]
             [ \--no-merges ]
+            [ \--remove-empty ]
             [ \--all ]
             [ [ \--merge-order [ \--show-breaks ] ] | [ \--topo-order ] ]
             [ \--parents ]
@@ -80,6 +81,9 @@ OPTIONS
        (still subject to count and age limitation), but apply
        merge simplification nevertheless.
 
+--remove-empty::
+       Stop when a given path disappears from the tree.
+
 --all::
        Pretend as if all the refs in `$GIT_DIR/refs/` are
        listed on the command line as <commit>.
diff --git a/cache.h b/cache.h
index 1e8e27f..bdbe2d6 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -221,6 +221,9 @@ extern int has_pack_file(const unsigned char *sha1);
 extern int has_pack_index(const unsigned char *sha1);
 
 /* Convert to/from hex/sha1 representation */
+#define MINIMUM_ABBREV 4
+#define DEFAULT_ABBREV 7
+
 extern int get_sha1(const char *str, unsigned char *sha1);
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 extern char *sha1_to_hex(const unsigned char *sha1);   /* static buffer result! */
index b8bf35e..97205bf 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -426,33 +426,37 @@ static int is_empty_line(const char *line, int len)
        return !len;
 }
 
-static int add_parent_info(enum cmit_fmt fmt, char *buf, const char *line, int parents)
+static int add_merge_info(enum cmit_fmt fmt, char *buf, const struct commit *commit, int abbrev)
 {
-       int offset = 0;
+       struct commit_list *parent = commit->parents;
+       int offset;
 
-       if (fmt == CMIT_FMT_ONELINE)
-               return offset;
-       switch (parents) {
-       case 1:
-               break;
-       case 2:
-               /* Go back to the previous line: 40 characters of previous parent, and one '\n' */
-               offset = sprintf(buf, "Merge: %.40s\n", line-41);
-               /* Fallthrough */
-       default:
-               /* Replace the previous '\n' with a space */
-               buf[offset-1] = ' ';
-               offset += sprintf(buf + offset, "%.40s\n", line+7);
+       if ((fmt == CMIT_FMT_ONELINE) || !parent || !parent->next)
+               return 0;
+
+       offset = sprintf(buf, "Merge:");
+
+       while (parent) {
+               struct commit *p = parent->item;
+               parent = parent->next;
+
+               offset += sprintf(buf + offset,
+                                 abbrev ? " %s..." : " %s",
+                                 abbrev
+                                 ? find_unique_abbrev(p->object.sha1, abbrev)
+                                 : sha1_to_hex(p->object.sha1));
        }
+       buf[offset++] = '\n';
        return offset;
 }
 
-unsigned long pretty_print_commit(enum cmit_fmt fmt, const char *msg, unsigned long len, char *buf, unsigned long space)
+unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev)
 {
        int hdr = 1, body = 0;
        unsigned long offset = 0;
-       int parents = 0;
        int indent = (fmt == CMIT_FMT_ONELINE) ? 0 : 4;
+       int parents_shown = 0;
+       const char *msg = commit->buffer;
 
        for (;;) {
                const char *line = msg;
@@ -488,9 +492,15 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const char *msg, unsigned l
                        if (!memcmp(line, "parent ", 7)) {
                                if (linelen != 48)
                                        die("bad parent line in commit");
-                               offset += add_parent_info(fmt, buf + offset, line, ++parents);
+                               continue;
                        }
 
+                       if (!parents_shown) {
+                               offset += add_merge_info(fmt, buf + offset,
+                                                        commit, abbrev);
+                               parents_shown = 1;
+                               continue;
+                       }
                        /*
                         * MEDIUM == DEFAULT shows only author with dates.
                         * FULL shows both authors but not dates.
index 9c4a244..986b22d 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -48,7 +48,7 @@ enum cmit_fmt {
 };
 
 extern enum cmit_fmt get_commit_format(const char *arg);
-extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const char *msg, unsigned long len, char *buf, unsigned long space);
+extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev);
 
 /** Removes the first commit from a list sorted by date, and adds all
  * of its parents.
index 4866510..ff65742 100644 (file)
@@ -11,7 +11,6 @@ static const char describe_usage[] =
 static int all = 0;    /* Default to annotated tags only */
 static int tags = 0;   /* But allow any tags if --tags is specified */
 
-#define DEFAULT_ABBREV 8 /* maybe too many */
 static int abbrev = DEFAULT_ABBREV;
 
 static int names = 0, allocs = 0;
@@ -155,7 +154,7 @@ int main(int argc, char **argv)
                        tags = 1;
                else if (!strncmp(arg, "--abbrev=", 9)) {
                        abbrev = strtoul(arg + 9, NULL, 10);
-                       if (abbrev < 4 || 40 <= abbrev)
+                       if (abbrev < MINIMUM_ABBREV || 40 <= abbrev)
                                abbrev = DEFAULT_ABBREV;
                }
                else
index 99c580c..6593a69 100644 (file)
@@ -67,12 +67,13 @@ static int diff_root_tree(const unsigned char *new, const char *base)
 
 static const char *generate_header(const unsigned char *commit_sha1,
                                   const unsigned char *parent_sha1,
-                                  const char *msg)
+                                  const struct commit *commit)
 {
        static char this_header[16384];
        int offset;
        unsigned long len;
        int abbrev = diff_options.abbrev;
+       const char *msg = commit->buffer;
 
        if (!verbose_header)
                return sha1_to_hex(commit_sha1);
@@ -89,9 +90,9 @@ static const char *generate_header(const unsigned char *commit_sha1,
                                  : "root");
        else
                offset += sprintf(this_header + offset, "(from parents)\n");
-       offset += pretty_print_commit(commit_format, msg, len,
+       offset += pretty_print_commit(commit_format, commit, len,
                                      this_header + offset,
-                                     sizeof(this_header) - offset);
+                                     sizeof(this_header) - offset, abbrev);
        return this_header;
 }
 
@@ -110,7 +111,7 @@ static int diff_tree_commit(const unsigned char *commit_sha1)
        
        /* Root commit? */
        if (show_root_diff && !commit->parents) {
-               header = generate_header(sha1, NULL, commit->buffer);
+               header = generate_header(sha1, NULL, commit);
                diff_root_tree(commit_sha1, "");
        }
 
@@ -119,8 +120,7 @@ static int diff_tree_commit(const unsigned char *commit_sha1)
                if (ignore_merges)
                        return 0;
                else if (combine_merges) {
-                       header = generate_header(sha1, sha1,
-                                                commit->buffer);
+                       header = generate_header(sha1, sha1, commit);
                        return diff_tree_combined_merge(sha1, header,
                                                        show_empty_combined,
                                                        dense_combined_merges);
@@ -129,9 +129,7 @@ static int diff_tree_commit(const unsigned char *commit_sha1)
 
        for (parents = commit->parents; parents; parents = parents->next) {
                struct commit *parent = parents->item;
-               header = generate_header(sha1,
-                                        parent->object.sha1,
-                                        commit->buffer);
+               header = generate_header(sha1, parent->object.sha1, commit);
                diff_tree_sha1_top(parent->object.sha1, commit_sha1, "");
                if (!header && verbose_header) {
                        header_prefix = "\ndiff-tree ";
diff --git a/diff.c b/diff.c
index 17d68fa..8ae6dbc 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -723,7 +723,7 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
 
        if (memcmp(one->sha1, two->sha1, 20)) {
                char one_sha1[41];
-               int abbrev = o->full_index ? 40 : DIFF_DEFAULT_INDEX_ABBREV;
+               int abbrev = o->full_index ? 40 : DEFAULT_ABBREV;
                memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
 
                len += snprintf(msg + len, sizeof(msg) - len,
@@ -846,9 +846,14 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        else if (!strcmp(arg, "--find-copies-harder"))
                options->find_copies_harder = 1;
        else if (!strcmp(arg, "--abbrev"))
-               options->abbrev = DIFF_DEFAULT_ABBREV;
-       else if (!strncmp(arg, "--abbrev=", 9))
+               options->abbrev = DEFAULT_ABBREV;
+       else if (!strncmp(arg, "--abbrev=", 9)) {
                options->abbrev = strtoul(arg + 9, NULL, 10);
+               if (options->abbrev < MINIMUM_ABBREV)
+                       options->abbrev = MINIMUM_ABBREV;
+               else if (40 < options->abbrev)
+                       options->abbrev = 40;
+       }
        else
                return 0;
        return 1;
diff --git a/diff.h b/diff.h
index 539bd2f..9a0169c 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -101,9 +101,6 @@ extern int diff_setup_done(struct diff_options *);
 
 #define DIFF_PICKAXE_ALL       1
 
-#define DIFF_DEFAULT_INDEX_ABBREV      7 /* hex digits */
-#define DIFF_DEFAULT_ABBREV    7 /* hex digits */
-
 extern void diffcore_std(struct diff_options *);
 
 extern void diffcore_std_no_resolve(struct diff_options *);
index e00e6fc..0b142c1 100644 (file)
@@ -21,6 +21,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"
@@ -54,6 +55,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)
 {
@@ -81,7 +83,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), 0);
                printf("%s%c", pretty_header, hdr_termination);
        }
        fflush(stdout);
@@ -424,14 +426,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 +461,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 +470,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 +499,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 +583,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 +604,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 +633,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;
@@ -808,6 +825,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;
index 7abad35..d2f0864 100644 (file)
@@ -20,6 +20,7 @@ static char *def = NULL;
 #define REVERSED 1
 static int show_type = NORMAL;
 static int symbolic = 0;
+static int abbrev = 0;
 static int output_sq = 0;
 
 static int revs_count = 0;
@@ -95,6 +96,8 @@ static void show_rev(int type, const unsigned char *sha1, const char *name)
                putchar('^');
        if (symbolic && name)
                show(name);
+       else if (abbrev)
+               show(find_unique_abbrev(sha1, abbrev));
        else
                show(sha1_to_hex(sha1));
 }
@@ -196,6 +199,19 @@ int main(int argc, char **argv)
                                verify = 1;
                                continue;
                        }
+                       if (!strcmp(arg, "--short") ||
+                           !strncmp(arg, "--short=", 9)) {
+                               filter &= ~(DO_FLAGS|DO_NOREV);
+                               verify = 1;
+                               abbrev = DEFAULT_ABBREV;
+                               if (arg[8] == '=')
+                                       abbrev = strtoul(arg + 9, NULL, 10);
+                               if (abbrev < MINIMUM_ABBREV)
+                                       abbrev = MINIMUM_ABBREV;
+                               else if (40 <= abbrev)
+                                       abbrev = 40;
+                               continue;
+                       }
                        if (!strcmp(arg, "--sq")) {
                                output_sq = 1;
                                continue;
@@ -294,7 +310,9 @@ int main(int argc, char **argv)
                }
                if (verify)
                        die("Needed a single revision");
-               if (lstat(arg, &st) < 0)
+               if ((filter & DO_REVS) &&
+                   (filter & DO_NONFLAGS) && /* !def && */
+                   lstat(arg, &st) < 0)
                        die("'%s': %s", arg, strerror(errno));
                as_is = 1;
                show_file(arg);
index e18a96d..ba0747c 100644 (file)
@@ -155,7 +155,7 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
        char canonical[40];
        unsigned char res[20];
 
-       if (len < 4)
+       if (len < MINIMUM_ABBREV)
                return -1;
        memset(res, 0, 20);
        memset(canonical, 'x', 40);
index 7a0dcc6..ffe7456 100644 (file)
@@ -258,8 +258,8 @@ static void show_one_commit(struct commit *commit, int no_name)
        char pretty[256], *cp;
        struct commit_name *name = commit->object.util;
        if (commit->object.parsed)
-               pretty_print_commit(CMIT_FMT_ONELINE, commit->buffer, ~0,
-                                   pretty, sizeof(pretty));
+               pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
+                                   pretty, sizeof(pretty), 0);
        else
                strcpy(pretty, "(unavailable)");
        if (!strncmp(pretty, "[PATCH] ", 8))