From: Junio C Hamano Date: Thu, 6 Nov 2014 18:52:36 +0000 (-0800) Subject: Merge branch 'tm/line-log-first-parent' X-Git-Tag: v2.2.0-rc1~3 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/64b9326460e066a6ae598ed53f38bec8ab4e577d?ds=inline;hp=-c Merge branch 'tm/line-log-first-parent' "git log --first-parent -L..." used to crash. * tm/line-log-first-parent: line-log: fix crash when --first-parent is used --- 64b9326460e066a6ae598ed53f38bec8ab4e577d diff --combined line-log.c index 038c58a395,fe04c9d109..b7864ad586 --- a/line-log.c +++ b/line-log.c @@@ -23,7 -23,7 +23,7 @@@ static void range_set_grow(struct range /* Either initialization would be fine */ #define RANGE_SET_INIT {0} -static void range_set_init(struct range_set *rs, size_t prealloc) +void range_set_init(struct range_set *rs, size_t prealloc) { rs->alloc = rs->nr = 0; rs->ranges = NULL; @@@ -31,7 -31,7 +31,7 @@@ range_set_grow(rs, prealloc); } -static void range_set_release(struct range_set *rs) +void range_set_release(struct range_set *rs) { free(rs->ranges); rs->alloc = rs->nr = 0; @@@ -56,7 -56,7 +56,7 @@@ static void range_set_move(struct range } /* tack on a _new_ range _at the end_ */ -static void range_set_append_unsafe(struct range_set *rs, long a, long b) +void range_set_append_unsafe(struct range_set *rs, long a, long b) { assert(a <= b); range_set_grow(rs, 1); @@@ -65,7 -65,7 +65,7 @@@ rs->nr++; } -static void range_set_append(struct range_set *rs, long a, long b) +void range_set_append(struct range_set *rs, long a, long b) { assert(rs->nr == 0 || rs->ranges[rs->nr-1].end <= a); range_set_append_unsafe(rs, a, b); @@@ -107,7 -107,7 +107,7 @@@ static void range_set_check_invariants( * In-place pass of sorting and merging the ranges in the range set, * to establish the invariants when we get the ranges from the user */ -static void sort_and_merge_range_set(struct range_set *rs) +void sort_and_merge_range_set(struct range_set *rs) { int i; int o = 0; /* output cursor */ @@@ -291,6 -291,7 +291,6 @@@ static void line_log_data_insert(struc if (p) { range_set_append_unsafe(&p->ranges, begin, end); - sort_and_merge_range_set(&p->ranges); free(path); return; } @@@ -298,6 -299,7 +298,6 @@@ p = xcalloc(1, sizeof(struct line_log_data)); p->path = path; range_set_append(&p->ranges, begin, end); - sort_and_merge_range_set(&p->ranges); if (ip) { p->next = ip->next; ip->next = p; @@@ -533,7 -535,7 +533,7 @@@ static void fill_line_ends(struct diff_ } /* shrink the array to fit the elements */ - ends = xrealloc(ends, cur * sizeof(*ends)); + REALLOC_ARRAY(ends, cur); *lines = cur-1; *line_ends = ends; } @@@ -564,14 -566,12 +564,14 @@@ parse_lines(struct commit *commit, cons struct nth_line_cb cb_data; struct string_list_item *item; struct line_log_data *ranges = NULL; + struct line_log_data *p; for_each_string_list_item(item, args) { const char *name_part, *range_part; char *full_name; struct diff_filespec *spec; long begin = 0, end = 0; + long anchor; name_part = skip_range_arg(item->string); if (!name_part || *name_part != ':' || !name_part[1]) @@@ -590,23 -590,17 +590,23 @@@ cb_data.lines = lines; cb_data.line_ends = ends; + p = search_line_log_data(ranges, full_name, NULL); + if (p && p->ranges.nr) + anchor = p->ranges.ranges[p->ranges.nr - 1].end + 1; + else + anchor = 1; + if (parse_range_arg(range_part, nth_line, &cb_data, - lines, &begin, &end, + lines, anchor, &begin, &end, full_name)) die("malformed -L argument '%s'", range_part); + if (lines < end || ((lines || begin) && lines < begin)) + die("file %s has only %lu lines", name_part, lines); if (begin < 1) begin = 1; if (end < 1) end = lines; begin--; - if (lines < end || lines < begin) - die("file %s has only %ld lines", name_part, lines); line_log_data_insert(&ranges, full_name, begin, end); free_filespec(spec); @@@ -614,9 -608,6 +614,9 @@@ ends = NULL; } + for (p = ranges; p; p = p->next) + sort_and_merge_range_set(&p->ranges); + return ranges; } @@@ -760,12 -751,32 +760,12 @@@ void line_log_init(struct rev_info *rev r = r->next; } paths[count] = NULL; - init_pathspec(&rev->diffopt.pathspec, paths); + parse_pathspec(&rev->diffopt.pathspec, 0, + PATHSPEC_PREFER_FULL, "", paths); free(paths); } } -static void load_tree_desc(struct tree_desc *desc, void **tree, - const unsigned char *sha1) -{ - unsigned long size; - *tree = read_object_with_reference(sha1, tree_type, &size, NULL); - if (!*tree) - die("Unable to read tree (%s)", sha1_to_hex(sha1)); - init_tree_desc(desc, *tree, size); -} - -static int count_parents(struct commit *commit) -{ - struct commit_list *parents = commit->parents; - int count = 0; - while (parents) { - count++; - parents = parents->next; - } - return count; -} - static void move_diff_queue(struct diff_queue_struct *dst, struct diff_queue_struct *src) { @@@ -821,11 -832,18 +821,11 @@@ static void queue_diffs(struct line_log struct diff_queue_struct *queue, struct commit *commit, struct commit *parent) { - void *tree1 = NULL, *tree2 = NULL; - struct tree_desc desc1, desc2; - assert(commit); - load_tree_desc(&desc2, &tree2, commit->tree->object.sha1); - if (parent) - load_tree_desc(&desc1, &tree1, parent->tree->object.sha1); - else - init_tree_desc(&desc1, "", 0); DIFF_QUEUE_CLEAR(&diff_queued_diff); - diff_tree(&desc1, &desc2, "", opt); + diff_tree_sha1(parent ? parent->tree->object.sha1 : NULL, + commit->tree->object.sha1, "", opt); if (opt->detect_rename) { filter_diffs_for_paths(range, 1); if (diff_might_be_rename()) @@@ -833,6 -851,11 +833,6 @@@ filter_diffs_for_paths(range, 0); } move_diff_queue(queue, &diff_queued_diff); - - if (tree1) - free(tree1); - if (tree2) - free(tree2); } static char *get_nth_line(long line, unsigned long *ends, void *data) @@@ -1139,8 -1162,11 +1139,11 @@@ static int process_ranges_merge_commit( struct commit **parents; struct commit_list *p; int i; - int nparents = count_parents(commit); + int nparents = commit_list_count(commit->parents); + if (nparents > 1 && rev->first_parent_only) + nparents = 1; + diffqueues = xmalloc(nparents * sizeof(*diffqueues)); cand = xmalloc(nparents * sizeof(*cand)); parents = xmalloc(nparents * sizeof(*parents)); @@@ -1163,7 -1189,9 +1166,7 @@@ */ add_line_range(rev, parents[i], cand[i]); clear_commit_line_range(rev, commit); - commit->parents = xmalloc(sizeof(struct commit_list)); - commit->parents->item = parents[i]; - commit->parents->next = NULL; + commit_list_append(parents[i], &commit->parents); free(parents); free(cand); free_diffqueues(nparents, diffqueues); diff --combined t/t4211-line-log.sh index 7369d3c517,3be25a3a7f..0901b30982 --- a/t/t4211-line-log.sh +++ b/t/t4211-line-log.sh @@@ -48,7 -48,7 +48,7 @@@ canned_test "-M -L '/long f/,/^}/:b.c' canned_test "-M -L ':f:b.c' parallel-change" parallel-change-f-to-main canned_test "-L 4,12:a.c -L :main:a.c simple" multiple -canned_test "-L 4,18:a.c -L :main:a.c simple" multiple-overlapping +canned_test "-L 4,18:a.c -L ^:main:a.c simple" multiple-overlapping canned_test "-L :main:a.c -L 4,18:a.c simple" multiple-overlapping canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset @@@ -64,34 -64,22 +64,39 @@@ test_bad_opts "-L 1,1000:b.c" "has only test_bad_opts "-L :b.c" "argument.*not of the form" test_bad_opts "-L :foo:b.c" "no match" -# There is a separate bug when an empty -L range is the first -L encountered, -# thus to demonstrate this particular bug, the empty -L range must follow a -# non-empty -L range. -test_expect_success '-L {empty-range} (any -L)' ' +test_expect_success '-L X (X == nlines)' ' + n=$(wc -l