From: Junio C Hamano Date: Tue, 8 Apr 2014 19:00:32 +0000 (-0700) Subject: Merge branch 'jk/pack-bitmap' X-Git-Tag: v2.0.0-rc0~13 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/967f8c918465312cc6cc1bcbcfacafcf95152bd8?ds=inline;hp=-c Merge branch 'jk/pack-bitmap' * jk/pack-bitmap: pack-objects: do not reuse packfiles without --delta-base-offset add `ignore_missing_links` mode to revwalk --- 967f8c918465312cc6cc1bcbcfacafcf95152bd8 diff --combined builtin/pack-objects.c index c1f4310871,c7590cb65a..de36c60ca1 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@@ -708,7 -708,7 +708,7 @@@ static struct object_entry **compute_wr static off_t write_reused_pack(struct sha1file *f) { unsigned char buffer[8192]; - off_t to_write; + off_t to_write, total; int fd; if (!is_pack_valid(reuse_packfile)) @@@ -725,7 -725,7 +725,7 @@@ if (reuse_packfile_offset < 0) reuse_packfile_offset = reuse_packfile->pack_size - 20; - to_write = reuse_packfile_offset - sizeof(struct pack_header); + total = to_write = reuse_packfile_offset - sizeof(struct pack_header); while (to_write) { int read_pack = xread(fd, buffer, sizeof(buffer)); @@@ -738,23 -738,10 +738,23 @@@ sha1write(f, buffer, read_pack); to_write -= read_pack; + + /* + * We don't know the actual number of objects written, + * only how many bytes written, how many bytes total, and + * how many objects total. So we can fake it by pretending all + * objects we are writing are the same size. This gives us a + * smooth progress meter, and at the end it matches the true + * answer. + */ + written = reuse_packfile_objects * + (((double)(total - to_write)) / total); + display_progress(progress_state, written); } close(fd); - written += reuse_packfile_objects; + written = reuse_packfile_objects; + display_progress(progress_state, written); return reuse_packfile_offset - sizeof(struct pack_header); } @@@ -768,7 -755,7 +768,7 @@@ static void write_pack_file(void struct object_entry **write_order; if (progress > pack_to_stdout) - progress_state = start_progress("Writing objects", nr_result); + progress_state = start_progress(_("Writing objects"), nr_result); written_list = xmalloc(to_pack.nr_objects * sizeof(*written_list)); write_order = compute_write_order(); @@@ -782,6 -769,8 +782,6 @@@ f = create_tmp_packfile(&pack_tmp_name); offset = write_pack_header(f, nr_remaining); - if (!offset) - die_errno("unable to write pack header"); if (reuse_packfile) { off_t packfile_size; @@@ -816,7 -805,7 +816,7 @@@ if (!pack_to_stdout) { struct stat st; - char tmpname[PATH_MAX]; + struct strbuf tmpname = STRBUF_INIT; /* * Packs are runtime accessed in their mtime @@@ -836,22 -825,26 +836,22 @@@ utb.modtime = --last_mtime; if (utime(pack_tmp_name, &utb) < 0) warning("failed utime() on %s: %s", - tmpname, strerror(errno)); + pack_tmp_name, strerror(errno)); } - /* Enough space for "-.pack"? */ - if (sizeof(tmpname) <= strlen(base_name) + 50) - die("pack base name '%s' too long", base_name); - snprintf(tmpname, sizeof(tmpname), "%s-", base_name); + strbuf_addf(&tmpname, "%s-", base_name); if (write_bitmap_index) { bitmap_writer_set_checksum(sha1); bitmap_writer_build_type_index(written_list, nr_written); } - finish_tmp_packfile(tmpname, pack_tmp_name, + finish_tmp_packfile(&tmpname, pack_tmp_name, written_list, nr_written, &pack_idx_opts, sha1); if (write_bitmap_index) { - char *end_of_name_prefix = strrchr(tmpname, 0); - sprintf(end_of_name_prefix, "%s.bitmap", sha1_to_hex(sha1)); + strbuf_addf(&tmpname, "%s.bitmap", sha1_to_hex(sha1)); stop_progress(&progress_state); @@@ -860,11 -853,10 +860,11 @@@ bitmap_writer_select_commits(indexed_commits, indexed_commits_nr, -1); bitmap_writer_build(&to_pack); bitmap_writer_finish(written_list, nr_written, - tmpname, write_bitmap_options); + tmpname.buf, write_bitmap_options); write_bitmap_index = 0; } + strbuf_release(&tmpname); free(pack_tmp_name); puts(sha1_to_hex(sha1)); } @@@ -1035,7 -1027,7 +1035,7 @@@ static int add_object_entry(const unsig exclude, name && no_try_delta(name), index_pos, found_pack, found_offset); - display_progress(progress_state, to_pack.nr_objects); + display_progress(progress_state, nr_result); return 1; } @@@ -1051,7 -1043,7 +1051,7 @@@ static int add_object_entry_from_bitmap create_object_entry(sha1, type, name_hash, 0, 0, index_pos, pack, offset); - display_progress(progress_state, to_pack.nr_objects); + display_progress(progress_state, nr_result); return 1; } @@@ -1076,7 -1068,7 +1076,7 @@@ static int pbase_tree_cache_ix_incr(in static struct pbase_tree { struct pbase_tree *next; /* This is a phony "cache" entry; we are not - * going to evict it nor find it through _get() + * going to evict it or find it through _get() * mechanism -- this is for the toplevel node that * would almost always change with any commit. */ @@@ -1233,9 -1225,12 +1233,9 @@@ static int check_pbase_path(unsigned ha if (0 <= pos) return 1; pos = -pos - 1; - if (done_pbase_paths_alloc <= done_pbase_paths_num) { - done_pbase_paths_alloc = alloc_nr(done_pbase_paths_alloc); - done_pbase_paths = xrealloc(done_pbase_paths, - done_pbase_paths_alloc * - sizeof(unsigned)); - } + ALLOC_GROW(done_pbase_paths, + done_pbase_paths_num + 1, + done_pbase_paths_alloc); done_pbase_paths_num++; if (pos < done_pbase_paths_num) memmove(done_pbase_paths + pos + 1, @@@ -2104,7 -2099,7 +2104,7 @@@ static int add_ref_tag(const char *path { unsigned char peeled[20]; - if (!prefixcmp(path, "refs/tags/") && /* is a tag? */ + if (starts_with(path, "refs/tags/") && /* is a tag? */ !peel_ref(path, peeled) && /* peelable? */ packlist_find(&to_pack, peeled, NULL)) /* object packed? */ add_object_entry(sha1, OBJ_TAG, NULL, 0); @@@ -2171,7 -2166,7 +2171,7 @@@ static void prepare_pack(int window, in if (nr_deltas && n > 1) { unsigned nr_done = 0; if (progress) - progress_state = start_progress("Compressing objects", + progress_state = start_progress(_("Compressing objects"), nr_deltas); qsort(delta_list, n, sizeof(*delta_list), type_size_sort); ll_find_deltas(delta_list, n, window+1, depth, &nr_done); @@@ -2439,18 -2434,34 +2439,29 @@@ static void loosen_unused_packed_object } } + /* + * This tracks any options which a reader of the pack might + * not understand, and which would therefore prevent blind reuse + * of what we have on disk. + */ + static int pack_options_allow_reuse(void) + { + return allow_ofs_delta; + } + static int get_object_list_from_bitmap(struct rev_info *revs) { if (prepare_bitmap_walk(revs) < 0) return -1; - if (!reuse_partial_packfile_from_bitmap( + if (pack_options_allow_reuse() && + !reuse_partial_packfile_from_bitmap( &reuse_packfile, &reuse_packfile_objects, &reuse_packfile_offset)) { assert(reuse_packfile_objects); nr_result += reuse_packfile_objects; - - if (progress) { - fprintf(stderr, "Reusing existing pack: %d, done.\n", - reuse_packfile_objects); - fflush(stderr); - } + display_progress(progress_state, nr_result); } traverse_bitmap_commit_list(&add_object_entry_from_bitmap); @@@ -2467,9 -2478,6 +2478,9 @@@ static void get_object_list(int ac, con save_commit_buffer = 0; setup_revisions(ac, av, &revs, NULL); + /* make sure shallows are read */ + is_repository_shallow(); + while (fgets(line, sizeof(line), stdin) != NULL) { int len = strlen(line); if (len && line[len - 1] == '\n') @@@ -2482,13 -2490,6 +2493,13 @@@ write_bitmap_index = 0; continue; } + if (starts_with(line, "--shallow ")) { + unsigned char sha1[20]; + if (get_sha1_hex(line + 10, sha1)) + die("not an SHA-1 '%s'", line + 10); + register_shallow(sha1); + continue; + } die("not a rev '%s'", line); } if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME)) @@@ -2634,7 -2635,7 +2645,7 @@@ int cmd_pack_objects(int argc, const ch OPT_END(), }; - read_replace_refs = 0; + check_replace_refs = 0; reset_pack_idx_option(&pack_idx_opts); git_config(git_pack_config, NULL); @@@ -2709,7 -2710,7 +2720,7 @@@ prepare_packed_git(); if (progress) - progress_state = start_progress("Counting objects", 0); + progress_state = start_progress(_("Counting objects"), 0); if (!use_internal_rev_list) read_object_list_from_stdin(); else { diff --combined list-objects.c index 206816fa9c,b2db6ba0d3..3595ee7a22 --- a/list-objects.c +++ b/list-objects.c @@@ -81,8 -81,11 +81,11 @@@ static void process_tree(struct rev_inf die("bad tree object"); if (obj->flags & (UNINTERESTING | SEEN)) return; - if (parse_tree(tree) < 0) + if (parse_tree(tree) < 0) { + if (revs->ignore_missing_links) + return; die("bad tree object %s", sha1_to_hex(obj->sha1)); + } obj->flags |= SEEN; show(obj, path, name, cb_data); me.up = path; @@@ -162,17 -165,15 +165,17 @@@ void mark_edges_uninteresting(struct re } mark_edge_parents_uninteresting(commit, revs, show_edge); } - for (i = 0; i < revs->cmdline.nr; i++) { - struct object *obj = revs->cmdline.rev[i].item; - struct commit *commit = (struct commit *)obj; - if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING)) - continue; - mark_tree_uninteresting(commit->tree); - if (revs->edge_hint && !(obj->flags & SHOWN)) { - obj->flags |= SHOWN; - show_edge(commit); + if (revs->edge_hint) { + for (i = 0; i < revs->cmdline.nr; i++) { + struct object *obj = revs->cmdline.rev[i].item; + struct commit *commit = (struct commit *)obj; + if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING)) + continue; + mark_tree_uninteresting(commit->tree); + if (!(obj->flags & SHOWN)) { + obj->flags |= SHOWN; + show_edge(commit); + } } } } diff --combined revision.c index 794a8835c0,520b3e7df6..71e2337423 --- a/revision.c +++ b/revision.c @@@ -16,7 -16,6 +16,7 @@@ #include "line-log.h" #include "mailmap.h" #include "commit-slab.h" +#include "dir.h" volatile show_early_output_fn_t show_early_output; @@@ -105,12 -104,17 +105,12 @@@ static void mark_blob_uninteresting(str blob->object.flags |= UNINTERESTING; } -void mark_tree_uninteresting(struct tree *tree) +static void mark_tree_contents_uninteresting(struct tree *tree) { struct tree_desc desc; struct name_entry entry; struct object *obj = &tree->object; - if (!tree) - return; - if (obj->flags & UNINTERESTING) - return; - obj->flags |= UNINTERESTING; if (!has_sha1_file(obj->sha1)) return; if (parse_tree(tree) < 0) @@@ -138,18 -142,6 +138,18 @@@ free_tree_buffer(tree); } +void mark_tree_uninteresting(struct tree *tree) +{ + struct object *obj = &tree->object; + + if (!tree) + return; + if (obj->flags & UNINTERESTING) + return; + obj->flags |= UNINTERESTING; + mark_tree_contents_uninteresting(tree); +} + void mark_parents_uninteresting(struct commit *commit) { struct commit_list *parents = NULL, *l; @@@ -284,7 -276,6 +284,7 @@@ static struct commit *handle_commit(str return NULL; die("bad object %s", sha1_to_hex(tag->tagged->sha1)); } + object->flags |= flags; } /* @@@ -296,6 -287,7 +296,6 @@@ 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; } @@@ -313,7 -305,7 +313,7 @@@ if (!revs->tree_objects) return NULL; if (flags & UNINTERESTING) { - mark_tree_uninteresting(tree); + mark_tree_contents_uninteresting(tree); return NULL; } add_pending_object(revs, object, ""); @@@ -324,10 -316,13 +324,10 @@@ * Blob object? You know the drill by now.. */ if (object->type == OBJ_BLOB) { - struct blob *blob = (struct blob *)object; if (!revs->blob_objects) return NULL; - if (flags & UNINTERESTING) { - mark_blob_uninteresting(blob); + if (flags & UNINTERESTING) return NULL; - } add_pending_object(revs, object, ""); return NULL; } @@@ -497,14 -492,24 +497,14 @@@ static int rev_compare_tree(struct rev_ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit) { int retval; - void *tree; - unsigned long size; - struct tree_desc empty, real; struct tree *t1 = commit->tree; if (!t1) return 0; - tree = read_object_with_reference(t1->object.sha1, tree_type, &size, NULL); - if (!tree) - return 0; - init_tree_desc(&real, tree, size); - init_tree_desc(&empty, "", 0); - tree_difference = REV_TREE_SAME; DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES); - retval = diff_tree(&empty, &real, "", &revs->pruning); - free(tree); + retval = diff_tree_sha1(NULL, t1->object.sha1, "", &revs->pruning); return retval >= 0 && (tree_difference == REV_TREE_SAME); } @@@ -1179,28 -1184,11 +1179,28 @@@ struct all_refs_cb const char *name_for_errormsg; }; +int ref_excluded(struct string_list *ref_excludes, const char *path) +{ + struct string_list_item *item; + + if (!ref_excludes) + return 0; + for_each_string_list_item(item, ref_excludes) { + if (!wildmatch(item->string, path, 0, NULL)) + return 1; + } + return 0; +} + static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data) { struct all_refs_cb *cb = cb_data; - struct object *object = get_reference(cb->all_revs, path, sha1, - cb->all_flags); + struct object *object; + + if (ref_excluded(cb->all_revs->ref_excludes, path)) + return 0; + + object = get_reference(cb->all_revs, path, sha1, cb->all_flags); add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags); add_pending_sha1(cb->all_revs, path, sha1, cb->all_flags); return 0; @@@ -1213,24 -1201,6 +1213,24 @@@ static void init_all_refs_cb(struct all cb->all_flags = flags; } +void clear_ref_exclusion(struct string_list **ref_excludes_p) +{ + if (*ref_excludes_p) { + string_list_clear(*ref_excludes_p, 0); + free(*ref_excludes_p); + } + *ref_excludes_p = NULL; +} + +void add_ref_exclusion(struct string_list **ref_excludes_p, const char *exclude) +{ + if (!*ref_excludes_p) { + *ref_excludes_p = xcalloc(1, sizeof(**ref_excludes_p)); + (*ref_excludes_p)->strdup_strings = 1; + } + string_list_append(*ref_excludes_p, exclude); +} + static void handle_refs(const char *submodule, struct rev_info *revs, unsigned flags, int (*for_each)(const char *, each_ref_fn, void *)) { @@@ -1395,7 -1365,7 +1395,7 @@@ static void prepare_show_merge(struct r const struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; - if (ce_path_match(ce, &revs->prune_data)) { + if (ce_path_match(ce, &revs->prune_data, NULL)) { prune_num++; prune = xrealloc(prune, sizeof(*prune) * prune_num); prune[prune_num-2] = ce->name; @@@ -1406,8 -1376,7 +1406,8 @@@ i++; } free_pathspec(&revs->prune_data); - parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC, 0, "", prune); + parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL, + PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH, "", prune); revs->limited = 1; } @@@ -1454,40 -1423,26 +1454,40 @@@ int handle_revision_arg(const char *arg } if (!get_sha1_committish(this, from_sha1) && !get_sha1_committish(next, sha1)) { - struct commit *a, *b; - struct commit_list *exclude; - - a = lookup_commit_reference(from_sha1); - b = lookup_commit_reference(sha1); - if (!a || !b) { - if (revs->ignore_missing) - return 0; - die(symmetric ? - "Invalid symmetric difference expression %s...%s" : - "Invalid revision range %s..%s", - arg, next); - } + struct object *a_obj, *b_obj; if (!cant_be_filename) { *dotdot = '.'; verify_non_filename(revs->prefix, arg); } - if (symmetric) { + a_obj = parse_object(from_sha1); + b_obj = parse_object(sha1); + if (!a_obj || !b_obj) { + missing: + if (revs->ignore_missing) + return 0; + die(symmetric + ? "Invalid symmetric difference expression %s" + : "Invalid revision range %s", arg); + } + + if (!symmetric) { + /* just A..B */ + a_flags = flags_exclude; + } else { + /* A...B -- find merge bases between the two */ + struct commit *a, *b; + struct commit_list *exclude; + + a = (a_obj->type == OBJ_COMMIT + ? (struct commit *)a_obj + : lookup_commit_reference(a_obj->sha1)); + b = (b_obj->type == OBJ_COMMIT + ? (struct commit *)b_obj + : lookup_commit_reference(b_obj->sha1)); + if (!a || !b) + goto missing; exclude = get_merge_bases(a, b, 1); add_rev_cmdline_list(revs, exclude, REV_CMD_MERGE_BASE, @@@ -1495,18 -1450,17 +1495,18 @@@ add_pending_commit_list(revs, exclude, flags_exclude); free_commit_list(exclude); + a_flags = flags | SYMMETRIC_LEFT; - } else - a_flags = flags_exclude; - a->object.flags |= a_flags; - b->object.flags |= flags; - add_rev_cmdline(revs, &a->object, this, + } + + a_obj->flags |= a_flags; + b_obj->flags |= flags; + add_rev_cmdline(revs, a_obj, this, REV_CMD_LEFT, a_flags); - add_rev_cmdline(revs, &b->object, next, + add_rev_cmdline(revs, b_obj, next, REV_CMD_RIGHT, flags); - add_pending_object(revs, &a->object, this); - add_pending_object(revs, &b->object, next); + add_pending_object(revs, a_obj, this); + add_pending_object(revs, b_obj, next); return 0; } *dotdot = '.'; @@@ -1553,7 -1507,7 +1553,7 @@@ struct cmdline_pathspec static void append_prune_data(struct cmdline_pathspec *prune, const char **av) { while (*av) { - ALLOC_GROW(prune->path, prune->nr+1, prune->alloc); + ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc); prune->path[prune->nr++] = *(av++); } } @@@ -1565,7 -1519,7 +1565,7 @@@ static void read_pathspec_from_stdin(st int len = sb->len; if (len && sb->buf[len - 1] == '\n') sb->buf[--len] = '\0'; - ALLOC_GROW(prune->path, prune->nr+1, prune->alloc); + ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc); prune->path[prune->nr++] = xstrdup(sb->buf); } } @@@ -1575,10 -1529,6 +1575,10 @@@ static void read_revisions_from_stdin(s { struct strbuf sb; int seen_dashdash = 0; + int save_warning; + + save_warning = warn_on_object_refname_ambiguity; + warn_on_object_refname_ambiguity = 0; strbuf_init(&sb, 1000); while (strbuf_getwholeline(&sb, stdin, '\n') != EOF) { @@@ -1600,9 -1550,7 +1600,9 @@@ } if (seen_dashdash) read_pathspec_from_stdin(revs, &sb, prune); + strbuf_release(&sb); + warn_on_object_refname_ambiguity = save_warning; } static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token what) @@@ -1632,9 -1580,9 +1632,9 @@@ static int handle_revision_opt(struct r !strcmp(arg, "--tags") || !strcmp(arg, "--remotes") || !strcmp(arg, "--reflog") || !strcmp(arg, "--not") || !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") || - !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") || - !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") || - !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk=")) + !strcmp(arg, "--bisect") || starts_with(arg, "--glob=") || + starts_with(arg, "--branches=") || starts_with(arg, "--tags=") || + starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk=")) { unkv[(*unkc)++] = arg; return 1; @@@ -1657,7 -1605,7 +1657,7 @@@ revs->max_count = atoi(argv[1]); revs->no_walk = 0; return 2; - } else if (!prefixcmp(arg, "-n")) { + } else if (starts_with(arg, "-n")) { revs->max_count = atoi(arg + 2); revs->no_walk = 0; } else if ((argcount = parse_long_opt("max-age", argv, &optarg))) { @@@ -1717,7 -1665,7 +1717,7 @@@ } else if (!strcmp(arg, "--author-date-order")) { revs->sort_order = REV_SORT_BY_AUTHOR_DATE; revs->topo_order = 1; - } else if (!prefixcmp(arg, "--early-output")) { + } else if (starts_with(arg, "--early-output")) { int count = 100; switch (arg[14]) { case '=': @@@ -1742,13 -1690,13 +1742,13 @@@ revs->min_parents = 2; } else if (!strcmp(arg, "--no-merges")) { revs->max_parents = 1; - } else if (!prefixcmp(arg, "--min-parents=")) { + } else if (starts_with(arg, "--min-parents=")) { revs->min_parents = atoi(arg+14); - } else if (!prefixcmp(arg, "--no-min-parents")) { + } else if (starts_with(arg, "--no-min-parents")) { revs->min_parents = 0; - } else if (!prefixcmp(arg, "--max-parents=")) { + } else if (starts_with(arg, "--max-parents=")) { revs->max_parents = atoi(arg+14); - } else if (!prefixcmp(arg, "--no-max-parents")) { + } else if (starts_with(arg, "--no-max-parents")) { revs->max_parents = -1; } else if (!strcmp(arg, "--boundary")) { revs->boundary = 1; @@@ -1798,7 -1746,7 +1798,7 @@@ revs->verify_objects = 1; } else if (!strcmp(arg, "--unpacked")) { revs->unpacked = 1; - } else if (!prefixcmp(arg, "--unpacked=")) { + } else if (starts_with(arg, "--unpacked=")) { die("--unpacked= no longer supported."); } else if (!strcmp(arg, "-r")) { revs->diff = 1; @@@ -1823,7 -1771,7 +1823,7 @@@ revs->verbose_header = 1; revs->pretty_given = 1; get_commit_format(arg+8, revs); - } else if (!prefixcmp(arg, "--pretty=") || !prefixcmp(arg, "--format=")) { + } else if (starts_with(arg, "--pretty=") || starts_with(arg, "--format=")) { /* * Detached form ("--pretty X" as opposed to "--pretty=X") * not allowed, since the argument is optional. @@@ -1837,20 -1785,12 +1837,20 @@@ revs->notes_opt.use_default_notes = 1; } else if (!strcmp(arg, "--show-signature")) { revs->show_signature = 1; - } else if (!prefixcmp(arg, "--show-notes=") || - !prefixcmp(arg, "--notes=")) { + } else if (!strcmp(arg, "--show-linear-break") || + starts_with(arg, "--show-linear-break=")) { + if (starts_with(arg, "--show-linear-break=")) + revs->break_bar = xstrdup(arg + 20); + else + revs->break_bar = " .........."; + revs->track_linear = 1; + revs->track_first_time = 1; + } else if (starts_with(arg, "--show-notes=") || + starts_with(arg, "--notes=")) { struct strbuf buf = STRBUF_INIT; revs->show_notes = 1; revs->show_notes_given = 1; - if (!prefixcmp(arg, "--show-notes")) { + if (starts_with(arg, "--show-notes")) { if (revs->notes_opt.use_default_notes < 0) revs->notes_opt.use_default_notes = 1; strbuf_addstr(&buf, arg+13); @@@ -1893,7 -1833,7 +1893,7 @@@ revs->abbrev = 0; } else if (!strcmp(arg, "--abbrev")) { revs->abbrev = DEFAULT_ABBREV; - } else if (!prefixcmp(arg, "--abbrev=")) { + } else if (starts_with(arg, "--abbrev=")) { revs->abbrev = strtoul(arg + 9, NULL, 10); if (revs->abbrev < MINIMUM_ABBREV) revs->abbrev = MINIMUM_ABBREV; @@@ -1968,8 -1908,6 +1968,8 @@@ unkv[(*unkc)++] = arg; return opts; } + if (revs->graph && revs->track_linear) + die("--show-linear-break and --graph are incompatible"); return 1; } @@@ -2019,51 -1957,40 +2019,51 @@@ static int handle_revision_pseudo_opt(c if (!strcmp(arg, "--all")) { handle_refs(submodule, revs, *flags, for_each_ref_submodule); handle_refs(submodule, revs, *flags, head_ref_submodule); + clear_ref_exclusion(&revs->ref_excludes); } else if (!strcmp(arg, "--branches")) { handle_refs(submodule, revs, *flags, for_each_branch_ref_submodule); + clear_ref_exclusion(&revs->ref_excludes); } else if (!strcmp(arg, "--bisect")) { handle_refs(submodule, revs, *flags, for_each_bad_bisect_ref); handle_refs(submodule, revs, *flags ^ (UNINTERESTING | BOTTOM), for_each_good_bisect_ref); revs->bisect = 1; } else if (!strcmp(arg, "--tags")) { handle_refs(submodule, revs, *flags, for_each_tag_ref_submodule); + clear_ref_exclusion(&revs->ref_excludes); } else if (!strcmp(arg, "--remotes")) { handle_refs(submodule, revs, *flags, for_each_remote_ref_submodule); + clear_ref_exclusion(&revs->ref_excludes); } else if ((argcount = parse_long_opt("glob", argv, &optarg))) { struct all_refs_cb cb; init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref(handle_one_ref, optarg, &cb); + clear_ref_exclusion(&revs->ref_excludes); + return argcount; + } else if ((argcount = parse_long_opt("exclude", argv, &optarg))) { + add_ref_exclusion(&revs->ref_excludes, optarg); return argcount; - } else if (!prefixcmp(arg, "--branches=")) { + } else if (starts_with(arg, "--branches=")) { struct all_refs_cb cb; init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref_in(handle_one_ref, arg + 11, "refs/heads/", &cb); - } else if (!prefixcmp(arg, "--tags=")) { + clear_ref_exclusion(&revs->ref_excludes); + } else if (starts_with(arg, "--tags=")) { struct all_refs_cb cb; init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref_in(handle_one_ref, arg + 7, "refs/tags/", &cb); - } else if (!prefixcmp(arg, "--remotes=")) { + clear_ref_exclusion(&revs->ref_excludes); + } else if (starts_with(arg, "--remotes=")) { struct all_refs_cb cb; init_all_refs_cb(&cb, revs, *flags); for_each_glob_ref_in(handle_one_ref, arg + 10, "refs/remotes/", &cb); + clear_ref_exclusion(&revs->ref_excludes); } else if (!strcmp(arg, "--reflog")) { handle_reflog(revs, *flags); } else if (!strcmp(arg, "--not")) { *flags ^= UNINTERESTING | BOTTOM; } else if (!strcmp(arg, "--no-walk")) { revs->no_walk = REVISION_WALK_NO_WALK_SORTED; - } else if (!prefixcmp(arg, "--no-walk=")) { + } else if (starts_with(arg, "--no-walk=")) { /* * Detached form ("--no-walk X" as opposed to "--no-walk=X") * not allowed, since the argument is optional. @@@ -2195,7 -2122,7 +2195,7 @@@ int setup_revisions(int argc, const cha * call init_pathspec() to set revs->prune_data here. * } */ - ALLOC_GROW(prune_data.path, prune_data.nr+1, prune_data.alloc); + ALLOC_GROW(prune_data.path, prune_data.nr + 1, prune_data.alloc); prune_data.path[prune_data.nr++] = NULL; parse_pathspec(&revs->prune_data, 0, 0, revs->prefix, prune_data.path); @@@ -2912,27 -2839,6 +2912,27 @@@ enum commit_action simplify_commit(stru return action; } +static void track_linear(struct rev_info *revs, struct commit *commit) +{ + if (revs->track_first_time) { + revs->linear = 1; + revs->track_first_time = 0; + } else { + struct commit_list *p; + for (p = revs->previous_parents; p; p = p->next) + if (p->item == NULL || /* first commit */ + !hashcmp(p->item->object.sha1, commit->object.sha1)) + break; + revs->linear = p != NULL; + } + if (revs->reverse) { + if (revs->linear) + commit->object.flags |= TRACK_LINEAR; + } + free_commit_list(revs->previous_parents); + revs->previous_parents = copy_commit_list(commit->parents); +} + static struct commit *get_revision_1(struct rev_info *revs) { if (!revs->commits) @@@ -2960,9 -2866,11 +2960,11 @@@ if (revs->max_age != -1 && (commit->date < revs->max_age)) continue; - if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) - die("Failed to traverse parents of commit %s", - sha1_to_hex(commit->object.sha1)); + if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) { + if (!revs->ignore_missing_links) + die("Failed to traverse parents of commit %s", + sha1_to_hex(commit->object.sha1)); + } } switch (simplify_commit(revs, commit)) { @@@ -2972,8 -2880,6 +2974,8 @@@ die("Failed to simplify parents of commit %s", sha1_to_hex(commit->object.sha1)); default: + if (revs->track_linear) + track_linear(revs, commit); return commit; } } while (revs->commits); @@@ -3071,7 -2977,7 +3073,7 @@@ static struct commit *get_revision_inte if (revs->max_count) { c = get_revision_1(revs); if (c) { - while (0 < revs->skip_count) { + while (revs->skip_count > 0) { revs->skip_count--; c = get_revision_1(revs); if (!c) @@@ -3086,8 -2992,9 +3088,8 @@@ if (c) c->object.flags |= SHOWN; - if (!revs->boundary) { + if (!revs->boundary) return c; - } if (!c) { /* @@@ -3133,30 -3040,22 +3135,30 @@@ struct commit *get_revision(struct rev_ if (revs->reverse) { reversed = NULL; - while ((c = get_revision_internal(revs))) { + while ((c = get_revision_internal(revs))) commit_list_insert(c, &reversed); - } revs->commits = reversed; revs->reverse = 0; revs->reverse_output_stage = 1; } - if (revs->reverse_output_stage) - return pop_commit(&revs->commits); + if (revs->reverse_output_stage) { + c = pop_commit(&revs->commits); + if (revs->track_linear) + revs->linear = !!(c && c->object.flags & TRACK_LINEAR); + return c; + } c = get_revision_internal(revs); if (c && revs->graph) graph_update(revs->graph, c); - if (!c) + if (!c) { free_saved_parents(revs); + if (revs->previous_parents) { + free_commit_list(revs->previous_parents); + revs->previous_parents = NULL; + } + } return c; } diff --combined revision.h index d9907dd460,4f051d2ea2..a6205307cf --- a/revision.h +++ b/revision.h @@@ -5,9 -5,7 +5,9 @@@ #include "grep.h" #include "notes.h" #include "commit.h" +#include "diff.h" +/* Remember to update object flag allocation in object.h */ #define SEEN (1u<<0) #define UNINTERESTING (1u<<1) #define TREESAME (1u<<2) @@@ -19,8 -17,7 +19,8 @@@ #define SYMMETRIC_LEFT (1u<<8) #define PATCHSAME (1u<<9) #define BOTTOM (1u<<10) -#define ALL_REV_FLAGS ((1u<<11)-1) +#define TRACK_LINEAR (1u<<26) +#define ALL_REV_FLAGS (((1u<<11)-1) | TRACK_LINEAR) #define DECORATE_SHORT_REFS 1 #define DECORATE_FULL_REFS 2 @@@ -63,9 -60,6 +63,9 @@@ struct rev_info /* The end-points specified by the end user */ struct rev_cmdline_info cmdline; + /* excluding from --branches, --refs, etc. expansion */ + struct string_list *ref_excludes; + /* Basic information */ const char *prefix; const char *def; @@@ -75,7 -69,8 +75,8 @@@ enum rev_sort_order sort_order; unsigned int early_output:1, - ignore_missing:1; + ignore_missing:1, + ignore_missing_links:1; /* Traversal flags */ unsigned int dense:1, @@@ -139,10 -134,6 +140,10 @@@ preserve_subject:1; unsigned int disable_stdin:1; unsigned int leak_pending:1; + /* --show-linear-break */ + unsigned int track_linear:1, + track_first_time:1, + linear:1; enum date_mode date_mode; @@@ -203,16 -194,8 +204,16 @@@ /* copies of the parent lists, for --full-diff display */ struct saved_parents *saved_parents_slab; + + struct commit_list *previous_parents; + const char *break_bar; }; +extern int ref_excluded(struct string_list *, const char *path); +void clear_ref_exclusion(struct string_list **); +void add_ref_exclusion(struct string_list **, const char *exclude); + + #define REV_TREE_SAME 0 #define REV_TREE_NEW 1 /* Only new files */ #define REV_TREE_OLD 2 /* Only files removed */