From: Junio C Hamano Date: Thu, 3 Apr 2014 19:38:11 +0000 (-0700) Subject: Merge branch 'nd/log-show-linear-break' X-Git-Tag: v2.0.0-rc0~29 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/b407d40933f9c37af16ca3dc275e615ab4fdd8c5?hp=-c Merge branch 'nd/log-show-linear-break' Attempts to show where a single-strand-of-pearls break in "git log" output. * nd/log-show-linear-break: log: add --show-linear-break to help see non-linear history object.h: centralize object flag allocation --- b407d40933f9c37af16ca3dc275e615ab4fdd8c5 diff --combined Documentation/rev-list-options.txt index 9a3da3646e,1261ac0865..b8139610b9 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@@ -257,14 -257,6 +257,14 @@@ See also linkgit:git-reflog[1] Output excluded boundary commits. Boundary commits are prefixed with `-`. +ifdef::git-rev-list[] +--use-bitmap-index:: + + Try to speed up the traversal using the pack bitmap index (if + one is available). Note that when traversing with `--objects`, + trees and blobs will not have their associated path printed. +endif::git-rev-list[] + -- History Simplification @@@ -758,6 -750,13 +758,13 @@@ This enables parent rewriting, see 'His This implies the `--topo-order` option by default, but the `--date-order` option may also be specified. + --show-linear-break[=]:: + When --graph is not used, all history branches are flattened + which can make it hard to see that the two consecutive commits + do not belong to a linear branch. This option puts a barrier + in between them in that case. If `` is specified, it + is the string that will be shown instead of the default one. + ifdef::git-rev-list[] --count:: Print a number stating how many commits would have been diff --combined bisect.c index 8448d27877,48ccbf118f..d6e851d783 --- a/bisect.c +++ b/bisect.c @@@ -21,8 -21,7 +21,7 @@@ static const char *argv_checkout[] = {" static const char *argv_show_branch[] = {"show-branch", NULL, NULL}; static const char *argv_update_ref[] = {"update-ref", "--no-deref", "BISECT_HEAD", NULL, NULL}; - /* bits #0-15 in revision.h */ - + /* Remember to update object flag allocation in object.h */ #define COUNTED (1u<<16) /* @@@ -685,6 -684,7 +684,6 @@@ static void mark_expected_rev(char *bis static int bisect_checkout(char *bisect_rev_hex, int no_checkout) { - int res; mark_expected_rev(bisect_rev_hex); @@@ -695,7 -695,6 +694,7 @@@ die("update-ref --no-deref HEAD failed on %s", bisect_rev_hex); } else { + int res; res = run_command_v_opt(argv_checkout, RUN_GIT_CMD); if (res) exit(res); diff --combined builtin/blame.c index e5b5d71bad,599fb58065..88cb799727 --- a/builtin/blame.c +++ b/builtin/blame.c @@@ -74,7 -74,7 +74,7 @@@ static unsigned blame_copy_score #define BLAME_DEFAULT_MOVE_SCORE 20 #define BLAME_DEFAULT_COPY_SCORE 40 - /* bits #0..7 in revision.h, #8..11 used for merge_bases() in commit.c */ + /* Remember to update object flag allocation in object.h */ #define METAINFO_SHOWN (1u<<12) #define MORE_THAN_ONE_PATH (1u<<13) @@@ -197,6 -197,7 +197,6 @@@ static void drop_origin_blob(struct ori * scoreboard structure, sorted by the target line number. */ struct blame_entry { - struct blame_entry *prev; struct blame_entry *next; /* the first line of this group in the final image; @@@ -255,6 -256,15 +255,6 @@@ struct scoreboard int *lineno; }; -static inline int same_suspect(struct origin *a, struct origin *b) -{ - if (a == b) - return 1; - if (a->commit != b->commit) - return 0; - return !strcmp(a->path, b->path); -} - static void sanity_check_refcnt(struct scoreboard *); /* @@@ -267,11 -277,13 +267,11 @@@ static void coalesce(struct scoreboard struct blame_entry *ent, *next; for (ent = sb->ent; ent && (next = ent->next); ent = next) { - if (same_suspect(ent->suspect, next->suspect) && + if (ent->suspect == next->suspect && ent->guilty == next->guilty && ent->s_lno + ent->num_lines == next->s_lno) { ent->num_lines += next->num_lines; ent->next = next->next; - if (ent->next) - ent->next->prev = ent; origin_decref(next->suspect); free(next); ent->score = 0; @@@ -522,7 -534,7 +522,7 @@@ static void add_blame_entry(struct scor prev = ent; /* prev, if not NULL, is the last one that is below e */ - e->prev = prev; + if (prev) { e->next = prev->next; prev->next = e; @@@ -531,6 -543,8 +531,6 @@@ e->next = sb->ent; sb->ent = e; } - if (e->next) - e->next->prev = e; } /* @@@ -541,12 -555,14 +541,12 @@@ */ static void dup_entry(struct blame_entry *dst, struct blame_entry *src) { - struct blame_entry *p, *n; + struct blame_entry *n; - p = dst->prev; n = dst->next; origin_incref(src->suspect); origin_decref(dst->suspect); memcpy(dst, src, sizeof(*src)); - dst->prev = p; dst->next = n; dst->score = 0; } @@@ -726,7 -742,7 +726,7 @@@ static int find_last_in_target(struct s int last_in_target = -1; for (e = sb->ent; e; e = e->next) { - if (e->guilty || !same_suspect(e->suspect, target)) + if (e->guilty || e->suspect != target) continue; if (last_in_target < e->s_lno + e->num_lines) last_in_target = e->s_lno + e->num_lines; @@@ -746,7 -762,7 +746,7 @@@ static void blame_chunk(struct scoreboa struct blame_entry *e; for (e = sb->ent; e; e = e->next) { - if (e->guilty || !same_suspect(e->suspect, target)) + if (e->guilty || e->suspect != target) continue; if (same <= e->s_lno) continue; @@@ -923,6 -939,7 +923,6 @@@ static void find_copy_in_blob(struct sc mmfile_t *file_p) { const char *cp; - int cnt; mmfile_t file_o; struct handle_split_cb_data d; @@@ -933,7 -950,13 +933,7 @@@ */ cp = nth_line(sb, ent->lno); file_o.ptr = (char *) cp; - cnt = ent->num_lines; - - while (cnt && cp < sb->final_buf + sb->final_buf_size) { - if (*cp++ == '\n') - cnt--; - } - file_o.size = cp - file_o.ptr; + file_o.size = nth_line(sb, ent->lno + ent->num_lines) - cp; /* * file_o is a part of final image we are annotating. @@@ -969,7 -992,7 +969,7 @@@ static int find_move_in_parent(struct s while (made_progress) { made_progress = 0; for (e = sb->ent; e; e = e->next) { - if (e->guilty || !same_suspect(e->suspect, target) || + if (e->guilty || e->suspect != target || ent_score(sb, e) < blame_move_score) continue; find_copy_in_blob(sb, e, parent, split, &file_p); @@@ -1004,14 -1027,14 +1004,14 @@@ static struct blame_list *setup_blame_l for (e = sb->ent, num_ents = 0; e; e = e->next) if (!e->scanned && !e->guilty && - same_suspect(e->suspect, target) && + e->suspect == target && min_score < ent_score(sb, e)) num_ents++; if (num_ents) { blame_list = xcalloc(num_ents, sizeof(struct blame_list)); for (e = sb->ent, i = 0; e; e = e->next) if (!e->scanned && !e->guilty && - same_suspect(e->suspect, target) && + e->suspect == target && min_score < ent_score(sb, e)) blame_list[i++].ent = e; } @@@ -1155,7 -1178,7 +1155,7 @@@ static void pass_whole_blame(struct sco origin->file.ptr = NULL; } for (e = sb->ent; e; e = e->next) { - if (!same_suspect(e->suspect, origin)) + if (e->suspect != origin) continue; origin_incref(porigin); origin_decref(e->suspect); @@@ -1544,7 -1567,7 +1544,7 @@@ static void assign_blame(struct scorebo /* Take responsibility for the remaining entries */ for (ent = sb->ent; ent; ent = ent->next) - if (same_suspect(ent->suspect, suspect)) + if (ent->suspect == suspect) found_guilty_entry(ent); origin_decref(suspect); @@@ -1557,14 -1580,14 +1557,14 @@@ static const char *format_time(unsigne int show_raw_time) { static char time_buf[128]; - const char *time_str; - int time_len; - int tz; if (show_raw_time) { snprintf(time_buf, sizeof(time_buf), "%lu %s", time, tz_str); } else { + const char *time_str; + int time_len; + int tz; tz = atoi(tz_str); time_str = show_date(time, tz, blame_date_mode); time_len = strlen(time_str); @@@ -1749,41 -1772,25 +1749,41 @@@ static int prepare_lines(struct scorebo { const char *buf = sb->final_buf; unsigned long len = sb->final_buf_size; - int num = 0, incomplete = 0, bol = 1; + const char *end = buf + len; + const char *p; + int *lineno; + int num = 0, incomplete = 0; - if (len && buf[len-1] != '\n') - incomplete++; /* incomplete line at the end */ - while (len--) { - if (bol) { - sb->lineno = xrealloc(sb->lineno, - sizeof(int *) * (num + 1)); - sb->lineno[num] = buf - sb->final_buf; - bol = 0; - } - if (*buf++ == '\n') { + for (p = buf;;) { + p = memchr(p, '\n', end - p); + if (p) { + p++; num++; - bol = 1; + continue; } + break; } - sb->lineno = xrealloc(sb->lineno, - sizeof(int *) * (num + incomplete + 1)); - sb->lineno[num + incomplete] = buf - sb->final_buf; + + if (len && end[-1] != '\n') + incomplete++; /* incomplete line at the end */ + + sb->lineno = xmalloc(sizeof(*sb->lineno) * (num + incomplete + 1)); + lineno = sb->lineno; + + *lineno++ = 0; + for (p = buf;;) { + p = memchr(p, '\n', end - p); + if (p) { + p++; + *lineno++ = p - buf; + continue; + } + break; + } + + if (incomplete) + *lineno++ = len; + sb->num_lines = num + incomplete; return sb->num_lines; } @@@ -2495,6 -2502,8 +2495,6 @@@ parse_done ent->suspect = o; ent->s_lno = bottom; ent->next = next; - if (next) - next->prev = ent; origin_incref(o); } origin_decref(o); diff --combined bundle.c index a85e0e4532,85d4a6abe1..1222952075 --- a/bundle.c +++ b/bundle.c @@@ -14,8 -14,12 +14,8 @@@ static const char bundle_signature[] = static void add_to_ref_list(const unsigned char *sha1, const char *name, struct ref_list *list) { - if (list->nr + 1 >= list->alloc) { - list->alloc = alloc_nr(list->nr + 1); - list->list = xrealloc(list->list, - list->alloc * sizeof(list->list[0])); - } - memcpy(list->list[list->nr].sha1, sha1, 20); + ALLOC_GROW(list->list, list->nr + 1, list->alloc); + hashcpy(list->list[list->nr].sha1, sha1); list->list[list->nr].name = xstrdup(name); list->nr++; } @@@ -120,6 -124,7 +120,7 @@@ static int list_refs(struct ref_list *r return 0; } + /* Remember to update object flag allocation in object.h */ #define PREREQ_MARK (1u<<16) int verify_bundle(struct bundle_header *header, int verbose) diff --combined commit.c index 0f28902bc3,96278c2fa5..f4793316a2 --- a/commit.c +++ b/commit.c @@@ -10,7 -10,6 +10,7 @@@ #include "mergesort.h" #include "commit-slab.h" #include "prio-queue.h" +#include "sha1-lookup.h" static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **); @@@ -115,16 -114,23 +115,16 @@@ static unsigned long parse_commit_date( static struct commit_graft **commit_graft; static int commit_graft_alloc, commit_graft_nr; +static const unsigned char *commit_graft_sha1_access(size_t index, void *table) +{ + struct commit_graft **commit_graft_table = table; + return commit_graft_table[index]->sha1; +} + static int commit_graft_pos(const unsigned char *sha1) { - int lo, hi; - lo = 0; - hi = commit_graft_nr; - while (lo < hi) { - int mi = (lo + hi) / 2; - struct commit_graft *graft = commit_graft[mi]; - int cmp = hashcmp(sha1, graft->sha1); - if (!cmp) - return mi; - if (cmp < 0) - hi = mi; - else - lo = mi + 1; - } - return -lo - 1; + return sha1_pos(sha1, commit_graft, commit_graft_nr, + commit_graft_sha1_access); } int register_commit_graft(struct commit_graft *graft, int ignore_dups) @@@ -141,8 -147,12 +141,8 @@@ return 1; } pos = -pos - 1; - if (commit_graft_alloc <= ++commit_graft_nr) { - commit_graft_alloc = alloc_nr(commit_graft_alloc); - commit_graft = xrealloc(commit_graft, - sizeof(*commit_graft) * - commit_graft_alloc); - } + ALLOC_GROW(commit_graft, commit_graft_nr + 1, commit_graft_alloc); + commit_graft_nr++; if (pos < commit_graft_nr) memmove(commit_graft + pos + 1, commit_graft + pos, @@@ -538,7 -548,7 +538,7 @@@ define_commit_slab(author_date_slab, un static void record_author_date(struct author_date_slab *author_date, struct commit *commit) { - const char *buf, *line_end; + const char *buf, *line_end, *ident_line; char *buffer = NULL; struct ident_split ident; char *date_end; @@@ -556,14 -566,14 +556,14 @@@ buf; buf = line_end + 1) { line_end = strchrnul(buf, '\n'); - if (!starts_with(buf, "author ")) { + ident_line = skip_prefix(buf, "author "); + if (!ident_line) { if (!line_end[0] || line_end[1] == '\n') return; /* end of header */ continue; } if (split_ident_line(&ident, - buf + strlen("author "), - line_end - (buf + strlen("author "))) || + ident_line, line_end - ident_line) || !ident.date_begin || !ident.date_end) goto fail_exit; /* malformed "author" line */ break; @@@ -721,7 -731,7 +721,7 @@@ void sort_in_topological_order(struct c /* merge-base stuff */ - /* bits #0..15 in revision.h */ + /* Remember to update object flag allocation in object.h */ #define PARENT1 (1u<<16) #define PARENT2 (1u<<17) #define STALE (1u<<18) @@@ -1183,8 -1193,10 +1183,8 @@@ static void parse_gpg_output(struct sig for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) { const char *found, *next; - if (starts_with(buf, sigcheck_gpg_status[i].check + 1)) { - /* At the very beginning of the buffer */ - found = buf + strlen(sigcheck_gpg_status[i].check + 1); - } else { + found = skip_prefix(buf, sigcheck_gpg_status[i].check + 1); + if (!found) { found = strstr(buf, sigcheck_gpg_status[i].check); if (!found) continue; diff --combined fetch-pack.c index 90d47da8a9,a7388bee9f..eeee2bb7e0 --- a/fetch-pack.c +++ b/fetch-pack.c @@@ -26,6 -26,7 +26,7 @@@ static int agent_supported static struct lock_file shallow_lock; static const char *alternate_shallow_file; + /* Remember to update object flag allocation in object.h */ #define COMPLETE (1U << 0) #define COMMON (1U << 1) #define COMMON_REF (1U << 2) @@@ -439,8 -440,7 +440,8 @@@ done } strbuf_release(&req_buf); - consume_shallow_list(args, fd[0]); + if (!got_ready || !no_done) + consume_shallow_list(args, fd[0]); while (flushes || multi_ack) { int ack = get_ack(fd[0], result_sha1); if (ack) { @@@ -507,7 -507,7 +508,7 @@@ static void filter_refs(struct fetch_pa next = ref->next; if (!memcmp(ref->name, "refs/", 5) && - check_refname_format(ref->name + 5, 0)) + check_refname_format(ref->name, 0)) ; /* trash */ else { while (i < nr_sought) { @@@ -948,6 -948,17 +949,6 @@@ static void update_shallow(struct fetch if (!si->shallow || !si->shallow->nr) return; - if (alternate_shallow_file) { - /* - * The temporary shallow file is only useful for - * index-pack and unpack-objects because it may - * contain more roots than we want. Delete it. - */ - if (*alternate_shallow_file) - unlink(alternate_shallow_file); - free((char *)alternate_shallow_file); - } - if (args->cloning) { /* * remote is shallow, but this is a clone, there are diff --combined log-tree.c index 5ce217d5eb,17862f6cfb..cf2f86c866 --- a/log-tree.c +++ b/log-tree.c @@@ -100,7 -100,7 +100,7 @@@ static int add_ref_decoration(const cha if (starts_with(refname, "refs/replace/")) { unsigned char original_sha1[20]; - if (!read_replace_refs) + if (!check_replace_refs) return 0; if (get_sha1_hex(refname + 13, original_sha1)) { warning("invalid replace ref %s", refname); @@@ -805,12 -805,16 +805,16 @@@ int log_tree_commit(struct rev_info *op if (opt->line_level_traverse) return line_log_print(opt, commit); + if (opt->track_linear && !opt->linear && !opt->reverse_output_stage) + printf("\n%s\n", opt->break_bar); shown = log_tree_diff(opt, commit, &log); if (!shown && opt->loginfo && opt->always_show_header) { log.parent = NULL; show_log(opt); shown = 1; } + if (opt->track_linear && !opt->linear && opt->reverse_output_stage) + printf("\n%s\n", opt->break_bar); opt->loginfo = NULL; maybe_flush_or_die(stdout, "stdout"); return shown; diff --combined object.h index 732bf4d7e7,ce011428ff..6e12f2c7f4 --- a/object.h +++ b/object.h @@@ -26,6 -26,19 +26,19 @@@ struct object_array #define OBJECT_ARRAY_INIT { 0, 0, NULL } #define TYPE_BITS 3 + /* + * object flag allocation: + * revision.h: 0---------10 26 + * fetch-pack.c: 0---4 + * walker.c: 0-2 + * upload-pack.c: 11----------------19 + * builtin/blame.c: 12-13 + * bisect.c: 16 + * bundle.c: 16 + * http-push.c: 16-----19 + * commit.c: 16-----19 + * sha1_name.c: 20 + */ #define FLAG_BITS 27 /* @@@ -42,14 -55,7 +55,14 @@@ struct object extern const char *typename(unsigned int type); extern int type_from_string(const char *str); +/* + * Return the current number of buckets in the object hashmap. + */ extern unsigned int get_max_object_index(void); + +/* + * Return the object from the specified bucket in the object hashmap. + */ extern struct object *get_indexed_object(unsigned int); /* diff --combined revision.c index 85085501f6,05b76c7966..794a8835c0 --- 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); } @@@ -774,10 -779,6 +774,10 @@@ static int add_parents_to_list(struct r return 0; commit->object.flags |= ADDED; + if (revs->include_check && + !revs->include_check(commit, revs->include_check_data)) + return 0; + /* * If the commit is uninteresting, don't try to * prune parents - we want the maximal uninteresting @@@ -1186,7 -1187,7 +1186,7 @@@ int ref_excluded(struct string_list *re if (!ref_excludes) return 0; for_each_string_list_item(item, ref_excludes) { - if (!fnmatch(item->string, path, 0)) + if (!wildmatch(item->string, path, 0, NULL)) return 1; } return 0; @@@ -1395,7 -1396,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; @@@ -1575,10 -1576,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 -1597,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) @@@ -1837,6 -1832,14 +1837,14 @@@ static int handle_revision_opt(struct r revs->notes_opt.use_default_notes = 1; } else if (!strcmp(arg, "--show-signature")) { revs->show_signature = 1; + } 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; @@@ -1960,6 -1963,8 +1968,8 @@@ unkv[(*unkc)++] = arg; return opts; } + if (revs->graph && revs->track_linear) + die("--show-linear-break and --graph are incompatible"); return 1; } @@@ -2902,6 -2907,27 +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) @@@ -2941,6 -2967,8 +2972,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); @@@ -3107,14 -3135,23 +3140,23 @@@ struct commit *get_revision(struct rev_ 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 1eb94c1548,b8f4bc9a76..d9907dd460 --- a/revision.h +++ b/revision.h @@@ -7,6 -7,7 +7,7 @@@ #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) @@@ -18,7 -19,8 +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 @@@ -137,6 -139,10 +139,10 @@@ struct rev_info 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; @@@ -172,8 -178,6 +178,8 @@@ unsigned long min_age; int min_parents; int max_parents; + int (*include_check)(struct commit *, void *); + void *include_check_data; /* diff info for patches and for paths limiting */ struct diff_options diffopt; @@@ -197,6 -201,9 +203,9 @@@ /* 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); diff --combined sha1_name.c index 6fca8692d2,23bb821d25..2b6322fad0 --- a/sha1_name.c +++ b/sha1_name.c @@@ -430,7 -430,7 +430,7 @@@ static inline int upstream_mark(const c } static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags); -static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf); +static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf); static int get_sha1_basic(const char *str, int len, unsigned char *sha1) { @@@ -492,7 -492,7 +492,7 @@@ struct strbuf buf = STRBUF_INIT; int detached; - if (interpret_nth_prior_checkout(str, &buf) > 0) { + if (interpret_nth_prior_checkout(str, len, &buf) > 0) { detached = (buf.len == 40 && !get_sha1_hex(buf.buf, sha1)); strbuf_release(&buf); if (detached) @@@ -819,6 -819,8 +819,8 @@@ static int get_sha1_1(const char *name * For future extension, ':/!' is reserved. If you want to match a message * beginning with a '!', you have to repeat the exclamation mark. */ + + /* Remember to update object flag allocation in object.h */ #define ONELINE_SEEN (1u<<20) static int handle_one_ref(const char *path, @@@ -929,8 -931,7 +931,8 @@@ static int grab_nth_branch_switch(unsig * Parse @{-N} syntax, return the number of characters parsed * if successful; otherwise signal an error with negative value. */ -static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf) +static int interpret_nth_prior_checkout(const char *name, int namelen, + struct strbuf *buf) { long nth; int retval; @@@ -938,11 -939,9 +940,11 @@@ const char *brace; char *num_end; + if (namelen < 4) + return -1; if (name[0] != '@' || name[1] != '{' || name[2] != '-') return -1; - brace = strchr(name, '}'); + brace = memchr(name, '}', namelen); if (!brace) return -1; nth = strtol(name + 3, &num_end, 10); @@@ -1015,7 -1014,7 +1017,7 @@@ static int interpret_empty_at(const cha return -1; /* make sure it's a single @, or @@{.*}, not @foo */ - next = strchr(name + len + 1, '@'); + next = memchr(name + len + 1, '@', namelen - len - 1); if (next && next[1] != '{') return -1; if (!next) @@@ -1049,57 -1048,6 +1051,57 @@@ static int reinterpret(const char *name return ret - used + len; } +static void set_shortened_ref(struct strbuf *buf, const char *ref) +{ + char *s = shorten_unambiguous_ref(ref, 0); + strbuf_reset(buf); + strbuf_addstr(buf, s); + free(s); +} + +static const char *get_upstream_branch(const char *branch_buf, int len) +{ + char *branch = xstrndup(branch_buf, len); + struct branch *upstream = branch_get(*branch ? branch : NULL); + + /* + * Upstream can be NULL only if branch refers to HEAD and HEAD + * points to something different than a branch. + */ + if (!upstream) + die(_("HEAD does not point to a branch")); + if (!upstream->merge || !upstream->merge[0]->dst) { + if (!ref_exists(upstream->refname)) + die(_("No such branch: '%s'"), branch); + if (!upstream->merge) { + die(_("No upstream configured for branch '%s'"), + upstream->name); + } + die( + _("Upstream branch '%s' not stored as a remote-tracking branch"), + upstream->merge[0]->src); + } + free(branch); + + return upstream->merge[0]->dst; +} + +static int interpret_upstream_mark(const char *name, int namelen, + int at, struct strbuf *buf) +{ + int len; + + len = upstream_mark(name + at, namelen - at); + if (!len) + return -1; + + if (memchr(name, ':', at)) + return -1; + + set_shortened_ref(buf, get_upstream_branch(name, at)); + return len + at; +} + /* * This reads short-hand syntax that not only evaluates to a commit * object name, but also can act as if the end user spelled the name @@@ -1123,9 -1071,10 +1125,9 @@@ */ int interpret_branch_name(const char *name, int namelen, struct strbuf *buf) { - char *cp; - struct branch *upstream; - int len = interpret_nth_prior_checkout(name, buf); - int tmp_len; + char *at; + const char *start; + int len = interpret_nth_prior_checkout(name, namelen, buf); if (!namelen) namelen = strlen(name); @@@ -1139,20 -1088,44 +1141,20 @@@ return reinterpret(name, namelen, len, buf); } - cp = strchr(name, '@'); - if (!cp) - return -1; - - len = interpret_empty_at(name, namelen, cp - name, buf); - if (len > 0) - return reinterpret(name, namelen, len, buf); + for (start = name; + (at = memchr(start, '@', namelen - (start - name))); + start = at + 1) { - tmp_len = upstream_mark(cp, namelen - (cp - name)); - if (!tmp_len) - return -1; + len = interpret_empty_at(name, namelen, at - name, buf); + if (len > 0) + return reinterpret(name, namelen, len, buf); - len = cp + tmp_len - name; - cp = xstrndup(name, cp - name); - upstream = branch_get(*cp ? cp : NULL); - /* - * Upstream can be NULL only if cp refers to HEAD and HEAD - * points to something different than a branch. - */ - if (!upstream) - die(_("HEAD does not point to a branch")); - if (!upstream->merge || !upstream->merge[0]->dst) { - if (!ref_exists(upstream->refname)) - die(_("No such branch: '%s'"), cp); - if (!upstream->merge) { - die(_("No upstream configured for branch '%s'"), - upstream->name); - } - die( - _("Upstream branch '%s' not stored as a remote-tracking branch"), - upstream->merge[0]->src); + len = interpret_upstream_mark(name, namelen, at - name, buf); + if (len > 0) + return len; } - free(cp); - cp = shorten_unambiguous_ref(upstream->merge[0]->dst, 0); - strbuf_reset(buf); - strbuf_addstr(buf, cp); - free(cp); - return len; + + return -1; } int strbuf_branchname(struct strbuf *sb, const char *name) diff --combined upload-pack.c index 286a9ed3ea,96013b35ec..01de944a0a --- a/upload-pack.c +++ b/upload-pack.c @@@ -17,7 -17,7 +17,7 @@@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=] "; - /* bits #0..7 in revision.h, #8..10 in commit.c */ + /* Remember to update object flag allocation in object.h */ #define THEY_HAVE (1u << 11) #define OUR_REF (1u << 12) #define WANTED (1u << 13) @@@ -70,14 -70,6 +70,14 @@@ static ssize_t send_client_data(int fd return sz; } +static int write_one_shallow(const struct commit_graft *graft, void *cb_data) +{ + FILE *fp = cb_data; + if (graft->nr_parent == -1) + fprintf(fp, "--shallow %s\n", sha1_to_hex(graft->sha1)); + return 0; +} + static void create_pack_file(void) { struct child_process pack_objects; @@@ -89,10 -81,12 +89,10 @@@ const char *argv[12]; int i, arg = 0; FILE *pipe_fd; - char *shallow_file = NULL; if (shallow_nr) { - shallow_file = setup_temporary_shallow(NULL); argv[arg++] = "--shallow-file"; - argv[arg++] = shallow_file; + argv[arg++] = ""; } argv[arg++] = "pack-objects"; argv[arg++] = "--revs"; @@@ -120,9 -114,6 +120,9 @@@ pipe_fd = xfdopen(pack_objects.in, "w"); + if (shallow_nr) + for_each_commit_graft(write_one_shallow, pipe_fd); + for (i = 0; i < want_obj.nr; i++) fprintf(pipe_fd, "%s\n", sha1_to_hex(want_obj.objects[i].item->sha1)); @@@ -251,6 -242,11 +251,6 @@@ error("git upload-pack: git-pack-objects died with error."); goto fail; } - if (shallow_file) { - if (*shallow_file) - unlink(shallow_file); - free(shallow_file); - } /* flush the data */ if (0 <= buffered) { @@@ -800,7 -796,7 +800,7 @@@ int main(int argc, char **argv packet_trace_identity("upload-pack"); git_extract_argv0_path(argv[0]); - read_replace_refs = 0; + check_replace_refs = 0; for (i = 1; i < argc; i++) { char *arg = argv[i];