rev-list.con commit pack-objects: hash basename and direname a bit differently. (eeef713)
   1#include "cache.h"
   2#include "refs.h"
   3#include "tag.h"
   4#include "commit.h"
   5#include "tree.h"
   6#include "blob.h"
   7#include "epoch.h"
   8#include "diff.h"
   9
  10#define SEEN            (1u << 0)
  11#define INTERESTING     (1u << 1)
  12#define COUNTED         (1u << 2)
  13#define SHOWN           (1u << 3)
  14#define TREECHANGE      (1u << 4)
  15#define TMP_MARK        (1u << 5) /* for isolated cases; clean after use */
  16
  17static const char rev_list_usage[] =
  18"git-rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
  19"  limiting output:\n"
  20"    --max-count=nr\n"
  21"    --max-age=epoch\n"
  22"    --min-age=epoch\n"
  23"    --sparse\n"
  24"    --no-merges\n"
  25"    --remove-empty\n"
  26"    --all\n"
  27"  ordering output:\n"
  28"    --merge-order [ --show-breaks ]\n"
  29"    --topo-order\n"
  30"  formatting output:\n"
  31"    --parents\n"
  32"    --objects\n"
  33"    --unpacked\n"
  34"    --header | --pretty\n"
  35"    --abbrev=nr | --no-abbrev\n"
  36"  special purpose:\n"
  37"    --bisect"
  38;
  39
  40static int dense = 1;
  41static int unpacked = 0;
  42static int bisect_list = 0;
  43static int tag_objects = 0;
  44static int tree_objects = 0;
  45static int blob_objects = 0;
  46static int verbose_header = 0;
  47static int abbrev = DEFAULT_ABBREV;
  48static int show_parents = 0;
  49static int hdr_termination = 0;
  50static const char *commit_prefix = "";
  51static unsigned long max_age = -1;
  52static unsigned long min_age = -1;
  53static int max_count = -1;
  54static enum cmit_fmt commit_format = CMIT_FMT_RAW;
  55static int merge_order = 0;
  56static int show_breaks = 0;
  57static int stop_traversal = 0;
  58static int topo_order = 0;
  59static int no_merges = 0;
  60static const char **paths = NULL;
  61static int remove_empty_trees = 0;
  62
  63static void show_commit(struct commit *commit)
  64{
  65        commit->object.flags |= SHOWN;
  66        if (show_breaks) {
  67                commit_prefix = "| ";
  68                if (commit->object.flags & DISCONTINUITY) {
  69                        commit_prefix = "^ ";     
  70                } else if (commit->object.flags & BOUNDARY) {
  71                        commit_prefix = "= ";
  72                } 
  73        }                       
  74        printf("%s%s", commit_prefix, sha1_to_hex(commit->object.sha1));
  75        if (show_parents) {
  76                struct commit_list *parents = commit->parents;
  77                while (parents) {
  78                        struct object *o = &(parents->item->object);
  79                        parents = parents->next;
  80                        if (o->flags & TMP_MARK)
  81                                continue;
  82                        printf(" %s", sha1_to_hex(o->sha1));
  83                        o->flags |= TMP_MARK;
  84                }
  85                /* TMP_MARK is a general purpose flag that can
  86                 * be used locally, but the user should clean
  87                 * things up after it is done with them.
  88                 */
  89                for (parents = commit->parents;
  90                     parents;
  91                     parents = parents->next)
  92                        parents->item->object.flags &= ~TMP_MARK;
  93        }
  94        if (commit_format == CMIT_FMT_ONELINE)
  95                putchar(' ');
  96        else
  97                putchar('\n');
  98
  99        if (verbose_header) {
 100                static char pretty_header[16384];
 101                pretty_print_commit(commit_format, commit, ~0, pretty_header, sizeof(pretty_header), abbrev);
 102                printf("%s%c", pretty_header, hdr_termination);
 103        }
 104        fflush(stdout);
 105}
 106
 107static int rewrite_one(struct commit **pp)
 108{
 109        for (;;) {
 110                struct commit *p = *pp;
 111                if (p->object.flags & (TREECHANGE | UNINTERESTING))
 112                        return 0;
 113                if (!p->parents)
 114                        return -1;
 115                *pp = p->parents->item;
 116        }
 117}
 118
 119static void rewrite_parents(struct commit *commit)
 120{
 121        struct commit_list **pp = &commit->parents;
 122        while (*pp) {
 123                struct commit_list *parent = *pp;
 124                if (rewrite_one(&parent->item) < 0) {
 125                        *pp = parent->next;
 126                        continue;
 127                }
 128                pp = &parent->next;
 129        }
 130}
 131
 132static int filter_commit(struct commit * commit)
 133{
 134        if (stop_traversal && (commit->object.flags & BOUNDARY))
 135                return STOP;
 136        if (commit->object.flags & (UNINTERESTING|SHOWN))
 137                return CONTINUE;
 138        if (min_age != -1 && (commit->date > min_age))
 139                return CONTINUE;
 140        if (max_age != -1 && (commit->date < max_age)) {
 141                stop_traversal=1;
 142                return CONTINUE;
 143        }
 144        if (no_merges && (commit->parents && commit->parents->next))
 145                return CONTINUE;
 146        if (paths && dense) {
 147                if (!(commit->object.flags & TREECHANGE))
 148                        return CONTINUE;
 149                rewrite_parents(commit);
 150        }
 151        return DO;
 152}
 153
 154static int process_commit(struct commit * commit)
 155{
 156        int action=filter_commit(commit);
 157
 158        if (action == STOP) {
 159                return STOP;
 160        }
 161
 162        if (action == CONTINUE) {
 163                return CONTINUE;
 164        }
 165
 166        if (max_count != -1 && !max_count--)
 167                return STOP;
 168
 169        show_commit(commit);
 170
 171        return CONTINUE;
 172}
 173
 174static struct object_list **add_object(struct object *obj, struct object_list **p, const char *name)
 175{
 176        struct object_list *entry = xmalloc(sizeof(*entry));
 177        entry->item = obj;
 178        entry->next = *p;
 179        entry->name = name;
 180        *p = entry;
 181        return &entry->next;
 182}
 183
 184static struct object_list **process_blob(struct blob *blob, struct object_list **p, const char *name)
 185{
 186        struct object *obj = &blob->object;
 187
 188        if (!blob_objects)
 189                return p;
 190        if (obj->flags & (UNINTERESTING | SEEN))
 191                return p;
 192        obj->flags |= SEEN;
 193        return add_object(obj, p, name);
 194}
 195
 196static struct object_list **process_tree(struct tree *tree, struct object_list **p, const char *name)
 197{
 198        struct object *obj = &tree->object;
 199        struct tree_entry_list *entry;
 200
 201        if (!tree_objects)
 202                return p;
 203        if (obj->flags & (UNINTERESTING | SEEN))
 204                return p;
 205        if (parse_tree(tree) < 0)
 206                die("bad tree object %s", sha1_to_hex(obj->sha1));
 207        obj->flags |= SEEN;
 208        p = add_object(obj, p, name);
 209        entry = tree->entries;
 210        tree->entries = NULL;
 211        while (entry) {
 212                struct tree_entry_list *next = entry->next;
 213                if (entry->directory)
 214                        p = process_tree(entry->item.tree, p, entry->name);
 215                else
 216                        p = process_blob(entry->item.blob, p, entry->name);
 217                free(entry);
 218                entry = next;
 219        }
 220        return p;
 221}
 222
 223static struct object_list *pending_objects = NULL;
 224
 225static void show_commit_list(struct commit_list *list)
 226{
 227        struct object_list *objects = NULL, **p = &objects, *pending;
 228        while (list) {
 229                struct commit *commit = pop_most_recent_commit(&list, SEEN);
 230
 231                p = process_tree(commit->tree, p, "");
 232                if (process_commit(commit) == STOP)
 233                        break;
 234        }
 235        for (pending = pending_objects; pending; pending = pending->next) {
 236                struct object *obj = pending->item;
 237                const char *name = pending->name;
 238                if (obj->flags & (UNINTERESTING | SEEN))
 239                        continue;
 240                if (obj->type == tag_type) {
 241                        obj->flags |= SEEN;
 242                        p = add_object(obj, p, name);
 243                        continue;
 244                }
 245                if (obj->type == tree_type) {
 246                        p = process_tree((struct tree *)obj, p, name);
 247                        continue;
 248                }
 249                if (obj->type == blob_type) {
 250                        p = process_blob((struct blob *)obj, p, name);
 251                        continue;
 252                }
 253                die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
 254        }
 255        while (objects) {
 256                /* An object with name "foo\n0000000000000000000000000000000000000000"
 257                 * can be used confuse downstream git-pack-objects very badly.
 258                 */
 259                const char *ep = strchr(objects->name, '\n');
 260                if (ep) {
 261                        printf("%s %.*s\n", sha1_to_hex(objects->item->sha1),
 262                               (int) (ep - objects->name),
 263                               objects->name);
 264                }
 265                else
 266                        printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name);
 267                objects = objects->next;
 268        }
 269}
 270
 271static void mark_blob_uninteresting(struct blob *blob)
 272{
 273        if (!blob_objects)
 274                return;
 275        if (blob->object.flags & UNINTERESTING)
 276                return;
 277        blob->object.flags |= UNINTERESTING;
 278}
 279
 280static void mark_tree_uninteresting(struct tree *tree)
 281{
 282        struct object *obj = &tree->object;
 283        struct tree_entry_list *entry;
 284
 285        if (!tree_objects)
 286                return;
 287        if (obj->flags & UNINTERESTING)
 288                return;
 289        obj->flags |= UNINTERESTING;
 290        if (!has_sha1_file(obj->sha1))
 291                return;
 292        if (parse_tree(tree) < 0)
 293                die("bad tree %s", sha1_to_hex(obj->sha1));
 294        entry = tree->entries;
 295        tree->entries = NULL;
 296        while (entry) {
 297                struct tree_entry_list *next = entry->next;
 298                if (entry->directory)
 299                        mark_tree_uninteresting(entry->item.tree);
 300                else
 301                        mark_blob_uninteresting(entry->item.blob);
 302                free(entry);
 303                entry = next;
 304        }
 305}
 306
 307static void mark_parents_uninteresting(struct commit *commit)
 308{
 309        struct commit_list *parents = commit->parents;
 310
 311        while (parents) {
 312                struct commit *commit = parents->item;
 313                commit->object.flags |= UNINTERESTING;
 314
 315                /*
 316                 * Normally we haven't parsed the parent
 317                 * yet, so we won't have a parent of a parent
 318                 * here. However, it may turn out that we've
 319                 * reached this commit some other way (where it
 320                 * wasn't uninteresting), in which case we need
 321                 * to mark its parents recursively too..
 322                 */
 323                if (commit->parents)
 324                        mark_parents_uninteresting(commit);
 325
 326                /*
 327                 * A missing commit is ok iff its parent is marked 
 328                 * uninteresting.
 329                 *
 330                 * We just mark such a thing parsed, so that when
 331                 * it is popped next time around, we won't be trying
 332                 * to parse it and get an error.
 333                 */
 334                if (!has_sha1_file(commit->object.sha1))
 335                        commit->object.parsed = 1;
 336                parents = parents->next;
 337        }
 338}
 339
 340static int everybody_uninteresting(struct commit_list *orig)
 341{
 342        struct commit_list *list = orig;
 343        while (list) {
 344                struct commit *commit = list->item;
 345                list = list->next;
 346                if (commit->object.flags & UNINTERESTING)
 347                        continue;
 348                return 0;
 349        }
 350        return 1;
 351}
 352
 353/*
 354 * This is a truly stupid algorithm, but it's only
 355 * used for bisection, and we just don't care enough.
 356 *
 357 * We care just barely enough to avoid recursing for
 358 * non-merge entries.
 359 */
 360static int count_distance(struct commit_list *entry)
 361{
 362        int nr = 0;
 363
 364        while (entry) {
 365                struct commit *commit = entry->item;
 366                struct commit_list *p;
 367
 368                if (commit->object.flags & (UNINTERESTING | COUNTED))
 369                        break;
 370                if (!paths || (commit->object.flags & TREECHANGE))
 371                        nr++;
 372                commit->object.flags |= COUNTED;
 373                p = commit->parents;
 374                entry = p;
 375                if (p) {
 376                        p = p->next;
 377                        while (p) {
 378                                nr += count_distance(p);
 379                                p = p->next;
 380                        }
 381                }
 382        }
 383
 384        return nr;
 385}
 386
 387static void clear_distance(struct commit_list *list)
 388{
 389        while (list) {
 390                struct commit *commit = list->item;
 391                commit->object.flags &= ~COUNTED;
 392                list = list->next;
 393        }
 394}
 395
 396static struct commit_list *find_bisection(struct commit_list *list)
 397{
 398        int nr, closest;
 399        struct commit_list *p, *best;
 400
 401        nr = 0;
 402        p = list;
 403        while (p) {
 404                if (!paths || (p->item->object.flags & TREECHANGE))
 405                        nr++;
 406                p = p->next;
 407        }
 408        closest = 0;
 409        best = list;
 410
 411        for (p = list; p; p = p->next) {
 412                int distance;
 413
 414                if (paths && !(p->item->object.flags & TREECHANGE))
 415                        continue;
 416
 417                distance = count_distance(p);
 418                clear_distance(list);
 419                if (nr - distance < distance)
 420                        distance = nr - distance;
 421                if (distance > closest) {
 422                        best = p;
 423                        closest = distance;
 424                }
 425        }
 426        if (best)
 427                best->next = NULL;
 428        return best;
 429}
 430
 431static void mark_edges_uninteresting(struct commit_list *list)
 432{
 433        for ( ; list; list = list->next) {
 434                struct commit_list *parents = list->item->parents;
 435
 436                for ( ; parents; parents = parents->next) {
 437                        struct commit *commit = parents->item;
 438                        if (commit->object.flags & UNINTERESTING)
 439                                mark_tree_uninteresting(commit->tree);
 440                }
 441        }
 442}
 443
 444#define TREE_SAME       0
 445#define TREE_NEW        1
 446#define TREE_DIFFERENT  2
 447static int tree_difference = TREE_SAME;
 448
 449static void file_add_remove(struct diff_options *options,
 450                    int addremove, unsigned mode,
 451                    const unsigned char *sha1,
 452                    const char *base, const char *path)
 453{
 454        int diff = TREE_DIFFERENT;
 455
 456        /*
 457         * Is it an add of a new file? It means that
 458         * the old tree didn't have it at all, so we
 459         * will turn "TREE_SAME" -> "TREE_NEW", but
 460         * leave any "TREE_DIFFERENT" alone (and if
 461         * it already was "TREE_NEW", we'll keep it
 462         * "TREE_NEW" of course).
 463         */
 464        if (addremove == '+') {
 465                diff = tree_difference;
 466                if (diff != TREE_SAME)
 467                        return;
 468                diff = TREE_NEW;
 469        }
 470        tree_difference = diff;
 471}
 472
 473static void file_change(struct diff_options *options,
 474                 unsigned old_mode, unsigned new_mode,
 475                 const unsigned char *old_sha1,
 476                 const unsigned char *new_sha1,
 477                 const char *base, const char *path)
 478{
 479        tree_difference = TREE_DIFFERENT;
 480}
 481
 482static struct diff_options diff_opt = {
 483        .recursive = 1,
 484        .add_remove = file_add_remove,
 485        .change = file_change,
 486};
 487
 488static int compare_tree(struct tree *t1, struct tree *t2)
 489{
 490        if (!t1)
 491                return TREE_NEW;
 492        if (!t2)
 493                return TREE_DIFFERENT;
 494        tree_difference = TREE_SAME;
 495        if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", &diff_opt) < 0)
 496                return TREE_DIFFERENT;
 497        return tree_difference;
 498}
 499
 500static int same_tree_as_empty(struct tree *t1)
 501{
 502        int retval;
 503        void *tree;
 504        struct tree_desc empty, real;
 505
 506        if (!t1)
 507                return 0;
 508
 509        tree = read_object_with_reference(t1->object.sha1, "tree", &real.size, NULL);
 510        if (!tree)
 511                return 0;
 512        real.buf = tree;
 513
 514        empty.buf = "";
 515        empty.size = 0;
 516
 517        tree_difference = 0;
 518        retval = diff_tree(&empty, &real, "", &diff_opt);
 519        free(tree);
 520
 521        return retval >= 0 && !tree_difference;
 522}
 523
 524static void try_to_simplify_commit(struct commit *commit)
 525{
 526        struct commit_list **pp, *parent;
 527
 528        if (!commit->tree)
 529                return;
 530
 531        if (!commit->parents) {
 532                if (!same_tree_as_empty(commit->tree))
 533                        commit->object.flags |= TREECHANGE;
 534                return;
 535        }
 536
 537        pp = &commit->parents;
 538        while ((parent = *pp) != NULL) {
 539                struct commit *p = parent->item;
 540
 541                if (p->object.flags & UNINTERESTING) {
 542                        pp = &parent->next;
 543                        continue;
 544                }
 545
 546                parse_commit(p);
 547                switch (compare_tree(p->tree, commit->tree)) {
 548                case TREE_SAME:
 549                        parent->next = NULL;
 550                        commit->parents = parent;
 551                        return;
 552
 553                case TREE_NEW:
 554                        if (remove_empty_trees && same_tree_as_empty(p->tree)) {
 555                                *pp = parent->next;
 556                                continue;
 557                        }
 558                /* fallthrough */
 559                case TREE_DIFFERENT:
 560                        pp = &parent->next;
 561                        continue;
 562                }
 563                die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
 564        }
 565        commit->object.flags |= TREECHANGE;
 566}
 567
 568static void add_parents_to_list(struct commit *commit, struct commit_list **list)
 569{
 570        struct commit_list *parent = commit->parents;
 571
 572        /*
 573         * If the commit is uninteresting, don't try to
 574         * prune parents - we want the maximal uninteresting
 575         * set.
 576         *
 577         * Normally we haven't parsed the parent
 578         * yet, so we won't have a parent of a parent
 579         * here. However, it may turn out that we've
 580         * reached this commit some other way (where it
 581         * wasn't uninteresting), in which case we need
 582         * to mark its parents recursively too..
 583         */
 584        if (commit->object.flags & UNINTERESTING) {
 585                while (parent) {
 586                        struct commit *p = parent->item;
 587                        parent = parent->next;
 588                        parse_commit(p);
 589                        p->object.flags |= UNINTERESTING;
 590                        if (p->parents)
 591                                mark_parents_uninteresting(p);
 592                        if (p->object.flags & SEEN)
 593                                continue;
 594                        p->object.flags |= SEEN;
 595                        insert_by_date(p, list);
 596                }
 597                return;
 598        }
 599
 600        /*
 601         * Ok, the commit wasn't uninteresting. Try to
 602         * simplify the commit history and find the parent
 603         * that has no differences in the path set if one exists.
 604         */
 605        if (paths)
 606                try_to_simplify_commit(commit);
 607
 608        parent = commit->parents;
 609        while (parent) {
 610                struct commit *p = parent->item;
 611
 612                parent = parent->next;
 613
 614                parse_commit(p);
 615                if (p->object.flags & SEEN)
 616                        continue;
 617                p->object.flags |= SEEN;
 618                insert_by_date(p, list);
 619        }
 620}
 621
 622static struct commit_list *limit_list(struct commit_list *list)
 623{
 624        struct commit_list *newlist = NULL;
 625        struct commit_list **p = &newlist;
 626        while (list) {
 627                struct commit_list *entry = list;
 628                struct commit *commit = list->item;
 629                struct object *obj = &commit->object;
 630
 631                list = list->next;
 632                free(entry);
 633
 634                if (max_age != -1 && (commit->date < max_age))
 635                        obj->flags |= UNINTERESTING;
 636                if (unpacked && has_sha1_pack(obj->sha1))
 637                        obj->flags |= UNINTERESTING;
 638                add_parents_to_list(commit, &list);
 639                if (obj->flags & UNINTERESTING) {
 640                        mark_parents_uninteresting(commit);
 641                        if (everybody_uninteresting(list))
 642                                break;
 643                        continue;
 644                }
 645                if (min_age != -1 && (commit->date > min_age))
 646                        continue;
 647                p = &commit_list_insert(commit, p)->next;
 648        }
 649        if (tree_objects)
 650                mark_edges_uninteresting(newlist);
 651        if (bisect_list)
 652                newlist = find_bisection(newlist);
 653        return newlist;
 654}
 655
 656static void add_pending_object(struct object *obj, const char *name)
 657{
 658        add_object(obj, &pending_objects, name);
 659}
 660
 661static struct commit *get_commit_reference(const char *name, const unsigned char *sha1, unsigned int flags)
 662{
 663        struct object *object;
 664
 665        object = parse_object(sha1);
 666        if (!object)
 667                die("bad object %s", name);
 668
 669        /*
 670         * Tag object? Look what it points to..
 671         */
 672        while (object->type == tag_type) {
 673                struct tag *tag = (struct tag *) object;
 674                object->flags |= flags;
 675                if (tag_objects && !(object->flags & UNINTERESTING))
 676                        add_pending_object(object, tag->tag);
 677                object = parse_object(tag->tagged->sha1);
 678                if (!object)
 679                        die("bad object %s", sha1_to_hex(tag->tagged->sha1));
 680        }
 681
 682        /*
 683         * Commit object? Just return it, we'll do all the complex
 684         * reachability crud.
 685         */
 686        if (object->type == commit_type) {
 687                struct commit *commit = (struct commit *)object;
 688                object->flags |= flags;
 689                if (parse_commit(commit) < 0)
 690                        die("unable to parse commit %s", name);
 691                if (flags & UNINTERESTING)
 692                        mark_parents_uninteresting(commit);
 693                return commit;
 694        }
 695
 696        /*
 697         * Tree object? Either mark it uniniteresting, or add it
 698         * to the list of objects to look at later..
 699         */
 700        if (object->type == tree_type) {
 701                struct tree *tree = (struct tree *)object;
 702                if (!tree_objects)
 703                        return NULL;
 704                if (flags & UNINTERESTING) {
 705                        mark_tree_uninteresting(tree);
 706                        return NULL;
 707                }
 708                add_pending_object(object, "");
 709                return NULL;
 710        }
 711
 712        /*
 713         * Blob object? You know the drill by now..
 714         */
 715        if (object->type == blob_type) {
 716                struct blob *blob = (struct blob *)object;
 717                if (!blob_objects)
 718                        return NULL;
 719                if (flags & UNINTERESTING) {
 720                        mark_blob_uninteresting(blob);
 721                        return NULL;
 722                }
 723                add_pending_object(object, "");
 724                return NULL;
 725        }
 726        die("%s is unknown object", name);
 727}
 728
 729static void handle_one_commit(struct commit *com, struct commit_list **lst)
 730{
 731        if (!com || com->object.flags & SEEN)
 732                return;
 733        com->object.flags |= SEEN;
 734        commit_list_insert(com, lst);
 735}
 736
 737/* for_each_ref() callback does not allow user data -- Yuck. */
 738static struct commit_list **global_lst;
 739
 740static int include_one_commit(const char *path, const unsigned char *sha1)
 741{
 742        struct commit *com = get_commit_reference(path, sha1, 0);
 743        handle_one_commit(com, global_lst);
 744        return 0;
 745}
 746
 747static void handle_all(struct commit_list **lst)
 748{
 749        global_lst = lst;
 750        for_each_ref(include_one_commit);
 751        global_lst = NULL;
 752}
 753
 754int main(int argc, const char **argv)
 755{
 756        const char *prefix = setup_git_directory();
 757        struct commit_list *list = NULL;
 758        int i, limited = 0;
 759
 760        for (i = 1 ; i < argc; i++) {
 761                int flags;
 762                const char *arg = argv[i];
 763                char *dotdot;
 764                struct commit *commit;
 765                unsigned char sha1[20];
 766
 767                /* accept -<digit>, like traditilnal "head" */
 768                if ((*arg == '-') && isdigit(arg[1])) {
 769                        max_count = atoi(arg + 1);
 770                        continue;
 771                }
 772                if (!strcmp(arg, "-n")) {
 773                        if (++i >= argc)
 774                                die("-n requires an argument");
 775                        max_count = atoi(argv[i]);
 776                        continue;
 777                }
 778                if (!strncmp(arg,"-n",2)) {
 779                        max_count = atoi(arg + 2);
 780                        continue;
 781                }
 782                if (!strncmp(arg, "--max-count=", 12)) {
 783                        max_count = atoi(arg + 12);
 784                        continue;
 785                }
 786                if (!strncmp(arg, "--max-age=", 10)) {
 787                        max_age = atoi(arg + 10);
 788                        limited = 1;
 789                        continue;
 790                }
 791                if (!strncmp(arg, "--min-age=", 10)) {
 792                        min_age = atoi(arg + 10);
 793                        limited = 1;
 794                        continue;
 795                }
 796                if (!strcmp(arg, "--header")) {
 797                        verbose_header = 1;
 798                        continue;
 799                }
 800                if (!strcmp(arg, "--no-abbrev")) {
 801                        abbrev = 0;
 802                        continue;
 803                }
 804                if (!strncmp(arg, "--abbrev=", 9)) {
 805                        abbrev = strtoul(arg + 9, NULL, 10);
 806                        if (abbrev && abbrev < MINIMUM_ABBREV)
 807                                abbrev = MINIMUM_ABBREV;
 808                        else if (40 < abbrev)
 809                                abbrev = 40;
 810                        continue;
 811                }
 812                if (!strncmp(arg, "--pretty", 8)) {
 813                        commit_format = get_commit_format(arg+8);
 814                        verbose_header = 1;
 815                        hdr_termination = '\n';
 816                        if (commit_format == CMIT_FMT_ONELINE)
 817                                commit_prefix = "";
 818                        else
 819                                commit_prefix = "commit ";
 820                        continue;
 821                }
 822                if (!strncmp(arg, "--no-merges", 11)) {
 823                        no_merges = 1;
 824                        continue;
 825                }
 826                if (!strcmp(arg, "--parents")) {
 827                        show_parents = 1;
 828                        continue;
 829                }
 830                if (!strcmp(arg, "--bisect")) {
 831                        bisect_list = 1;
 832                        continue;
 833                }
 834                if (!strcmp(arg, "--all")) {
 835                        handle_all(&list);
 836                        continue;
 837                }
 838                if (!strcmp(arg, "--objects")) {
 839                        tag_objects = 1;
 840                        tree_objects = 1;
 841                        blob_objects = 1;
 842                        continue;
 843                }
 844                if (!strcmp(arg, "--unpacked")) {
 845                        unpacked = 1;
 846                        limited = 1;
 847                        continue;
 848                }
 849                if (!strcmp(arg, "--merge-order")) {
 850                        merge_order = 1;
 851                        continue;
 852                }
 853                if (!strcmp(arg, "--show-breaks")) {
 854                        show_breaks = 1;
 855                        continue;
 856                }
 857                if (!strcmp(arg, "--topo-order")) {
 858                        topo_order = 1;
 859                        limited = 1;
 860                        continue;
 861                }
 862                if (!strcmp(arg, "--dense")) {
 863                        dense = 1;
 864                        continue;
 865                }
 866                if (!strcmp(arg, "--sparse")) {
 867                        dense = 0;
 868                        continue;
 869                }
 870                if (!strcmp(arg, "--remove-empty")) {
 871                        remove_empty_trees = 1;
 872                        continue;
 873                }
 874                if (!strcmp(arg, "--")) {
 875                        i++;
 876                        break;
 877                }
 878
 879                if (show_breaks && !merge_order)
 880                        usage(rev_list_usage);
 881
 882                flags = 0;
 883                dotdot = strstr(arg, "..");
 884                if (dotdot) {
 885                        unsigned char from_sha1[20];
 886                        char *next = dotdot + 2;
 887                        *dotdot = 0;
 888                        if (!*next)
 889                                next = "HEAD";
 890                        if (!get_sha1(arg, from_sha1) && !get_sha1(next, sha1)) {
 891                                struct commit *exclude;
 892                                struct commit *include;
 893                                
 894                                exclude = get_commit_reference(arg, from_sha1, UNINTERESTING);
 895                                include = get_commit_reference(next, sha1, 0);
 896                                if (!exclude || !include)
 897                                        die("Invalid revision range %s..%s", arg, next);
 898                                limited = 1;
 899                                handle_one_commit(exclude, &list);
 900                                handle_one_commit(include, &list);
 901                                continue;
 902                        }
 903                        *dotdot = '.';
 904                }
 905                if (*arg == '^') {
 906                        flags = UNINTERESTING;
 907                        arg++;
 908                        limited = 1;
 909                }
 910                if (get_sha1(arg, sha1) < 0) {
 911                        struct stat st;
 912                        if (lstat(arg, &st) < 0)
 913                                die("'%s': %s", arg, strerror(errno));
 914                        break;
 915                }
 916                commit = get_commit_reference(arg, sha1, flags);
 917                handle_one_commit(commit, &list);
 918        }
 919
 920        if (!list &&
 921            (!(tag_objects||tree_objects||blob_objects) && !pending_objects))
 922                usage(rev_list_usage);
 923
 924        paths = get_pathspec(prefix, argv + i);
 925        if (paths) {
 926                limited = 1;
 927                diff_tree_setup_paths(paths);
 928        }
 929
 930        save_commit_buffer = verbose_header;
 931        track_object_refs = 0;
 932
 933        if (!merge_order) {             
 934                sort_by_date(&list);
 935                if (list && !limited && max_count == 1 &&
 936                    !tag_objects && !tree_objects && !blob_objects) {
 937                        show_commit(list->item);
 938                        return 0;
 939                }
 940                if (limited)
 941                        list = limit_list(list);
 942                if (topo_order)
 943                        sort_in_topological_order(&list);
 944                show_commit_list(list);
 945        } else {
 946#ifndef NO_OPENSSL
 947                if (sort_list_in_merge_order(list, &process_commit)) {
 948                        die("merge order sort failed\n");
 949                }
 950#else
 951                die("merge order sort unsupported, OpenSSL not linked");
 952#endif
 953        }
 954
 955        return 0;
 956}