line-log: route -L output through the standard diff pipeline

`git log -L` has always bypassed the standard diff pipeline. `dump_diff_hacky()` in line-log.c hand-rolls its own diff headers and hunk output, which means most diff formatting options are silently ignored. A NEEDSWORK comment has acknowledged this since the feature was introduced: /* * NEEDSWORK: manually building a diff here is not the Right * Thing(tm). log -L should be built into the diff pipeline. */ Remove `dump_diff_hacky()` and its helpers and route -L output through `builtin_diff()` / `fn_out_consume()`, the same path used by `git diff` and `git log -p`. The mechanism is a pair of callback wrappers that sit between `xdi_diff_outf()` and `fn_out_consume()`, filtering xdiff's output to only the tracked line ranges. To ensure xdiff emits all lines within each range as context, the context length is inflated to span the largest range. Wire up the `-L` implies `--patch` default in revision setup rather than forcing it at output time, so `line_log_print()` is just `diffcore_std()` + `diff_flush()` with no format save/restore. Rename detection is a no-op since pairs are already resolved during the history walk in `queue_diffs()`, but running `diffcore_std()` means `-S`/`-G` (pickaxe), `--orderfile`, and `--diff-filter` now work with `-L`, and `diff_resolve_rename_copy()` sets pair statuses correctly without manual assignment. Switch `diff_filepair_dup()` from `xmalloc` to `xcalloc` so that new fields (including `line_ranges`) are zero-initialized by default. As a result, diff formatting options that were previously silently ignored (e.g. --word-diff, --no-prefix, -w, --color-moved) now work with -L, and output gains `index` lines, `new file mode` headers, and funcname context in `@@` headers. This is a user-visible output change: tools that parse -L output may need to handle the additional header lines. The context-length inflation means xdiff may process more output than needed for very wide line ranges, but benchmarks on files up to 7800 lines show no measurable regression. Signed-off-by: Michael Montalbo <mmontalbo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Michael Montalbo committed Mar 17, 2026 at 02:21 UTC 86e986f166d207e1f4b80062c2befb4f94c191c4
34 files changed +512 -213
diff.c
+277 -2
@@ -608,6 +608,52 @@ struct emit_callback {
608 struct strbuf *header;
609 };
610
611 +/*
612 + * State for the line-range callback wrappers that sit between
613 + * xdi_diff_outf() and fn_out_consume(). xdiff produces a normal,
614 + * unfiltered diff; the wrappers intercept each hunk header and line,
615 + * track post-image position, and forward only lines that fall within
616 + * the requested ranges. Contiguous in-range lines are collected into
617 + * range hunks and flushed with a synthetic @@ header so that
618 + * fn_out_consume() sees well-formed unified-diff fragments.
619 + *
620 + * Removal lines ('-') cannot be classified by post-image position, so
621 + * they are buffered in pending_rm until the next '+' or ' ' line
622 + * reveals whether they precede an in-range line (flush into range hunk) or
623 + * an out-of-range line (discard).
624 + */
625 +struct line_range_callback {
626 + xdiff_emit_line_fn orig_line_fn;
627 + void *orig_cb_data;
628 + const struct range_set *ranges; /* 0-based [start, end) */
629 + unsigned int cur_range; /* index into the range_set */
630 +
631 + /* Post/pre-image line counters (1-based, set from hunk headers) */
632 + long lno_post;
633 + long lno_pre;
634 +
635 + /*
636 + * Function name from most recent xdiff hunk header;
637 + * size matches struct func_line.buf in xdiff/xemit.c.
638 + */
639 + char func[80];
640 + long funclen;
641 +
642 + /* Range hunk being accumulated for the current range */
643 + struct strbuf rhunk;
644 + long rhunk_old_begin, rhunk_old_count;
645 + long rhunk_new_begin, rhunk_new_count;
646 + int rhunk_active;
647 + int rhunk_has_changes; /* any '+' or '-' lines? */
648 +
649 + /* Removal lines not yet known to be in-range */
650 + struct strbuf pending_rm;
651 + int pending_rm_count;
652 + long pending_rm_pre_begin; /* pre-image line of first pending */
653 +
654 + int ret; /* latched error from orig_line_fn */
655 +};
656 +
657 static int count_lines(const char *data, int size)
658 {
659 int count, ch, completely_empty = 1, nl_just_seen = 0;
@@ -2493,6 +2539,188 @@ static int quick_consume(void *priv, char *line UNUSED, unsigned long len UNUSED
2539 return 1;
2540 }
2541
2542 +static void discard_pending_rm(struct line_range_callback *s)
2543 +{
2544 + strbuf_reset(&s->pending_rm);
2545 + s->pending_rm_count = 0;
2546 +}
2547 +
2548 +static void flush_rhunk(struct line_range_callback *s)
2549 +{
2550 + struct strbuf hdr = STRBUF_INIT;
2551 + const char *p, *end;
2552 +
2553 + if (!s->rhunk_active || s->ret)
2554 + return;
2555 +
2556 + /* Drain any pending removal lines into the range hunk */
2557 + if (s->pending_rm_count) {
2558 + strbuf_addbuf(&s->rhunk, &s->pending_rm);
2559 + s->rhunk_old_count += s->pending_rm_count;
2560 + s->rhunk_has_changes = 1;
2561 + discard_pending_rm(s);
2562 + }
2563 +
2564 + /*
2565 + * Suppress context-only hunks: they contain no actual changes
2566 + * and would just be noise. This can happen when the inflated
2567 + * ctxlen causes xdiff to emit context covering a range that
2568 + * has no changes in this commit.
2569 + */
2570 + if (!s->rhunk_has_changes) {
2571 + s->rhunk_active = 0;
2572 + strbuf_reset(&s->rhunk);
2573 + return;
2574 + }
2575 +
2576 + strbuf_addf(&hdr, "@@ -%ld,%ld +%ld,%ld @@",
2577 + s->rhunk_old_begin, s->rhunk_old_count,
2578 + s->rhunk_new_begin, s->rhunk_new_count);
2579 + if (s->funclen > 0) {
2580 + strbuf_addch(&hdr, ' ');
2581 + strbuf_add(&hdr, s->func, s->funclen);
2582 + }
2583 + strbuf_addch(&hdr, '\n');
2584 +
2585 + s->ret = s->orig_line_fn(s->orig_cb_data, hdr.buf, hdr.len);
2586 + strbuf_release(&hdr);
2587 +
2588 + /*
2589 + * Replay buffered lines one at a time through fn_out_consume.
2590 + * The cast discards const because xdiff_emit_line_fn takes
2591 + * char *, though fn_out_consume does not modify the buffer.
2592 + */
2593 + p = s->rhunk.buf;
2594 + end = p + s->rhunk.len;
2595 + while (!s->ret && p < end) {
2596 + const char *eol = memchr(p, '\n', end - p);
2597 + unsigned long line_len = eol ? (unsigned long)(eol - p + 1)
2598 + : (unsigned long)(end - p);
2599 + s->ret = s->orig_line_fn(s->orig_cb_data, (char *)p, line_len);
2600 + p += line_len;
2601 + }
2602 +
2603 + s->rhunk_active = 0;
2604 + strbuf_reset(&s->rhunk);
2605 +}
2606 +
2607 +static void line_range_hunk_fn(void *data,
2608 + long old_begin, long old_nr UNUSED,
2609 + long new_begin, long new_nr UNUSED,
2610 + const char *func, long funclen)
2611 +{
2612 + struct line_range_callback *s = data;
2613 +
2614 + /*
2615 + * When count > 0, begin is 1-based. When count == 0, begin is
2616 + * adjusted down by 1 by xdl_emit_hunk_hdr(), but no lines of
2617 + * that type will arrive, so the value is unused.
2618 + *
2619 + * Any pending removal lines from the previous xdiff hunk are
2620 + * intentionally left in pending_rm: the line callback will
2621 + * flush or discard them when the next content line reveals
2622 + * whether the removals precede in-range content.
2623 + */
2624 + s->lno_post = new_begin;
2625 + s->lno_pre = old_begin;
2626 +
2627 + if (funclen > 0) {
2628 + if (funclen > (long)sizeof(s->func))
2629 + funclen = sizeof(s->func);
2630 + memcpy(s->func, func, funclen);
2631 + }
2632 + s->funclen = funclen;
2633 +}
2634 +
2635 +static int line_range_line_fn(void *priv, char *line, unsigned long len)
2636 +{
2637 + struct line_range_callback *s = priv;
2638 + const struct range *cur;
2639 + long lno_0, cur_pre;
2640 +
2641 + if (s->ret)
2642 + return s->ret;
2643 +
2644 + if (line[0] == '-') {
2645 + if (!s->pending_rm_count)
2646 + s->pending_rm_pre_begin = s->lno_pre;
2647 + s->lno_pre++;
2648 + strbuf_add(&s->pending_rm, line, len);
2649 + s->pending_rm_count++;
2650 + return s->ret;
2651 + }
2652 +
2653 + if (line[0] == '\\') {
2654 + if (s->pending_rm_count)
2655 + strbuf_add(&s->pending_rm, line, len);
2656 + else if (s->rhunk_active)
2657 + strbuf_add(&s->rhunk, line, len);
2658 + /* otherwise outside tracked range; drop silently */
2659 + return s->ret;
2660 + }
2661 +
2662 + if (line[0] != '+' && line[0] != ' ')
2663 + BUG("unexpected diff line type '%c'", line[0]);
2664 +
2665 + lno_0 = s->lno_post - 1;
2666 + cur_pre = s->lno_pre; /* save before advancing for context lines */
2667 + s->lno_post++;
2668 + if (line[0] == ' ')
2669 + s->lno_pre++;
2670 +
2671 + /* Advance past ranges we've passed */
2672 + while (s->cur_range < s->ranges->nr &&
2673 + lno_0 >= s->ranges->ranges[s->cur_range].end) {
2674 + if (s->rhunk_active)
2675 + flush_rhunk(s);
2676 + discard_pending_rm(s);
2677 + s->cur_range++;
2678 + }
2679 +
2680 + /* Past all ranges */
2681 + if (s->cur_range >= s->ranges->nr) {
2682 + discard_pending_rm(s);
2683 + return s->ret;
2684 + }
2685 +
2686 + cur = &s->ranges->ranges[s->cur_range];
2687 +
2688 + /* Before current range */
2689 + if (lno_0 < cur->start) {
2690 + discard_pending_rm(s);
2691 + return s->ret;
2692 + }
2693 +
2694 + /* In range so start a new range hunk if needed */
2695 + if (!s->rhunk_active) {
2696 + s->rhunk_active = 1;
2697 + s->rhunk_has_changes = 0;
2698 + s->rhunk_new_begin = lno_0 + 1;
2699 + s->rhunk_old_begin = s->pending_rm_count
2700 + ? s->pending_rm_pre_begin : cur_pre;
2701 + s->rhunk_old_count = 0;
2702 + s->rhunk_new_count = 0;
2703 + strbuf_reset(&s->rhunk);
2704 + }
2705 +
2706 + /* Flush pending removals into range hunk */
2707 + if (s->pending_rm_count) {
2708 + strbuf_addbuf(&s->rhunk, &s->pending_rm);
2709 + s->rhunk_old_count += s->pending_rm_count;
2710 + s->rhunk_has_changes = 1;
2711 + discard_pending_rm(s);
2712 + }
2713 +
2714 + strbuf_add(&s->rhunk, line, len);
2715 + s->rhunk_new_count++;
2716 + if (line[0] == '+')
2717 + s->rhunk_has_changes = 1;
2718 + else
2719 + s->rhunk_old_count++;
2720 +
2721 + return s->ret;
2722 +}
2723 +
2724 static void pprint_rename(struct strbuf *name, const char *a, const char *b)
2725 {
2726 const char *old_name = a;
@@ -3596,7 +3824,8 @@ static void builtin_diff(const char *name_a,
3824 const char *xfrm_msg,
3825 int must_show_header,
3826 struct diff_options *o,
3599 - int complete_rewrite)
3827 + int complete_rewrite,
3828 + const struct range_set *line_ranges)
3829 {
3830 mmfile_t mf1, mf2;
3831 const char *lbl[2];
@@ -3837,6 +4066,52 @@ static void builtin_diff(const char *name_a,
4066 */
4067 xdi_diff_outf(&mf1, &mf2, NULL, quick_consume,
4068 &ecbdata, &xpp, &xecfg);
4069 + } else if (line_ranges) {
4070 + struct line_range_callback lr_state;
4071 + unsigned int i;
4072 + long max_span = 0;
4073 +
4074 + memset(&lr_state, 0, sizeof(lr_state));
4075 + lr_state.orig_line_fn = fn_out_consume;
4076 + lr_state.orig_cb_data = &ecbdata;
4077 + lr_state.ranges = line_ranges;
4078 + strbuf_init(&lr_state.rhunk, 0);
4079 + strbuf_init(&lr_state.pending_rm, 0);
4080 +
4081 + /*
4082 + * Inflate ctxlen so that all changes within
4083 + * any single range are merged into one xdiff
4084 + * hunk and the inter-change context is emitted.
4085 + * The callback clips back to range boundaries.
4086 + *
4087 + * The optimal ctxlen depends on where changes
4088 + * fall within the range, which is only known
4089 + * after xdiff runs; the max range span is the
4090 + * upper bound that guarantees correctness in a
4091 + * single pass.
4092 + */
4093 + for (i = 0; i < line_ranges->nr; i++) {
4094 + long span = line_ranges->ranges[i].end -
4095 + line_ranges->ranges[i].start;
4096 + if (span > max_span)
4097 + max_span = span;
4098 + }
4099 + if (max_span > xecfg.ctxlen)
4100 + xecfg.ctxlen = max_span;
4101 +
4102 + if (xdi_diff_outf(&mf1, &mf2,
4103 + line_range_hunk_fn,
4104 + line_range_line_fn,
4105 + &lr_state, &xpp, &xecfg))
4106 + die("unable to generate diff for %s",
4107 + one->path);
4108 +
4109 + flush_rhunk(&lr_state);
4110 + if (lr_state.ret)
4111 + die("unable to generate diff for %s",
4112 + one->path);
4113 + strbuf_release(&lr_state.rhunk);
4114 + strbuf_release(&lr_state.pending_rm);
4115 } else if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume,
4116 &ecbdata, &xpp, &xecfg))
4117 die("unable to generate diff for %s", one->path);
@@ -4678,7 +4953,7 @@ static void run_diff_cmd(const struct external_diff *pgm,
4953
4954 builtin_diff(name, other ? other : name,
4955 one, two, xfrm_msg, must_show_header,
4681 - o, complete_rewrite);
4956 + o, complete_rewrite, p->line_ranges);
4957 if (p->status == DIFF_STATUS_COPIED ||
4958 p->status == DIFF_STATUS_RENAMED)
4959 o->found_changes = 1;
diffcore.h
+16
@@ -19,6 +19,17 @@ struct userdiff_driver;
19 * in anything else.
20 */
21
22 +/* A range [start, end). Lines are numbered starting at 0. */
23 +struct range {
24 + long start, end;
25 +};
26 +
27 +/* A set of ranges. The ranges must always be disjoint and sorted. */
28 +struct range_set {
29 + unsigned int alloc, nr;
30 + struct range *ranges;
31 +};
32 +
33 /* We internally use unsigned short as the score value,
34 * and rely on an int capable to hold 32-bits. -B can take
35 * -Bmerge_score/break_score format and the two scores are
@@ -106,6 +117,11 @@ int diff_filespec_is_binary(struct repository *, struct diff_filespec *);
117 struct diff_filepair {
118 struct diff_filespec *one;
119 struct diff_filespec *two;
120 + /*
121 + * Tracked line ranges for -L filtering; borrowed from
122 + * line_log_data and must not be freed.
123 + */
124 + const struct range_set *line_ranges;
125 unsigned short int score;
126 char status; /* M C R A D U etc. (see Documentation/diff-format.adoc or DIFF_STATUS_* in diff.h) */
127 unsigned broken_pair : 1;
line-log.c
+17 -157
@@ -885,160 +885,6 @@ static void queue_diffs(struct line_log_data *range,
885 move_diff_queue(queue, &diff_queued_diff);
886 }
887
888 -static char *get_nth_line(long line, unsigned long *ends, void *data)
889 -{
890 - if (line == 0)
891 - return (char *)data;
892 - else
893 - return (char *)data + ends[line] + 1;
894 -}
895 -
896 -static void print_line(const char *prefix, char first,
897 - long line, unsigned long *ends, void *data,
898 - const char *color, const char *reset, FILE *file)
899 -{
900 - char *begin = get_nth_line(line, ends, data);
901 - char *end = get_nth_line(line+1, ends, data);
902 - int had_nl = 0;
903 -
904 - if (end > begin && end[-1] == '\n') {
905 - end--;
906 - had_nl = 1;
907 - }
908 -
909 - fputs(prefix, file);
910 - fputs(color, file);
911 - putc(first, file);
912 - fwrite(begin, 1, end-begin, file);
913 - fputs(reset, file);
914 - putc('\n', file);
915 - if (!had_nl)
916 - fputs("\\ No newline at end of file\n", file);
917 -}
918 -
919 -static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *range)
920 -{
921 - unsigned int i, j = 0;
922 - long p_lines, t_lines;
923 - unsigned long *p_ends = NULL, *t_ends = NULL;
924 - struct diff_filepair *pair = range->pair;
925 - struct diff_ranges *diff = &range->diff;
926 -
927 - struct diff_options *opt = &rev->diffopt;
928 - const char *prefix = diff_line_prefix(opt);
929 - const char *c_reset = diff_get_color(opt->use_color, DIFF_RESET);
930 - const char *c_frag = diff_get_color(opt->use_color, DIFF_FRAGINFO);
931 - const char *c_meta = diff_get_color(opt->use_color, DIFF_METAINFO);
932 - const char *c_old = diff_get_color(opt->use_color, DIFF_FILE_OLD);
933 - const char *c_new = diff_get_color(opt->use_color, DIFF_FILE_NEW);
934 - const char *c_context = diff_get_color(opt->use_color, DIFF_CONTEXT);
935 -
936 - if (!pair || !diff)
937 - goto out;
938 -
939 - if (pair->one->oid_valid)
940 - fill_line_ends(rev->diffopt.repo, pair->one, &p_lines, &p_ends);
941 - fill_line_ends(rev->diffopt.repo, pair->two, &t_lines, &t_ends);
942 -
943 - fprintf(opt->file, "%s%sdiff --git a/%s b/%s%s\n", prefix, c_meta, pair->one->path, pair->two->path, c_reset);
944 - fprintf(opt->file, "%s%s--- %s%s%s\n", prefix, c_meta,
945 - pair->one->oid_valid ? "a/" : "",
946 - pair->one->oid_valid ? pair->one->path : "/dev/null",
947 - c_reset);
948 - fprintf(opt->file, "%s%s+++ b/%s%s\n", prefix, c_meta, pair->two->path, c_reset);
949 - for (i = 0; i < range->ranges.nr; i++) {
950 - long p_start, p_end;
951 - long t_start = range->ranges.ranges[i].start;
952 - long t_end = range->ranges.ranges[i].end;
953 - long t_cur = t_start;
954 - unsigned int j_last;
955 -
956 - /*
957 - * If a diff range touches multiple line ranges, then all
958 - * those line ranges should be shown, so take a step back if
959 - * the current line range is still in the previous diff range
960 - * (even if only partially).
961 - */
962 - if (j > 0 && diff->target.ranges[j-1].end > t_start)
963 - j--;
964 -
965 - while (j < diff->target.nr && diff->target.ranges[j].end < t_start)
966 - j++;
967 - if (j == diff->target.nr || diff->target.ranges[j].start >= t_end)
968 - continue;
969 -
970 - /* Scan ahead to determine the last diff that falls in this range */
971 - j_last = j;
972 - while (j_last < diff->target.nr && diff->target.ranges[j_last].start < t_end)
973 - j_last++;
974 - if (j_last > j)
975 - j_last--;
976 -
977 - /*
978 - * Compute parent hunk headers: we know that the diff
979 - * has the correct line numbers (but not all hunks).
980 - * So it suffices to shift the start/end according to
981 - * the line numbers of the first/last hunk(s) that
982 - * fall in this range.
983 - */
984 - if (t_start < diff->target.ranges[j].start)
985 - p_start = diff->parent.ranges[j].start - (diff->target.ranges[j].start-t_start);
986 - else
987 - p_start = diff->parent.ranges[j].start;
988 - if (t_end > diff->target.ranges[j_last].end)
989 - p_end = diff->parent.ranges[j_last].end + (t_end-diff->target.ranges[j_last].end);
990 - else
991 - p_end = diff->parent.ranges[j_last].end;
992 -
993 - if (!p_start && !p_end) {
994 - p_start = -1;
995 - p_end = -1;
996 - }
997 -
998 - /* Now output a diff hunk for this range */
999 - fprintf(opt->file, "%s%s@@ -%ld,%ld +%ld,%ld @@%s\n",
1000 - prefix, c_frag,
1001 - p_start+1, p_end-p_start, t_start+1, t_end-t_start,
1002 - c_reset);
1003 - while (j < diff->target.nr && diff->target.ranges[j].start < t_end) {
1004 - int k;
1005 - for (; t_cur < diff->target.ranges[j].start; t_cur++)
1006 - print_line(prefix, ' ', t_cur, t_ends, pair->two->data,
1007 - c_context, c_reset, opt->file);
1008 - for (k = diff->parent.ranges[j].start; k < diff->parent.ranges[j].end; k++)
1009 - print_line(prefix, '-', k, p_ends, pair->one->data,
1010 - c_old, c_reset, opt->file);
1011 - for (; t_cur < diff->target.ranges[j].end && t_cur < t_end; t_cur++)
1012 - print_line(prefix, '+', t_cur, t_ends, pair->two->data,
1013 - c_new, c_reset, opt->file);
1014 - j++;
1015 - }
1016 - for (; t_cur < t_end; t_cur++)
1017 - print_line(prefix, ' ', t_cur, t_ends, pair->two->data,
1018 - c_context, c_reset, opt->file);
1019 - }
1020 -
1021 -out:
1022 - free(p_ends);
1023 - free(t_ends);
1024 -}
1025 -
1026 -/*
1027 - * NEEDSWORK: manually building a diff here is not the Right
1028 - * Thing(tm). log -L should be built into the diff pipeline.
1029 - */
1030 -static void dump_diff_hacky(struct rev_info *rev, struct line_log_data *range)
1031 -{
1032 - const char *prefix = diff_line_prefix(&rev->diffopt);
1033 -
1034 - fprintf(rev->diffopt.file, "%s\n", prefix);
1035 -
1036 - while (range) {
1037 - dump_diff_hacky_one(rev, range);
1038 - range = range->next;
1039 - }
1040 -}
1041 -
888 /*
889 * Unlike most other functions, this destructively operates on
890 * 'range'.
@@ -1102,7 +948,7 @@ static int process_diff_filepair(struct rev_info *rev,
948
949 static struct diff_filepair *diff_filepair_dup(struct diff_filepair *pair)
950 {
1105 - struct diff_filepair *new_filepair = xmalloc(sizeof(struct diff_filepair));
951 + struct diff_filepair *new_filepair = xcalloc(1, sizeof(struct diff_filepair));
952 new_filepair->one = pair->one;
953 new_filepair->two = pair->two;
954 new_filepair->one->count++;
@@ -1160,11 +1006,25 @@ static int process_all_files(struct line_log_data **range_out,
1006
1007 int line_log_print(struct rev_info *rev, struct commit *commit)
1008 {
1163 -
1009 show_log(rev);
1010 if (!(rev->diffopt.output_format & DIFF_FORMAT_NO_OUTPUT)) {
1011 struct line_log_data *range = lookup_line_range(rev, commit);
1167 - dump_diff_hacky(rev, range);
1012 + struct line_log_data *r;
1013 + const char *prefix = diff_line_prefix(&rev->diffopt);
1014 +
1015 + fprintf(rev->diffopt.file, "%s\n", prefix);
1016 +
1017 + for (r = range; r; r = r->next) {
1018 + if (r->pair) {
1019 + struct diff_filepair *p =
1020 + diff_filepair_dup(r->pair);
1021 + p->line_ranges = &r->ranges;
1022 + diff_q(&diff_queued_diff, p);
1023 + }
1024 + }
1025 +
1026 + diffcore_std(&rev->diffopt);
1027 + diff_flush(&rev->diffopt);
1028 }
1029 return 1;
1030 }
line-log.h
+2 -12
@@ -1,22 +1,12 @@
1 #ifndef LINE_LOG_H
2 #define LINE_LOG_H
3
4 +#include "diffcore.h" /* struct range, struct range_set */
5 +
6 struct rev_info;
7 struct commit;
8 struct string_list;
9
8 -/* A range [start,end]. Lines are numbered starting at 0, and the
9 - * ranges include start but exclude end. */
10 -struct range {
11 - long start, end;
12 -};
13 -
14 -/* A set of ranges. The ranges must always be disjoint and sorted. */
15 -struct range_set {
16 - unsigned int alloc, nr;
17 - struct range *ranges;
18 -};
19 -
10 /* A diff, encoded as the set of pre- and post-image ranges where the
11 * files differ. A pair of ranges corresponds to a hunk. */
12 struct diff_ranges {
revision.c
+2
@@ -3111,6 +3111,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
3111 if (want_ancestry(revs))
3112 revs->limited = 1;
3113 revs->topo_order = 1;
3114 + if (!revs->diffopt.output_format)
3115 + revs->diffopt.output_format = DIFF_FORMAT_PATCH;
3116 }
3117
3118 if (revs->topo_order && !generation_numbers_enabled(the_repository))
t/t4211-line-log.sh
+10 -2
@@ -129,7 +129,7 @@ test_expect_success '-L with --output' '
129 git checkout parallel-change &&
130 git log --output=log -L :main:b.c >output &&
131 test_must_be_empty output &&
132 - test_line_count = 70 log
132 + test_line_count = 75 log
133 '
134
135 test_expect_success 'range_set_union' '
@@ -340,13 +340,19 @@ test_expect_success 'zero-width regex .* matches any function name' '
340 '
341
342 test_expect_success 'show line-log with graph' '
343 + git checkout parent-oids &&
344 + head_blob_old=$(git rev-parse --short HEAD^:file.c) &&
345 + head_blob_new=$(git rev-parse --short HEAD:file.c) &&
346 + root_blob=$(git rev-parse --short HEAD~4:file.c) &&
347 + null_blob=$(test_oid zero | cut -c1-7) &&
348 qz_to_tab_space >expect <<-EOF &&
349 * $head_oid Modify func2() in file.c
350 |Z
351 | diff --git a/file.c b/file.c
352 + | index $head_blob_old..$head_blob_new 100644
353 | --- a/file.c
354 | +++ b/file.c
349 - | @@ -6,4 +6,4 @@
355 + | @@ -6,4 +6,4 @@ int func1()
356 | int func2()
357 | {
358 | - return F2;
@@ -355,6 +361,8 @@ test_expect_success 'show line-log with graph' '
361 * $root_oid Add func1() and func2() in file.c
362 ZZ
363 diff --git a/file.c b/file.c
364 + new file mode 100644
365 + index $null_blob..$root_blob
366 --- /dev/null
367 +++ b/file.c
368 @@ -0,0 +6,4 @@
t/t4211/sha1/expect.beginning-of-file
+4
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:47:40 2013 +0100
5 change at very beginning
6
7 diff --git a/a.c b/a.c
8 +index bdb2bb1..5e709a1 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -1,3 +1,4 @@
@@ -20,6 +21,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
21 touch both functions
22
23 diff --git a/a.c b/a.c
24 +index 3233403..e51de13 100644
25 --- a/a.c
26 +++ b/a.c
27 @@ -1,3 +1,3 @@
@@ -35,6 +37,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
37 initial
38
39 diff --git a/a.c b/a.c
40 +new file mode 100644
41 +index 0000000..444e415
42 --- /dev/null
43 +++ b/a.c
44 @@ -0,0 +1,3 @@
t/t4211/sha1/expect.end-of-file
+8 -3
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index 0b9cae5..5de3ea4 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -20,3 +20,5 @@
11 +@@ -20,3 +20,5 @@ long f(long x)
12 printf("%ld\n", f(15));
13 return 0;
14 -}
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
24 change to an incomplete line at end
25
26 diff --git a/a.c b/a.c
27 +index 5e709a1..0b9cae5 100644
28 --- a/a.c
29 +++ b/a.c
28 -@@ -20,3 +20,3 @@
30 +@@ -20,3 +20,3 @@ int main ()
31 printf("%ld\n", f(15));
32 return 0;
33 -}
@@ -39,9 +41,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
41 touch both functions
42
43 diff --git a/a.c b/a.c
44 +index 3233403..e51de13 100644
45 --- a/a.c
46 +++ b/a.c
44 -@@ -19,3 +19,3 @@
47 +@@ -19,3 +19,3 @@ int f(int x)
48 - printf("%d\n", f(15));
49 + printf("%ld\n", f(15));
50 return 0;
@@ -54,6 +57,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
57 initial
58
59 diff --git a/a.c b/a.c
60 +new file mode 100644
61 +index 0000000..444e415
62 --- /dev/null
63 +++ b/a.c
64 @@ -0,0 +18,3 @@
t/t4211/sha1/expect.move-support-f
+5
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:49:50 2013 +0100
5 another simple change
6
7 diff --git a/b.c b/b.c
8 +index 5de3ea4..bf79c2f 100644
9 --- a/b.c
10 +++ b/b.c
11 @@ -4,9 +4,9 @@
@@ -26,6 +27,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
27 touch both functions
28
29 diff --git a/a.c b/a.c
30 +index 3233403..e51de13 100644
31 --- a/a.c
32 +++ b/a.c
33 @@ -3,9 +3,9 @@
@@ -47,6 +49,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
49 change f()
50
51 diff --git a/a.c b/a.c
52 +index 444e415..3233403 100644
53 --- a/a.c
54 +++ b/a.c
55 @@ -3,8 +3,9 @@
@@ -67,6 +70,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
70 initial
71
72 diff --git a/a.c b/a.c
73 +new file mode 100644
74 +index 0000000..444e415
75 --- /dev/null
76 +++ b/a.c
77 @@ -0,0 +3,8 @@
t/t4211/sha1/expect.multiple
+8 -2
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index 0b9cae5..5de3ea4 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -18,5 +18,7 @@
11 +@@ -18,5 +18,7 @@ long f(long x)
12 int main ()
13 {
14 printf("%ld\n", f(15));
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
26 change to an incomplete line at end
27
28 diff --git a/a.c b/a.c
29 +index 5e709a1..0b9cae5 100644
30 --- a/a.c
31 +++ b/a.c
30 -@@ -18,5 +18,5 @@
32 +@@ -18,5 +18,5 @@ long f(long x)
33 int main ()
34 {
35 printf("%ld\n", f(15));
@@ -43,6 +45,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
45 touch both functions
46
47 diff --git a/a.c b/a.c
48 +index 3233403..e51de13 100644
49 --- a/a.c
50 +++ b/a.c
51 @@ -3,9 +3,9 @@
@@ -71,6 +74,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
74 change f()
75
76 diff --git a/a.c b/a.c
77 +index 444e415..3233403 100644
78 --- a/a.c
79 +++ b/a.c
80 @@ -3,8 +3,9 @@
@@ -91,6 +95,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
95 initial
96
97 diff --git a/a.c b/a.c
98 +new file mode 100644
99 +index 0000000..444e415
100 --- /dev/null
101 +++ b/a.c
102 @@ -0,0 +3,8 @@
t/t4211/sha1/expect.multiple-overlapping
+7
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index 0b9cae5..5de3ea4 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -4,19 +4,21 @@
@@ -39,6 +40,7 @@ Date: Thu Feb 28 10:48:10 2013 +0100
40 change to an incomplete line at end
41
42 diff --git a/a.c b/a.c
43 +index 5e709a1..0b9cae5 100644
44 --- a/a.c
45 +++ b/a.c
46 @@ -4,19 +4,19 @@
@@ -71,6 +73,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
73 touch comment
74
75 diff --git a/a.c b/a.c
76 +index e51de13..bdb2bb1 100644
77 --- a/a.c
78 +++ b/a.c
79 @@ -3,19 +3,19 @@
@@ -102,6 +105,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
105 touch both functions
106
107 diff --git a/a.c b/a.c
108 +index 3233403..e51de13 100644
109 --- a/a.c
110 +++ b/a.c
111 @@ -3,19 +3,19 @@
@@ -134,6 +138,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
138 change f()
139
140 diff --git a/a.c b/a.c
141 +index 444e415..3233403 100644
142 --- a/a.c
143 +++ b/a.c
144 @@ -3,18 +3,19 @@
@@ -164,6 +169,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
169 initial
170
171 diff --git a/a.c b/a.c
172 +new file mode 100644
173 +index 0000000..444e415
174 --- /dev/null
175 +++ b/a.c
176 @@ -0,0 +3,18 @@
t/t4211/sha1/expect.multiple-superset
+7
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index 0b9cae5..5de3ea4 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -4,19 +4,21 @@
@@ -39,6 +40,7 @@ Date: Thu Feb 28 10:48:10 2013 +0100
40 change to an incomplete line at end
41
42 diff --git a/a.c b/a.c
43 +index 5e709a1..0b9cae5 100644
44 --- a/a.c
45 +++ b/a.c
46 @@ -4,19 +4,19 @@
@@ -71,6 +73,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
73 touch comment
74
75 diff --git a/a.c b/a.c
76 +index e51de13..bdb2bb1 100644
77 --- a/a.c
78 +++ b/a.c
79 @@ -3,19 +3,19 @@
@@ -102,6 +105,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
105 touch both functions
106
107 diff --git a/a.c b/a.c
108 +index 3233403..e51de13 100644
109 --- a/a.c
110 +++ b/a.c
111 @@ -3,19 +3,19 @@
@@ -134,6 +138,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
138 change f()
139
140 diff --git a/a.c b/a.c
141 +index 444e415..3233403 100644
142 --- a/a.c
143 +++ b/a.c
144 @@ -3,18 +3,19 @@
@@ -164,6 +169,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
169 initial
170
171 diff --git a/a.c b/a.c
172 +new file mode 100644
173 +index 0000000..444e415
174 --- /dev/null
175 +++ b/a.c
176 @@ -0,0 +3,18 @@
t/t4211/sha1/expect.no-assertion-error
+9 -3
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:50:24 2013 +0100
5 move within the file
6
7 diff --git a/b.c b/b.c
8 +index bf79c2f..27c829c 100644
9 --- a/b.c
10 +++ b/b.c
11 @@ -25,0 +18,9 @@
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
26 change back to complete line
27
28 diff --git a/a.c b/a.c
29 +index 0b9cae5..5de3ea4 100644
30 --- a/a.c
31 +++ b/a.c
30 -@@ -18,5 +18,7 @@
32 +@@ -18,5 +18,7 @@ long f(long x)
33 int main ()
34 {
35 printf("%ld\n", f(15));
@@ -45,9 +47,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
47 change to an incomplete line at end
48
49 diff --git a/a.c b/a.c
50 +index 5e709a1..0b9cae5 100644
51 --- a/a.c
52 +++ b/a.c
50 -@@ -18,5 +18,5 @@
53 +@@ -18,5 +18,5 @@ long f(long x)
54 int main ()
55 {
56 printf("%ld\n", f(15));
@@ -63,9 +66,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
66 touch both functions
67
68 diff --git a/a.c b/a.c
69 +index 3233403..e51de13 100644
70 --- a/a.c
71 +++ b/a.c
68 -@@ -17,5 +17,5 @@
72 +@@ -17,5 +17,5 @@ int f(int x)
73 int main ()
74 {
75 - printf("%d\n", f(15));
@@ -80,6 +84,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
84 initial
85
86 diff --git a/a.c b/a.c
87 +new file mode 100644
88 +index 0000000..444e415
89 --- /dev/null
90 +++ b/a.c
91 @@ -0,0 +16,5 @@
t/t4211/sha1/expect.parallel-change-f-to-main
+7
@@ -13,6 +13,7 @@ Date: Thu Feb 28 10:49:50 2013 +0100
13 another simple change
14
15 diff --git a/b.c b/b.c
16 +index 5de3ea4..bf79c2f 100644
17 --- a/b.c
18 +++ b/b.c
19 @@ -4,14 +4,14 @@
@@ -39,6 +40,7 @@ Date: Fri Apr 12 16:15:57 2013 +0200
40 change on another line of history while rename happens
41
42 diff --git a/a.c b/a.c
43 +index 5de3ea4..01b5b65 100644
44 --- a/a.c
45 +++ b/a.c
46 @@ -4,14 +4,14 @@
@@ -65,6 +67,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
67 touch comment
68
69 diff --git a/a.c b/a.c
70 +index e51de13..bdb2bb1 100644
71 --- a/a.c
72 +++ b/a.c
73 @@ -3,14 +3,14 @@
@@ -91,6 +94,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
94 touch both functions
95
96 diff --git a/a.c b/a.c
97 +index 3233403..e51de13 100644
98 --- a/a.c
99 +++ b/a.c
100 @@ -3,14 +3,14 @@
@@ -117,6 +121,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
121 change f()
122
123 diff --git a/a.c b/a.c
124 +index 444e415..3233403 100644
125 --- a/a.c
126 +++ b/a.c
127 @@ -3,13 +3,14 @@
@@ -142,6 +147,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
147 initial
148
149 diff --git a/a.c b/a.c
150 +new file mode 100644
151 +index 0000000..444e415
152 --- /dev/null
153 +++ b/a.c
154 @@ -0,0 +3,13 @@
t/t4211/sha1/expect.simple-f
+4
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
5 touch both functions
6
7 diff --git a/a.c b/a.c
8 +index 3233403..e51de13 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -3,9 +3,9 @@
@@ -26,6 +27,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
27 change f()
28
29 diff --git a/a.c b/a.c
30 +index 444e415..3233403 100644
31 --- a/a.c
32 +++ b/a.c
33 @@ -3,8 +3,9 @@
@@ -46,6 +48,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
48 initial
49
50 diff --git a/a.c b/a.c
51 +new file mode 100644
52 +index 0000000..444e415
53 --- /dev/null
54 +++ b/a.c
55 @@ -0,0 +3,8 @@
t/t4211/sha1/expect.simple-f-to-main
+5
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
5 touch comment
6
7 diff --git a/a.c b/a.c
8 +index e51de13..bdb2bb1 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -3,14 +3,14 @@
@@ -31,6 +32,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
32 touch both functions
33
34 diff --git a/a.c b/a.c
35 +index 3233403..e51de13 100644
36 --- a/a.c
37 +++ b/a.c
38 @@ -3,14 +3,14 @@
@@ -57,6 +59,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
59 change f()
60
61 diff --git a/a.c b/a.c
62 +index 444e415..3233403 100644
63 --- a/a.c
64 +++ b/a.c
65 @@ -3,13 +3,14 @@
@@ -82,6 +85,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
85 initial
86
87 diff --git a/a.c b/a.c
88 +new file mode 100644
89 +index 0000000..444e415
90 --- /dev/null
91 +++ b/a.c
92 @@ -0,0 +3,13 @@
t/t4211/sha1/expect.simple-main
+8 -3
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index 0b9cae5..5de3ea4 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -18,5 +18,5 @@
11 +@@ -18,5 +18,5 @@ long f(long x)
12 int main ()
13 {
14 printf("%ld\n", f(15));
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
24 change to an incomplete line at end
25
26 diff --git a/a.c b/a.c
27 +index 5e709a1..0b9cae5 100644
28 --- a/a.c
29 +++ b/a.c
28 -@@ -18,5 +18,5 @@
30 +@@ -18,5 +18,5 @@ long f(long x)
31 int main ()
32 {
33 printf("%ld\n", f(15));
@@ -41,9 +43,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
43 touch both functions
44
45 diff --git a/a.c b/a.c
46 +index 3233403..e51de13 100644
47 --- a/a.c
48 +++ b/a.c
46 -@@ -17,5 +17,5 @@
49 +@@ -17,5 +17,5 @@ int f(int x)
50 int main ()
51 {
52 - printf("%d\n", f(15));
@@ -58,6 +61,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
61 initial
62
63 diff --git a/a.c b/a.c
64 +new file mode 100644
65 +index 0000000..444e415
66 --- /dev/null
67 +++ b/a.c
68 @@ -0,0 +16,5 @@
t/t4211/sha1/expect.simple-main-to-end
+8 -3
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index 0b9cae5..5de3ea4 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -18,5 +18,7 @@
11 +@@ -18,5 +18,7 @@ long f(long x)
12 int main ()
13 {
14 printf("%ld\n", f(15));
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
26 change to an incomplete line at end
27
28 diff --git a/a.c b/a.c
29 +index 5e709a1..0b9cae5 100644
30 --- a/a.c
31 +++ b/a.c
30 -@@ -18,5 +18,5 @@
32 +@@ -18,5 +18,5 @@ long f(long x)
33 int main ()
34 {
35 printf("%ld\n", f(15));
@@ -43,9 +45,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
45 touch both functions
46
47 diff --git a/a.c b/a.c
48 +index 3233403..e51de13 100644
49 --- a/a.c
50 +++ b/a.c
48 -@@ -17,5 +17,5 @@
51 +@@ -17,5 +17,5 @@ int f(int x)
52 int main ()
53 {
54 - printf("%d\n", f(15));
@@ -60,6 +63,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
63 initial
64
65 diff --git a/a.c b/a.c
66 +new file mode 100644
67 +index 0000000..444e415
68 --- /dev/null
69 +++ b/a.c
70 @@ -0,0 +16,5 @@
t/t4211/sha1/expect.two-ranges
+8 -2
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index 0b9cae5..5de3ea4 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -18,5 +18,5 @@
11 +@@ -18,5 +18,5 @@ long f(long x)
12 int main ()
13 {
14 printf("%ld\n", f(15));
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
24 change to an incomplete line at end
25
26 diff --git a/a.c b/a.c
27 +index 5e709a1..0b9cae5 100644
28 --- a/a.c
29 +++ b/a.c
28 -@@ -18,5 +18,5 @@
30 +@@ -18,5 +18,5 @@ long f(long x)
31 int main ()
32 {
33 printf("%ld\n", f(15));
@@ -41,6 +43,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
43 touch both functions
44
45 diff --git a/a.c b/a.c
46 +index 3233403..e51de13 100644
47 --- a/a.c
48 +++ b/a.c
49 @@ -3,9 +3,9 @@
@@ -69,6 +72,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
72 change f()
73
74 diff --git a/a.c b/a.c
75 +index 444e415..3233403 100644
76 --- a/a.c
77 +++ b/a.c
78 @@ -3,8 +3,9 @@
@@ -89,6 +93,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
93 initial
94
95 diff --git a/a.c b/a.c
96 +new file mode 100644
97 +index 0000000..444e415
98 --- /dev/null
99 +++ b/a.c
100 @@ -0,0 +3,8 @@
t/t4211/sha1/expect.vanishes-early
+6 -4
@@ -5,11 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index 0b9cae5..5de3ea4 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -22,1 +24,1 @@
11 --}
12 -\ No newline at end of file
11 +@@ -23,0 +24,1 @@ int main ()
12 +/* incomplete lines are bad! */
13
14 commit 100b61a6f2f720f812620a9d10afb3a960ccb73c
@@ -19,9 +18,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
18 change to an incomplete line at end
19
20 diff --git a/a.c b/a.c
21 +index 5e709a1..0b9cae5 100644
22 --- a/a.c
23 +++ b/a.c
24 -@@ -22,1 +22,1 @@
24 +@@ -22,1 +22,1 @@ int main ()
25 -}
26 +}
27 \ No newline at end of file
@@ -33,6 +33,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
33 initial
34
35 diff --git a/a.c b/a.c
36 +new file mode 100644
37 +index 0000000..444e415
38 --- /dev/null
39 +++ b/a.c
40 @@ -0,0 +20,1 @@
t/t4211/sha256/expect.beginning-of-file
+4
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:47:40 2013 +0100
5 change at very beginning
6
7 diff --git a/a.c b/a.c
8 +index 3a78aaf..d325124 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -1,3 +1,4 @@
@@ -20,6 +21,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
21 touch both functions
22
23 diff --git a/a.c b/a.c
24 +index 7a296b9..75c0119 100644
25 --- a/a.c
26 +++ b/a.c
27 @@ -1,3 +1,3 @@
@@ -35,6 +37,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
37 initial
38
39 diff --git a/a.c b/a.c
40 +new file mode 100644
41 +index 0000000..9f550c3
42 --- /dev/null
43 +++ b/a.c
44 @@ -0,0 +1,3 @@
t/t4211/sha256/expect.end-of-file
+8 -3
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index e4fa1d8..62c1fc2 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -20,3 +20,5 @@
11 +@@ -20,3 +20,5 @@ long f(long x)
12 printf("%ld\n", f(15));
13 return 0;
14 -}
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
24 change to an incomplete line at end
25
26 diff --git a/a.c b/a.c
27 +index d325124..e4fa1d8 100644
28 --- a/a.c
29 +++ b/a.c
28 -@@ -20,3 +20,3 @@
30 +@@ -20,3 +20,3 @@ int main ()
31 printf("%ld\n", f(15));
32 return 0;
33 -}
@@ -39,9 +41,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
41 touch both functions
42
43 diff --git a/a.c b/a.c
44 +index 7a296b9..75c0119 100644
45 --- a/a.c
46 +++ b/a.c
44 -@@ -19,3 +19,3 @@
47 +@@ -19,3 +19,3 @@ int f(int x)
48 - printf("%d\n", f(15));
49 + printf("%ld\n", f(15));
50 return 0;
@@ -54,6 +57,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
57 initial
58
59 diff --git a/a.c b/a.c
60 +new file mode 100644
61 +index 0000000..9f550c3
62 --- /dev/null
63 +++ b/a.c
64 @@ -0,0 +18,3 @@
t/t4211/sha256/expect.move-support-f
+5
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:49:50 2013 +0100
5 another simple change
6
7 diff --git a/b.c b/b.c
8 +index 62c1fc2..69cb69c 100644
9 --- a/b.c
10 +++ b/b.c
11 @@ -4,9 +4,9 @@
@@ -26,6 +27,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
27 touch both functions
28
29 diff --git a/a.c b/a.c
30 +index 7a296b9..75c0119 100644
31 --- a/a.c
32 +++ b/a.c
33 @@ -3,9 +3,9 @@
@@ -47,6 +49,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
49 change f()
50
51 diff --git a/a.c b/a.c
52 +index 9f550c3..7a296b9 100644
53 --- a/a.c
54 +++ b/a.c
55 @@ -3,8 +3,9 @@
@@ -67,6 +70,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
70 initial
71
72 diff --git a/a.c b/a.c
73 +new file mode 100644
74 +index 0000000..9f550c3
75 --- /dev/null
76 +++ b/a.c
77 @@ -0,0 +3,8 @@
t/t4211/sha256/expect.multiple
+8 -2
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index e4fa1d8..62c1fc2 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -18,5 +18,7 @@
11 +@@ -18,5 +18,7 @@ long f(long x)
12 int main ()
13 {
14 printf("%ld\n", f(15));
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
26 change to an incomplete line at end
27
28 diff --git a/a.c b/a.c
29 +index d325124..e4fa1d8 100644
30 --- a/a.c
31 +++ b/a.c
30 -@@ -18,5 +18,5 @@
32 +@@ -18,5 +18,5 @@ long f(long x)
33 int main ()
34 {
35 printf("%ld\n", f(15));
@@ -43,6 +45,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
45 touch both functions
46
47 diff --git a/a.c b/a.c
48 +index 7a296b9..75c0119 100644
49 --- a/a.c
50 +++ b/a.c
51 @@ -3,9 +3,9 @@
@@ -71,6 +74,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
74 change f()
75
76 diff --git a/a.c b/a.c
77 +index 9f550c3..7a296b9 100644
78 --- a/a.c
79 +++ b/a.c
80 @@ -3,8 +3,9 @@
@@ -91,6 +95,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
95 initial
96
97 diff --git a/a.c b/a.c
98 +new file mode 100644
99 +index 0000000..9f550c3
100 --- /dev/null
101 +++ b/a.c
102 @@ -0,0 +3,8 @@
t/t4211/sha256/expect.multiple-overlapping
+7
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index e4fa1d8..62c1fc2 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -4,19 +4,21 @@
@@ -39,6 +40,7 @@ Date: Thu Feb 28 10:48:10 2013 +0100
40 change to an incomplete line at end
41
42 diff --git a/a.c b/a.c
43 +index d325124..e4fa1d8 100644
44 --- a/a.c
45 +++ b/a.c
46 @@ -4,19 +4,19 @@
@@ -71,6 +73,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
73 touch comment
74
75 diff --git a/a.c b/a.c
76 +index 75c0119..3a78aaf 100644
77 --- a/a.c
78 +++ b/a.c
79 @@ -3,19 +3,19 @@
@@ -102,6 +105,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
105 touch both functions
106
107 diff --git a/a.c b/a.c
108 +index 7a296b9..75c0119 100644
109 --- a/a.c
110 +++ b/a.c
111 @@ -3,19 +3,19 @@
@@ -134,6 +138,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
138 change f()
139
140 diff --git a/a.c b/a.c
141 +index 9f550c3..7a296b9 100644
142 --- a/a.c
143 +++ b/a.c
144 @@ -3,18 +3,19 @@
@@ -164,6 +169,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
169 initial
170
171 diff --git a/a.c b/a.c
172 +new file mode 100644
173 +index 0000000..9f550c3
174 --- /dev/null
175 +++ b/a.c
176 @@ -0,0 +3,18 @@
t/t4211/sha256/expect.multiple-superset
+7
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index e4fa1d8..62c1fc2 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -4,19 +4,21 @@
@@ -39,6 +40,7 @@ Date: Thu Feb 28 10:48:10 2013 +0100
40 change to an incomplete line at end
41
42 diff --git a/a.c b/a.c
43 +index d325124..e4fa1d8 100644
44 --- a/a.c
45 +++ b/a.c
46 @@ -4,19 +4,19 @@
@@ -71,6 +73,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
73 touch comment
74
75 diff --git a/a.c b/a.c
76 +index 75c0119..3a78aaf 100644
77 --- a/a.c
78 +++ b/a.c
79 @@ -3,19 +3,19 @@
@@ -102,6 +105,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
105 touch both functions
106
107 diff --git a/a.c b/a.c
108 +index 7a296b9..75c0119 100644
109 --- a/a.c
110 +++ b/a.c
111 @@ -3,19 +3,19 @@
@@ -134,6 +138,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
138 change f()
139
140 diff --git a/a.c b/a.c
141 +index 9f550c3..7a296b9 100644
142 --- a/a.c
143 +++ b/a.c
144 @@ -3,18 +3,19 @@
@@ -164,6 +169,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
169 initial
170
171 diff --git a/a.c b/a.c
172 +new file mode 100644
173 +index 0000000..9f550c3
174 --- /dev/null
175 +++ b/a.c
176 @@ -0,0 +3,18 @@
t/t4211/sha256/expect.no-assertion-error
+9 -3
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:50:24 2013 +0100
5 move within the file
6
7 diff --git a/b.c b/b.c
8 +index 69cb69c..a0d566e 100644
9 --- a/b.c
10 +++ b/b.c
11 @@ -25,0 +18,9 @@
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
26 change back to complete line
27
28 diff --git a/a.c b/a.c
29 +index e4fa1d8..62c1fc2 100644
30 --- a/a.c
31 +++ b/a.c
30 -@@ -18,5 +18,7 @@
32 +@@ -18,5 +18,7 @@ long f(long x)
33 int main ()
34 {
35 printf("%ld\n", f(15));
@@ -45,9 +47,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
47 change to an incomplete line at end
48
49 diff --git a/a.c b/a.c
50 +index d325124..e4fa1d8 100644
51 --- a/a.c
52 +++ b/a.c
50 -@@ -18,5 +18,5 @@
53 +@@ -18,5 +18,5 @@ long f(long x)
54 int main ()
55 {
56 printf("%ld\n", f(15));
@@ -63,9 +66,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
66 touch both functions
67
68 diff --git a/a.c b/a.c
69 +index 7a296b9..75c0119 100644
70 --- a/a.c
71 +++ b/a.c
68 -@@ -17,5 +17,5 @@
72 +@@ -17,5 +17,5 @@ int f(int x)
73 int main ()
74 {
75 - printf("%d\n", f(15));
@@ -80,6 +84,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
84 initial
85
86 diff --git a/a.c b/a.c
87 +new file mode 100644
88 +index 0000000..9f550c3
89 --- /dev/null
90 +++ b/a.c
91 @@ -0,0 +16,5 @@
t/t4211/sha256/expect.parallel-change-f-to-main
+7
@@ -13,6 +13,7 @@ Date: Thu Feb 28 10:49:50 2013 +0100
13 another simple change
14
15 diff --git a/b.c b/b.c
16 +index 62c1fc2..69cb69c 100644
17 --- a/b.c
18 +++ b/b.c
19 @@ -4,14 +4,14 @@
@@ -39,6 +40,7 @@ Date: Fri Apr 12 16:15:57 2013 +0200
40 change on another line of history while rename happens
41
42 diff --git a/a.c b/a.c
43 +index 62c1fc2..e1e8475 100644
44 --- a/a.c
45 +++ b/a.c
46 @@ -4,14 +4,14 @@
@@ -65,6 +67,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
67 touch comment
68
69 diff --git a/a.c b/a.c
70 +index 75c0119..3a78aaf 100644
71 --- a/a.c
72 +++ b/a.c
73 @@ -3,14 +3,14 @@
@@ -91,6 +94,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
94 touch both functions
95
96 diff --git a/a.c b/a.c
97 +index 7a296b9..75c0119 100644
98 --- a/a.c
99 +++ b/a.c
100 @@ -3,14 +3,14 @@
@@ -117,6 +121,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
121 change f()
122
123 diff --git a/a.c b/a.c
124 +index 9f550c3..7a296b9 100644
125 --- a/a.c
126 +++ b/a.c
127 @@ -3,13 +3,14 @@
@@ -142,6 +147,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
147 initial
148
149 diff --git a/a.c b/a.c
150 +new file mode 100644
151 +index 0000000..9f550c3
152 --- /dev/null
153 +++ b/a.c
154 @@ -0,0 +3,13 @@
t/t4211/sha256/expect.simple-f
+4
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
5 touch both functions
6
7 diff --git a/a.c b/a.c
8 +index 7a296b9..75c0119 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -3,9 +3,9 @@
@@ -26,6 +27,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
27 change f()
28
29 diff --git a/a.c b/a.c
30 +index 9f550c3..7a296b9 100644
31 --- a/a.c
32 +++ b/a.c
33 @@ -3,8 +3,9 @@
@@ -46,6 +48,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
48 initial
49
50 diff --git a/a.c b/a.c
51 +new file mode 100644
52 +index 0000000..9f550c3
53 --- /dev/null
54 +++ b/a.c
55 @@ -0,0 +3,8 @@
t/t4211/sha256/expect.simple-f-to-main
+5
@@ -5,6 +5,7 @@ Date: Thu Feb 28 10:45:41 2013 +0100
5 touch comment
6
7 diff --git a/a.c b/a.c
8 +index 75c0119..3a78aaf 100644
9 --- a/a.c
10 +++ b/a.c
11 @@ -3,14 +3,14 @@
@@ -31,6 +32,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
32 touch both functions
33
34 diff --git a/a.c b/a.c
35 +index 7a296b9..75c0119 100644
36 --- a/a.c
37 +++ b/a.c
38 @@ -3,14 +3,14 @@
@@ -57,6 +59,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
59 change f()
60
61 diff --git a/a.c b/a.c
62 +index 9f550c3..7a296b9 100644
63 --- a/a.c
64 +++ b/a.c
65 @@ -3,13 +3,14 @@
@@ -82,6 +85,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
85 initial
86
87 diff --git a/a.c b/a.c
88 +new file mode 100644
89 +index 0000000..9f550c3
90 --- /dev/null
91 +++ b/a.c
92 @@ -0,0 +3,13 @@
t/t4211/sha256/expect.simple-main
+8 -3
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index e4fa1d8..62c1fc2 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -18,5 +18,5 @@
11 +@@ -18,5 +18,5 @@ long f(long x)
12 int main ()
13 {
14 printf("%ld\n", f(15));
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
24 change to an incomplete line at end
25
26 diff --git a/a.c b/a.c
27 +index d325124..e4fa1d8 100644
28 --- a/a.c
29 +++ b/a.c
28 -@@ -18,5 +18,5 @@
30 +@@ -18,5 +18,5 @@ long f(long x)
31 int main ()
32 {
33 printf("%ld\n", f(15));
@@ -41,9 +43,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
43 touch both functions
44
45 diff --git a/a.c b/a.c
46 +index 7a296b9..75c0119 100644
47 --- a/a.c
48 +++ b/a.c
46 -@@ -17,5 +17,5 @@
49 +@@ -17,5 +17,5 @@ int f(int x)
50 int main ()
51 {
52 - printf("%d\n", f(15));
@@ -58,6 +61,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
61 initial
62
63 diff --git a/a.c b/a.c
64 +new file mode 100644
65 +index 0000000..9f550c3
66 --- /dev/null
67 +++ b/a.c
68 @@ -0,0 +16,5 @@
t/t4211/sha256/expect.simple-main-to-end
+8 -3
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index e4fa1d8..62c1fc2 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -18,5 +18,7 @@
11 +@@ -18,5 +18,7 @@ long f(long x)
12 int main ()
13 {
14 printf("%ld\n", f(15));
@@ -25,9 +26,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
26 change to an incomplete line at end
27
28 diff --git a/a.c b/a.c
29 +index d325124..e4fa1d8 100644
30 --- a/a.c
31 +++ b/a.c
30 -@@ -18,5 +18,5 @@
32 +@@ -18,5 +18,5 @@ long f(long x)
33 int main ()
34 {
35 printf("%ld\n", f(15));
@@ -43,9 +45,10 @@ Date: Thu Feb 28 10:45:16 2013 +0100
45 touch both functions
46
47 diff --git a/a.c b/a.c
48 +index 7a296b9..75c0119 100644
49 --- a/a.c
50 +++ b/a.c
48 -@@ -17,5 +17,5 @@
51 +@@ -17,5 +17,5 @@ int f(int x)
52 int main ()
53 {
54 - printf("%d\n", f(15));
@@ -60,6 +63,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
63 initial
64
65 diff --git a/a.c b/a.c
66 +new file mode 100644
67 +index 0000000..9f550c3
68 --- /dev/null
69 +++ b/a.c
70 @@ -0,0 +16,5 @@
t/t4211/sha256/expect.two-ranges
+8 -2
@@ -5,9 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index e4fa1d8..62c1fc2 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -18,5 +18,5 @@
11 +@@ -18,5 +18,5 @@ long f(long x)
12 int main ()
13 {
14 printf("%ld\n", f(15));
@@ -23,9 +24,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
24 change to an incomplete line at end
25
26 diff --git a/a.c b/a.c
27 +index d325124..e4fa1d8 100644
28 --- a/a.c
29 +++ b/a.c
28 -@@ -18,5 +18,5 @@
30 +@@ -18,5 +18,5 @@ long f(long x)
31 int main ()
32 {
33 printf("%ld\n", f(15));
@@ -41,6 +43,7 @@ Date: Thu Feb 28 10:45:16 2013 +0100
43 touch both functions
44
45 diff --git a/a.c b/a.c
46 +index 7a296b9..75c0119 100644
47 --- a/a.c
48 +++ b/a.c
49 @@ -3,9 +3,9 @@
@@ -69,6 +72,7 @@ Date: Thu Feb 28 10:44:55 2013 +0100
72 change f()
73
74 diff --git a/a.c b/a.c
75 +index 9f550c3..7a296b9 100644
76 --- a/a.c
77 +++ b/a.c
78 @@ -3,8 +3,9 @@
@@ -89,6 +93,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
93 initial
94
95 diff --git a/a.c b/a.c
96 +new file mode 100644
97 +index 0000000..9f550c3
98 --- /dev/null
99 +++ b/a.c
100 @@ -0,0 +3,8 @@
t/t4211/sha256/expect.vanishes-early
+6 -4
@@ -5,11 +5,10 @@ Date: Thu Feb 28 10:48:43 2013 +0100
5 change back to complete line
6
7 diff --git a/a.c b/a.c
8 +index e4fa1d8..62c1fc2 100644
9 --- a/a.c
10 +++ b/a.c
10 -@@ -22,1 +24,1 @@
11 --}
12 -\ No newline at end of file
11 +@@ -23,0 +24,1 @@ int main ()
12 +/* incomplete lines are bad! */
13
14 commit 29f32ac3141c48b22803e5c4127b719917b67d0f8ca8c5248bebfa2a19f7da10
@@ -19,9 +18,10 @@ Date: Thu Feb 28 10:48:10 2013 +0100
18 change to an incomplete line at end
19
20 diff --git a/a.c b/a.c
21 +index d325124..e4fa1d8 100644
22 --- a/a.c
23 +++ b/a.c
24 -@@ -22,1 +22,1 @@
24 +@@ -22,1 +22,1 @@ int main ()
25 -}
26 +}
27 \ No newline at end of file
@@ -33,6 +33,8 @@ Date: Thu Feb 28 10:44:48 2013 +0100
33 initial
34
35 diff --git a/a.c b/a.c
36 +new file mode 100644
37 +index 0000000..9f550c3
38 --- /dev/null
39 +++ b/a.c
40 @@ -0,0 +20,1 @@