builtin / rev-list.con commit blob: add repository argument to lookup_blob (da14a7f)
   1#include "cache.h"
   2#include "config.h"
   3#include "commit.h"
   4#include "diff.h"
   5#include "revision.h"
   6#include "list-objects.h"
   7#include "list-objects-filter.h"
   8#include "list-objects-filter-options.h"
   9#include "object-store.h"
  10#include "pack.h"
  11#include "pack-bitmap.h"
  12#include "builtin.h"
  13#include "log-tree.h"
  14#include "graph.h"
  15#include "bisect.h"
  16#include "progress.h"
  17#include "reflog-walk.h"
  18#include "oidset.h"
  19#include "packfile.h"
  20
  21static const char rev_list_usage[] =
  22"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
  23"  limiting output:\n"
  24"    --max-count=<n>\n"
  25"    --max-age=<epoch>\n"
  26"    --min-age=<epoch>\n"
  27"    --sparse\n"
  28"    --no-merges\n"
  29"    --min-parents=<n>\n"
  30"    --no-min-parents\n"
  31"    --max-parents=<n>\n"
  32"    --no-max-parents\n"
  33"    --remove-empty\n"
  34"    --all\n"
  35"    --branches\n"
  36"    --tags\n"
  37"    --remotes\n"
  38"    --stdin\n"
  39"    --quiet\n"
  40"  ordering output:\n"
  41"    --topo-order\n"
  42"    --date-order\n"
  43"    --reverse\n"
  44"  formatting output:\n"
  45"    --parents\n"
  46"    --children\n"
  47"    --objects | --objects-edge\n"
  48"    --unpacked\n"
  49"    --header | --pretty\n"
  50"    --abbrev=<n> | --no-abbrev\n"
  51"    --abbrev-commit\n"
  52"    --left-right\n"
  53"    --count\n"
  54"  special purpose:\n"
  55"    --bisect\n"
  56"    --bisect-vars\n"
  57"    --bisect-all"
  58;
  59
  60static struct progress *progress;
  61static unsigned progress_counter;
  62
  63static struct list_objects_filter_options filter_options;
  64static struct oidset omitted_objects;
  65static int arg_print_omitted; /* print objects omitted by filter */
  66
  67static struct oidset missing_objects;
  68enum missing_action {
  69        MA_ERROR = 0,    /* fail if any missing objects are encountered */
  70        MA_ALLOW_ANY,    /* silently allow ALL missing objects */
  71        MA_PRINT,        /* print ALL missing objects in special section */
  72        MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
  73};
  74static enum missing_action arg_missing_action;
  75
  76#define DEFAULT_OIDSET_SIZE     (16*1024)
  77
  78static void finish_commit(struct commit *commit, void *data);
  79static void show_commit(struct commit *commit, void *data)
  80{
  81        struct rev_list_info *info = data;
  82        struct rev_info *revs = info->revs;
  83
  84        display_progress(progress, ++progress_counter);
  85
  86        if (info->flags & REV_LIST_QUIET) {
  87                finish_commit(commit, data);
  88                return;
  89        }
  90
  91        graph_show_commit(revs->graph);
  92
  93        if (revs->count) {
  94                if (commit->object.flags & PATCHSAME)
  95                        revs->count_same++;
  96                else if (commit->object.flags & SYMMETRIC_LEFT)
  97                        revs->count_left++;
  98                else
  99                        revs->count_right++;
 100                finish_commit(commit, data);
 101                return;
 102        }
 103
 104        if (info->show_timestamp)
 105                printf("%"PRItime" ", commit->date);
 106        if (info->header_prefix)
 107                fputs(info->header_prefix, stdout);
 108
 109        if (!revs->graph)
 110                fputs(get_revision_mark(revs, commit), stdout);
 111        if (revs->abbrev_commit && revs->abbrev)
 112                fputs(find_unique_abbrev(&commit->object.oid, revs->abbrev),
 113                      stdout);
 114        else
 115                fputs(oid_to_hex(&commit->object.oid), stdout);
 116        if (revs->print_parents) {
 117                struct commit_list *parents = commit->parents;
 118                while (parents) {
 119                        printf(" %s", oid_to_hex(&parents->item->object.oid));
 120                        parents = parents->next;
 121                }
 122        }
 123        if (revs->children.name) {
 124                struct commit_list *children;
 125
 126                children = lookup_decoration(&revs->children, &commit->object);
 127                while (children) {
 128                        printf(" %s", oid_to_hex(&children->item->object.oid));
 129                        children = children->next;
 130                }
 131        }
 132        show_decorations(revs, commit);
 133        if (revs->commit_format == CMIT_FMT_ONELINE)
 134                putchar(' ');
 135        else
 136                putchar('\n');
 137
 138        if (revs->verbose_header) {
 139                struct strbuf buf = STRBUF_INIT;
 140                struct pretty_print_context ctx = {0};
 141                ctx.abbrev = revs->abbrev;
 142                ctx.date_mode = revs->date_mode;
 143                ctx.date_mode_explicit = revs->date_mode_explicit;
 144                ctx.fmt = revs->commit_format;
 145                ctx.output_encoding = get_log_output_encoding();
 146                ctx.color = revs->diffopt.use_color;
 147                pretty_print_commit(&ctx, commit, &buf);
 148                if (buf.len) {
 149                        if (revs->commit_format != CMIT_FMT_ONELINE)
 150                                graph_show_oneline(revs->graph);
 151
 152                        graph_show_commit_msg(revs->graph, stdout, &buf);
 153
 154                        /*
 155                         * Add a newline after the commit message.
 156                         *
 157                         * Usually, this newline produces a blank
 158                         * padding line between entries, in which case
 159                         * we need to add graph padding on this line.
 160                         *
 161                         * However, the commit message may not end in a
 162                         * newline.  In this case the newline simply
 163                         * ends the last line of the commit message,
 164                         * and we don't need any graph output.  (This
 165                         * always happens with CMIT_FMT_ONELINE, and it
 166                         * happens with CMIT_FMT_USERFORMAT when the
 167                         * format doesn't explicitly end in a newline.)
 168                         */
 169                        if (buf.len && buf.buf[buf.len - 1] == '\n')
 170                                graph_show_padding(revs->graph);
 171                        putchar(info->hdr_termination);
 172                } else {
 173                        /*
 174                         * If the message buffer is empty, just show
 175                         * the rest of the graph output for this
 176                         * commit.
 177                         */
 178                        if (graph_show_remainder(revs->graph))
 179                                putchar('\n');
 180                        if (revs->commit_format == CMIT_FMT_ONELINE)
 181                                putchar('\n');
 182                }
 183                strbuf_release(&buf);
 184        } else {
 185                if (graph_show_remainder(revs->graph))
 186                        putchar('\n');
 187        }
 188        maybe_flush_or_die(stdout, "stdout");
 189        finish_commit(commit, data);
 190}
 191
 192static void finish_commit(struct commit *commit, void *data)
 193{
 194        if (commit->parents) {
 195                free_commit_list(commit->parents);
 196                commit->parents = NULL;
 197        }
 198        free_commit_buffer(commit);
 199}
 200
 201static inline void finish_object__ma(struct object *obj)
 202{
 203        /*
 204         * Whether or not we try to dynamically fetch missing objects
 205         * from the server, we currently DO NOT have the object.  We
 206         * can either print, allow (ignore), or conditionally allow
 207         * (ignore) them.
 208         */
 209        switch (arg_missing_action) {
 210        case MA_ERROR:
 211                die("missing blob object '%s'", oid_to_hex(&obj->oid));
 212                return;
 213
 214        case MA_ALLOW_ANY:
 215                return;
 216
 217        case MA_PRINT:
 218                oidset_insert(&missing_objects, &obj->oid);
 219                return;
 220
 221        case MA_ALLOW_PROMISOR:
 222                if (is_promisor_object(&obj->oid))
 223                        return;
 224                die("unexpected missing blob object '%s'",
 225                    oid_to_hex(&obj->oid));
 226                return;
 227
 228        default:
 229                BUG("unhandled missing_action");
 230                return;
 231        }
 232}
 233
 234static int finish_object(struct object *obj, const char *name, void *cb_data)
 235{
 236        struct rev_list_info *info = cb_data;
 237        if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid)) {
 238                finish_object__ma(obj);
 239                return 1;
 240        }
 241        if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
 242                parse_object(the_repository, &obj->oid);
 243        return 0;
 244}
 245
 246static void show_object(struct object *obj, const char *name, void *cb_data)
 247{
 248        struct rev_list_info *info = cb_data;
 249        if (finish_object(obj, name, cb_data))
 250                return;
 251        display_progress(progress, ++progress_counter);
 252        if (info->flags & REV_LIST_QUIET)
 253                return;
 254        show_object_with_name(stdout, obj, name);
 255}
 256
 257static void show_edge(struct commit *commit)
 258{
 259        printf("-%s\n", oid_to_hex(&commit->object.oid));
 260}
 261
 262static void print_var_str(const char *var, const char *val)
 263{
 264        printf("%s='%s'\n", var, val);
 265}
 266
 267static void print_var_int(const char *var, int val)
 268{
 269        printf("%s=%d\n", var, val);
 270}
 271
 272static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
 273{
 274        int cnt, flags = info->flags;
 275        char hex[GIT_MAX_HEXSZ + 1] = "";
 276        struct commit_list *tried;
 277        struct rev_info *revs = info->revs;
 278
 279        if (!revs->commits)
 280                return 1;
 281
 282        revs->commits = filter_skipped(revs->commits, &tried,
 283                                       flags & BISECT_SHOW_ALL,
 284                                       NULL, NULL);
 285
 286        /*
 287         * revs->commits can reach "reaches" commits among
 288         * "all" commits.  If it is good, then there are
 289         * (all-reaches) commits left to be bisected.
 290         * On the other hand, if it is bad, then the set
 291         * to bisect is "reaches".
 292         * A bisect set of size N has (N-1) commits further
 293         * to test, as we already know one bad one.
 294         */
 295        cnt = all - reaches;
 296        if (cnt < reaches)
 297                cnt = reaches;
 298
 299        if (revs->commits)
 300                oid_to_hex_r(hex, &revs->commits->item->object.oid);
 301
 302        if (flags & BISECT_SHOW_ALL) {
 303                traverse_commit_list(revs, show_commit, show_object, info);
 304                printf("------\n");
 305        }
 306
 307        print_var_str("bisect_rev", hex);
 308        print_var_int("bisect_nr", cnt - 1);
 309        print_var_int("bisect_good", all - reaches - 1);
 310        print_var_int("bisect_bad", reaches - 1);
 311        print_var_int("bisect_all", all);
 312        print_var_int("bisect_steps", estimate_bisect_steps(all));
 313
 314        return 0;
 315}
 316
 317static int show_object_fast(
 318        const struct object_id *oid,
 319        enum object_type type,
 320        int exclude,
 321        uint32_t name_hash,
 322        struct packed_git *found_pack,
 323        off_t found_offset)
 324{
 325        fprintf(stdout, "%s\n", oid_to_hex(oid));
 326        return 1;
 327}
 328
 329static inline int parse_missing_action_value(const char *value)
 330{
 331        if (!strcmp(value, "error")) {
 332                arg_missing_action = MA_ERROR;
 333                return 1;
 334        }
 335
 336        if (!strcmp(value, "allow-any")) {
 337                arg_missing_action = MA_ALLOW_ANY;
 338                fetch_if_missing = 0;
 339                return 1;
 340        }
 341
 342        if (!strcmp(value, "print")) {
 343                arg_missing_action = MA_PRINT;
 344                fetch_if_missing = 0;
 345                return 1;
 346        }
 347
 348        if (!strcmp(value, "allow-promisor")) {
 349                arg_missing_action = MA_ALLOW_PROMISOR;
 350                fetch_if_missing = 0;
 351                return 1;
 352        }
 353
 354        return 0;
 355}
 356
 357int cmd_rev_list(int argc, const char **argv, const char *prefix)
 358{
 359        struct rev_info revs;
 360        struct rev_list_info info;
 361        int i;
 362        int bisect_list = 0;
 363        int bisect_show_vars = 0;
 364        int bisect_find_all = 0;
 365        int use_bitmap_index = 0;
 366        const char *show_progress = NULL;
 367
 368        if (argc == 2 && !strcmp(argv[1], "-h"))
 369                usage(rev_list_usage);
 370
 371        git_config(git_default_config, NULL);
 372        init_revisions(&revs, prefix);
 373        revs.abbrev = DEFAULT_ABBREV;
 374        revs.commit_format = CMIT_FMT_UNSPECIFIED;
 375
 376        /*
 377         * Scan the argument list before invoking setup_revisions(), so that we
 378         * know if fetch_if_missing needs to be set to 0.
 379         *
 380         * "--exclude-promisor-objects" acts as a pre-filter on missing objects
 381         * by not crossing the boundary from realized objects to promisor
 382         * objects.
 383         *
 384         * Let "--missing" to conditionally set fetch_if_missing.
 385         */
 386        for (i = 1; i < argc; i++) {
 387                const char *arg = argv[i];
 388                if (!strcmp(arg, "--exclude-promisor-objects")) {
 389                        fetch_if_missing = 0;
 390                        revs.exclude_promisor_objects = 1;
 391                        break;
 392                }
 393        }
 394        for (i = 1; i < argc; i++) {
 395                const char *arg = argv[i];
 396                if (skip_prefix(arg, "--missing=", &arg)) {
 397                        if (revs.exclude_promisor_objects)
 398                                die(_("cannot combine --exclude-promisor-objects and --missing"));
 399                        if (parse_missing_action_value(arg))
 400                                break;
 401                }
 402        }
 403
 404        argc = setup_revisions(argc, argv, &revs, NULL);
 405
 406        memset(&info, 0, sizeof(info));
 407        info.revs = &revs;
 408        if (revs.bisect)
 409                bisect_list = 1;
 410
 411        if (revs.diffopt.flags.quick)
 412                info.flags |= REV_LIST_QUIET;
 413        for (i = 1 ; i < argc; i++) {
 414                const char *arg = argv[i];
 415
 416                if (!strcmp(arg, "--header")) {
 417                        revs.verbose_header = 1;
 418                        continue;
 419                }
 420                if (!strcmp(arg, "--timestamp")) {
 421                        info.show_timestamp = 1;
 422                        continue;
 423                }
 424                if (!strcmp(arg, "--bisect")) {
 425                        bisect_list = 1;
 426                        continue;
 427                }
 428                if (!strcmp(arg, "--bisect-all")) {
 429                        bisect_list = 1;
 430                        bisect_find_all = 1;
 431                        info.flags |= BISECT_SHOW_ALL;
 432                        revs.show_decorations = 1;
 433                        continue;
 434                }
 435                if (!strcmp(arg, "--bisect-vars")) {
 436                        bisect_list = 1;
 437                        bisect_show_vars = 1;
 438                        continue;
 439                }
 440                if (!strcmp(arg, "--use-bitmap-index")) {
 441                        use_bitmap_index = 1;
 442                        continue;
 443                }
 444                if (!strcmp(arg, "--test-bitmap")) {
 445                        test_bitmap_walk(&revs);
 446                        return 0;
 447                }
 448                if (skip_prefix(arg, "--progress=", &arg)) {
 449                        show_progress = arg;
 450                        continue;
 451                }
 452
 453                if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
 454                        parse_list_objects_filter(&filter_options, arg);
 455                        if (filter_options.choice && !revs.blob_objects)
 456                                die(_("object filtering requires --objects"));
 457                        if (filter_options.choice == LOFC_SPARSE_OID &&
 458                            !filter_options.sparse_oid_value)
 459                                die(_("invalid sparse value '%s'"),
 460                                    filter_options.filter_spec);
 461                        continue;
 462                }
 463                if (!strcmp(arg, ("--no-" CL_ARG__FILTER))) {
 464                        list_objects_filter_set_no_filter(&filter_options);
 465                        continue;
 466                }
 467                if (!strcmp(arg, "--filter-print-omitted")) {
 468                        arg_print_omitted = 1;
 469                        continue;
 470                }
 471
 472                if (!strcmp(arg, "--exclude-promisor-objects"))
 473                        continue; /* already handled above */
 474                if (skip_prefix(arg, "--missing=", &arg))
 475                        continue; /* already handled above */
 476
 477                usage(rev_list_usage);
 478
 479        }
 480        if (revs.commit_format != CMIT_FMT_UNSPECIFIED) {
 481                /* The command line has a --pretty  */
 482                info.hdr_termination = '\n';
 483                if (revs.commit_format == CMIT_FMT_ONELINE)
 484                        info.header_prefix = "";
 485                else
 486                        info.header_prefix = "commit ";
 487        }
 488        else if (revs.verbose_header)
 489                /* Only --header was specified */
 490                revs.commit_format = CMIT_FMT_RAW;
 491
 492        if ((!revs.commits && reflog_walk_empty(revs.reflog_info) &&
 493             (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
 494              !revs.pending.nr) &&
 495             !revs.rev_input_given) ||
 496            revs.diff)
 497                usage(rev_list_usage);
 498
 499        if (revs.show_notes)
 500                die(_("rev-list does not support display of notes"));
 501
 502        if (filter_options.choice && use_bitmap_index)
 503                die(_("cannot combine --use-bitmap-index with object filtering"));
 504
 505        save_commit_buffer = (revs.verbose_header ||
 506                              revs.grep_filter.pattern_list ||
 507                              revs.grep_filter.header_list);
 508        if (bisect_list)
 509                revs.limited = 1;
 510
 511        if (show_progress)
 512                progress = start_delayed_progress(show_progress, 0);
 513
 514        if (use_bitmap_index && !revs.prune) {
 515                if (revs.count && !revs.left_right && !revs.cherry_mark) {
 516                        uint32_t commit_count;
 517                        int max_count = revs.max_count;
 518                        if (!prepare_bitmap_walk(&revs)) {
 519                                count_bitmap_commit_list(&commit_count, NULL, NULL, NULL);
 520                                if (max_count >= 0 && max_count < commit_count)
 521                                        commit_count = max_count;
 522                                printf("%d\n", commit_count);
 523                                return 0;
 524                        }
 525                } else if (revs.max_count < 0 &&
 526                           revs.tag_objects && revs.tree_objects && revs.blob_objects) {
 527                        if (!prepare_bitmap_walk(&revs)) {
 528                                traverse_bitmap_commit_list(&show_object_fast);
 529                                return 0;
 530                        }
 531                }
 532        }
 533
 534        if (prepare_revision_walk(&revs))
 535                die("revision walk setup failed");
 536        if (revs.tree_objects)
 537                mark_edges_uninteresting(&revs, show_edge);
 538
 539        if (bisect_list) {
 540                int reaches, all;
 541
 542                find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
 543
 544                if (bisect_show_vars)
 545                        return show_bisect_vars(&info, reaches, all);
 546        }
 547
 548        if (arg_print_omitted)
 549                oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
 550        if (arg_missing_action == MA_PRINT)
 551                oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
 552
 553        traverse_commit_list_filtered(
 554                &filter_options, &revs, show_commit, show_object, &info,
 555                (arg_print_omitted ? &omitted_objects : NULL));
 556
 557        if (arg_print_omitted) {
 558                struct oidset_iter iter;
 559                struct object_id *oid;
 560                oidset_iter_init(&omitted_objects, &iter);
 561                while ((oid = oidset_iter_next(&iter)))
 562                        printf("~%s\n", oid_to_hex(oid));
 563                oidset_clear(&omitted_objects);
 564        }
 565        if (arg_missing_action == MA_PRINT) {
 566                struct oidset_iter iter;
 567                struct object_id *oid;
 568                oidset_iter_init(&missing_objects, &iter);
 569                while ((oid = oidset_iter_next(&iter)))
 570                        printf("?%s\n", oid_to_hex(oid));
 571                oidset_clear(&missing_objects);
 572        }
 573
 574        stop_progress(&progress);
 575
 576        if (revs.count) {
 577                if (revs.left_right && revs.cherry_mark)
 578                        printf("%d\t%d\t%d\n", revs.count_left, revs.count_right, revs.count_same);
 579                else if (revs.left_right)
 580                        printf("%d\t%d\n", revs.count_left, revs.count_right);
 581                else if (revs.cherry_mark)
 582                        printf("%d\t%d\n", revs.count_left + revs.count_right, revs.count_same);
 583                else
 584                        printf("%d\n", revs.count_left + revs.count_right);
 585        }
 586
 587        return 0;
 588}