summaryrefslogtreecommitdiff
path: root/combine-diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'combine-diff.c')
-rw-r--r--combine-diff.c439
1 files changed, 327 insertions, 112 deletions
diff --git a/combine-diff.c b/combine-diff.c
index bb1cc96c4e..24ca7e2334 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -5,19 +5,20 @@
#include "diffcore.h"
#include "quote.h"
#include "xdiff-interface.h"
+#include "xdiff/xmacros.h"
#include "log-tree.h"
#include "refs.h"
#include "userdiff.h"
#include "sha1-array.h"
+#include "revision.h"
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
{
struct diff_queue_struct *q = &diff_queued_diff;
- struct combine_diff_path *p;
- int i;
+ struct combine_diff_path *p, **tail = &curr;
+ int i, cmp;
if (!n) {
- struct combine_diff_path *list = NULL, **tail = &list;
for (i = 0; i < q->nr; i++) {
int len;
const char *path;
@@ -29,7 +30,6 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
p->path = (char *) &(p->parent[num_parent]);
memcpy(p->path, path, len);
p->path[len] = 0;
- p->len = len;
p->next = NULL;
memset(p->parent, 0,
sizeof(p->parent[0]) * num_parent);
@@ -42,47 +42,61 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
*tail = p;
tail = &p->next;
}
- return list;
+ return curr;
}
- for (p = curr; p; p = p->next) {
- int found = 0;
- if (!p->len)
+ /*
+ * paths in curr (linked list) and q->queue[] (array) are
+ * both sorted in the tree order.
+ */
+ i = 0;
+ while ((p = *tail) != NULL) {
+ cmp = ((i >= q->nr)
+ ? -1 : strcmp(p->path, q->queue[i]->two->path));
+
+ if (cmp < 0) {
+ /* p->path not in q->queue[]; drop it */
+ *tail = p->next;
+ free(p);
continue;
- for (i = 0; i < q->nr; i++) {
- const char *path;
- int len;
+ }
- if (diff_unmodified_pair(q->queue[i]))
- continue;
- path = q->queue[i]->two->path;
- len = strlen(path);
- if (len == p->len && !memcmp(path, p->path, len)) {
- found = 1;
- hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1);
- p->parent[n].mode = q->queue[i]->one->mode;
- p->parent[n].status = q->queue[i]->status;
- break;
- }
+ if (cmp > 0) {
+ /* q->queue[i] not in p->path; skip it */
+ i++;
+ continue;
}
- if (!found)
- p->len = 0;
+
+ hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1);
+ p->parent[n].mode = q->queue[i]->one->mode;
+ p->parent[n].status = q->queue[i]->status;
+
+ tail = &p->next;
+ i++;
}
return curr;
}
/* Lines lost from parent */
struct lline {
- struct lline *next;
+ struct lline *next, *prev;
int len;
unsigned long parent_map;
char line[FLEX_ARRAY];
};
+/* Lines lost from current parent (before coalescing) */
+struct plost {
+ struct lline *lost_head, *lost_tail;
+ int len;
+};
+
/* Lines surviving in the merge result */
struct sline {
- struct lline *lost_head, **lost_tail;
- struct lline *next_lost;
+ /* Accumulated and coalesced lost lines */
+ struct lline *lost;
+ int lenlost;
+ struct plost plost;
char *bol;
int len;
/* bit 0 up to (N-1) are on if the parent has this line (i.e.
@@ -94,6 +108,172 @@ struct sline {
unsigned long *p_lno;
};
+static int match_string_spaces(const char *line1, int len1,
+ const char *line2, int len2,
+ long flags)
+{
+ if (flags & XDF_WHITESPACE_FLAGS) {
+ for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
+ for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
+ }
+
+ if (!(flags & (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE)))
+ return (len1 == len2 && !memcmp(line1, line2, len1));
+
+ while (len1 > 0 && len2 > 0) {
+ len1--;
+ len2--;
+ if (XDL_ISSPACE(line1[len1]) || XDL_ISSPACE(line2[len2])) {
+ if ((flags & XDF_IGNORE_WHITESPACE_CHANGE) &&
+ (!XDL_ISSPACE(line1[len1]) || !XDL_ISSPACE(line2[len2])))
+ return 0;
+
+ for (; len1 > 0 && XDL_ISSPACE(line1[len1]); len1--);
+ for (; len2 > 0 && XDL_ISSPACE(line2[len2]); len2--);
+ }
+ if (line1[len1] != line2[len2])
+ return 0;
+ }
+
+ if (flags & XDF_IGNORE_WHITESPACE) {
+ /* Consume remaining spaces */
+ for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
+ for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
+ }
+
+ /* We matched full line1 and line2 */
+ if (!len1 && !len2)
+ return 1;
+
+ return 0;
+}
+
+enum coalesce_direction { MATCH, BASE, NEW };
+
+/* Coalesce new lines into base by finding LCS */
+static struct lline *coalesce_lines(struct lline *base, int *lenbase,
+ struct lline *new, int lennew,
+ unsigned long parent, long flags)
+{
+ int **lcs;
+ enum coalesce_direction **directions;
+ struct lline *baseend, *newend = NULL;
+ int i, j, origbaselen = *lenbase;
+
+ if (new == NULL)
+ return base;
+
+ if (base == NULL) {
+ *lenbase = lennew;
+ return new;
+ }
+
+ /*
+ * Coalesce new lines into base by finding the LCS
+ * - Create the table to run dynamic programming
+ * - Compute the LCS
+ * - Then reverse read the direction structure:
+ * - If we have MATCH, assign parent to base flag, and consume
+ * both baseend and newend
+ * - Else if we have BASE, consume baseend
+ * - Else if we have NEW, insert newend lline into base and
+ * consume newend
+ */
+ lcs = xcalloc(origbaselen + 1, sizeof(int*));
+ directions = xcalloc(origbaselen + 1, sizeof(enum coalesce_direction*));
+ for (i = 0; i < origbaselen + 1; i++) {
+ lcs[i] = xcalloc(lennew + 1, sizeof(int));
+ directions[i] = xcalloc(lennew + 1, sizeof(enum coalesce_direction));
+ directions[i][0] = BASE;
+ }
+ for (j = 1; j < lennew + 1; j++)
+ directions[0][j] = NEW;
+
+ for (i = 1, baseend = base; i < origbaselen + 1; i++) {
+ for (j = 1, newend = new; j < lennew + 1; j++) {
+ if (match_string_spaces(baseend->line, baseend->len,
+ newend->line, newend->len, flags)) {
+ lcs[i][j] = lcs[i - 1][j - 1] + 1;
+ directions[i][j] = MATCH;
+ } else if (lcs[i][j - 1] >= lcs[i - 1][j]) {
+ lcs[i][j] = lcs[i][j - 1];
+ directions[i][j] = NEW;
+ } else {
+ lcs[i][j] = lcs[i - 1][j];
+ directions[i][j] = BASE;
+ }
+ if (newend->next)
+ newend = newend->next;
+ }
+ if (baseend->next)
+ baseend = baseend->next;
+ }
+
+ for (i = 0; i < origbaselen + 1; i++)
+ free(lcs[i]);
+ free(lcs);
+
+ /* At this point, baseend and newend point to the end of each lists */
+ i--;
+ j--;
+ while (i != 0 || j != 0) {
+ if (directions[i][j] == MATCH) {
+ baseend->parent_map |= 1<<parent;
+ baseend = baseend->prev;
+ newend = newend->prev;
+ i--;
+ j--;
+ } else if (directions[i][j] == NEW) {
+ struct lline *lline;
+
+ lline = newend;
+ /* Remove lline from new list and update newend */
+ if (lline->prev)
+ lline->prev->next = lline->next;
+ else
+ new = lline->next;
+ if (lline->next)
+ lline->next->prev = lline->prev;
+
+ newend = lline->prev;
+ j--;
+
+ /* Add lline to base list */
+ if (baseend) {
+ lline->next = baseend->next;
+ lline->prev = baseend;
+ if (lline->prev)
+ lline->prev->next = lline;
+ }
+ else {
+ lline->next = base;
+ base = lline;
+ }
+ (*lenbase)++;
+
+ if (lline->next)
+ lline->next->prev = lline;
+
+ } else {
+ baseend = baseend->prev;
+ i--;
+ }
+ }
+
+ newend = new;
+ while (newend) {
+ struct lline *lline = newend;
+ newend = newend->next;
+ free(lline);
+ }
+
+ for (i = 0; i < origbaselen + 1; i++)
+ free(directions[i]);
+ free(directions);
+
+ return base;
+}
+
static char *grab_blob(const unsigned char *sha1, unsigned int mode,
unsigned long *size, struct userdiff_driver *textconv,
const char *path)
@@ -129,29 +309,19 @@ static void append_lost(struct sline *sline, int n, const char *line, int len)
if (line[len-1] == '\n')
len--;
- /* Check to see if we can squash things */
- if (sline->lost_head) {
- lline = sline->next_lost;
- while (lline) {
- if (lline->len == len &&
- !memcmp(lline->line, line, len)) {
- lline->parent_map |= this_mask;
- sline->next_lost = lline->next;
- return;
- }
- lline = lline->next;
- }
- }
-
lline = xmalloc(sizeof(*lline) + len + 1);
lline->len = len;
lline->next = NULL;
+ lline->prev = sline->plost.lost_tail;
+ if (lline->prev)
+ lline->prev->next = lline;
+ else
+ sline->plost.lost_head = lline;
+ sline->plost.lost_tail = lline;
+ sline->plost.len++;
lline->parent_map = this_mask;
memcpy(lline->line, line, len);
lline->line[len] = 0;
- *sline->lost_tail = lline;
- sline->lost_tail = &lline->next;
- sline->next_lost = NULL;
}
struct combine_diff_state {
@@ -194,7 +364,6 @@ static void consume_line(void *state_, char *line, unsigned long len)
xcalloc(state->num_parent,
sizeof(unsigned long));
state->sline[state->nb-1].p_lno[state->n] = state->ob;
- state->lost_bucket->next_lost = state->lost_bucket->lost_head;
return;
}
if (!state->lost_bucket)
@@ -215,7 +384,7 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
struct sline *sline, unsigned int cnt, int n,
int num_parent, int result_deleted,
struct userdiff_driver *textconv,
- const char *path)
+ const char *path, long flags)
{
unsigned int p_lno, lno;
unsigned long nmask = (1UL << n);
@@ -231,7 +400,7 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
parent_file.ptr = grab_blob(parent, mode, &sz, textconv, path);
parent_file.size = sz;
memset(&xpp, 0, sizeof(xpp));
- xpp.flags = 0;
+ xpp.flags = flags;
memset(&xecfg, 0, sizeof(xecfg));
memset(&state, 0, sizeof(state));
state.nmask = nmask;
@@ -255,8 +424,18 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
struct lline *ll;
sline[lno].p_lno[n] = p_lno;
+ /* Coalesce new lines */
+ if (sline[lno].plost.lost_head) {
+ struct sline *sl = &sline[lno];
+ sl->lost = coalesce_lines(sl->lost, &sl->lenlost,
+ sl->plost.lost_head,
+ sl->plost.len, n, flags);
+ sl->plost.lost_head = sl->plost.lost_tail = NULL;
+ sl->plost.len = 0;
+ }
+
/* How many lines would this sline advance the p_lno? */
- ll = sline[lno].lost_head;
+ ll = sline[lno].lost;
while (ll) {
if (ll->parent_map & nmask)
p_lno++; /* '-' means parent had it */
@@ -276,7 +455,7 @@ static int interesting(struct sline *sline, unsigned long all_mask)
/* If some parents lost lines here, or if we have added to
* some parent, it is interesting.
*/
- return ((sline->flag & all_mask) || sline->lost_head);
+ return ((sline->flag & all_mask) || sline->lost);
}
static unsigned long adjust_hunk_tail(struct sline *sline,
@@ -344,8 +523,11 @@ static int give_context(struct sline *sline, unsigned long cnt, int num_parent)
unsigned long k;
/* Paint a few lines before the first interesting line. */
- while (j < i)
- sline[j++].flag |= mark | no_pre_delete;
+ while (j < i) {
+ if (!(sline[j].flag & mark))
+ sline[j].flag |= no_pre_delete;
+ sline[j++].flag |= mark;
+ }
again:
/* we know up to i is to be included. where does the
@@ -459,7 +641,7 @@ static int make_hunks(struct sline *sline, unsigned long cnt,
has_interesting = 0;
for (j = i; j < hunk_end && !has_interesting; j++) {
unsigned long this_diff = sline[j].flag & all_mask;
- struct lline *ll = sline[j].lost_head;
+ struct lline *ll = sline[j].lost;
if (this_diff) {
/* This has some changes. Is it the
* same as others?
@@ -526,7 +708,8 @@ static void show_line_to_eol(const char *line, int len, const char *reset)
saw_cr_at_eol ? "\r" : "");
}
-static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
+static void dump_sline(struct sline *sline, const char *line_prefix,
+ unsigned long cnt, int num_parent,
int use_color, int result_deleted)
{
unsigned long mark = (1UL<<num_parent);
@@ -582,7 +765,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
rlines -= null_context;
}
- fputs(c_frag, stdout);
+ printf("%s%s", line_prefix, c_frag);
for (i = 0; i <= num_parent; i++) putchar(combine_marker);
for (i = 0; i < num_parent; i++)
show_parent_lno(sline, lno, hunk_end, i, null_context);
@@ -612,9 +795,9 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
int j;
unsigned long p_mask;
struct sline *sl = &sline[lno++];
- ll = (sl->flag & no_pre_delete) ? NULL : sl->lost_head;
+ ll = (sl->flag & no_pre_delete) ? NULL : sl->lost;
while (ll) {
- fputs(c_old, stdout);
+ printf("%s%s", line_prefix, c_old);
for (j = 0; j < num_parent; j++) {
if (ll->parent_map & (1UL<<j))
putchar('-');
@@ -627,6 +810,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
if (cnt < lno)
break;
p_mask = 1;
+ fputs(line_prefix, stdout);
if (!(sl->flag & (mark-1))) {
/*
* This sline was here to hang the
@@ -662,7 +846,7 @@ static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
jmask = (1UL<<j);
for (lno = 0; lno <= cnt; lno++) {
- struct lline *ll = sline->lost_head;
+ struct lline *ll = sline->lost;
sline->p_lno[i] = sline->p_lno[j];
while (ll) {
if (ll->parent_map & jmask)
@@ -680,11 +864,13 @@ static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
static void dump_quoted_path(const char *head,
const char *prefix,
const char *path,
+ const char *line_prefix,
const char *c_meta, const char *c_reset)
{
static struct strbuf buf = STRBUF_INIT;
strbuf_reset(&buf);
+ strbuf_addstr(&buf, line_prefix);
strbuf_addstr(&buf, c_meta);
strbuf_addstr(&buf, head);
quote_two_c_style(&buf, prefix, path, 0);
@@ -696,6 +882,7 @@ static void show_combined_header(struct combine_diff_path *elem,
int num_parent,
int dense,
struct rev_info *rev,
+ const char *line_prefix,
int mode_differs,
int show_file_header)
{
@@ -714,8 +901,8 @@ static void show_combined_header(struct combine_diff_path *elem,
show_log(rev);
dump_quoted_path(dense ? "diff --cc " : "diff --combined ",
- "", elem->path, c_meta, c_reset);
- printf("%sindex ", c_meta);
+ "", elem->path, line_prefix, c_meta, c_reset);
+ printf("%s%sindex ", line_prefix, c_meta);
for (i = 0; i < num_parent; i++) {
abb = find_unique_abbrev(elem->parent[i].sha1,
abbrev);
@@ -734,11 +921,12 @@ static void show_combined_header(struct combine_diff_path *elem,
DIFF_STATUS_ADDED)
added = 0;
if (added)
- printf("%snew file mode %06o",
- c_meta, elem->mode);
+ printf("%s%snew file mode %06o",
+ line_prefix, c_meta, elem->mode);
else {
if (deleted)
- printf("%sdeleted file ", c_meta);
+ printf("%s%sdeleted file ",
+ line_prefix, c_meta);
printf("mode ");
for (i = 0; i < num_parent; i++) {
printf("%s%06o", i ? "," : "",
@@ -755,16 +943,16 @@ static void show_combined_header(struct combine_diff_path *elem,
if (added)
dump_quoted_path("--- ", "", "/dev/null",
- c_meta, c_reset);
+ line_prefix, c_meta, c_reset);
else
dump_quoted_path("--- ", a_prefix, elem->path,
- c_meta, c_reset);
+ line_prefix, c_meta, c_reset);
if (deleted)
dump_quoted_path("+++ ", "", "/dev/null",
- c_meta, c_reset);
+ line_prefix, c_meta, c_reset);
else
dump_quoted_path("+++ ", b_prefix, elem->path,
- c_meta, c_reset);
+ line_prefix, c_meta, c_reset);
}
static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
@@ -782,6 +970,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
struct userdiff_driver *userdiff;
struct userdiff_driver *textconv = NULL;
int is_binary;
+ const char *line_prefix = diff_line_prefix(opt);
context = opt->context;
userdiff = userdiff_find_by_path(elem->path);
@@ -901,7 +1090,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
}
if (is_binary) {
show_combined_header(elem, num_parent, dense, rev,
- mode_differs, 0);
+ line_prefix, mode_differs, 0);
printf("Binary files differ\n");
free(result);
return;
@@ -916,10 +1105,6 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
sline = xcalloc(cnt+2, sizeof(*sline));
sline[0].bol = result;
- for (lno = 0; lno <= cnt + 1; lno++) {
- sline[lno].lost_tail = &sline[lno].lost_head;
- sline[lno].flag = 0;
- }
for (lno = 0, cp = result; cp < result + result_size; cp++) {
if (*cp == '\n') {
sline[lno].len = cp - sline[lno].bol;
@@ -955,22 +1140,22 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
elem->parent[i].mode,
&result_file, sline,
cnt, i, num_parent, result_deleted,
- textconv, elem->path);
+ textconv, elem->path, opt->xdl_opts);
}
show_hunks = make_hunks(sline, cnt, num_parent, dense);
if (show_hunks || mode_differs || working_tree_file) {
show_combined_header(elem, num_parent, dense, rev,
- mode_differs, 1);
- dump_sline(sline, cnt, num_parent,
+ line_prefix, mode_differs, 1);
+ dump_sline(sline, line_prefix, cnt, num_parent,
opt->use_color, result_deleted);
}
free(result);
for (lno = 0; lno < cnt; lno++) {
- if (sline[lno].lost_head) {
- struct lline *ll = sline[lno].lost_head;
+ if (sline[lno].lost) {
+ struct lline *ll = sline[lno].lost;
while (ll) {
struct lline *tmp = ll;
ll = ll->next;
@@ -982,14 +1167,11 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
free(sline);
}
-#define COLONS "::::::::::::::::::::::::::::::::"
-
static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
- int i, offset;
- const char *prefix;
- int line_termination, inter_name_termination;
+ int line_termination, inter_name_termination, i;
+ const char *line_prefix = diff_line_prefix(opt);
line_termination = opt->line_termination;
inter_name_termination = '\t';
@@ -999,18 +1181,18 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
if (rev->loginfo && !rev->no_commit_id)
show_log(rev);
+
if (opt->output_format & DIFF_FORMAT_RAW) {
- offset = strlen(COLONS) - num_parent;
- if (offset < 0)
- offset = 0;
- prefix = COLONS + offset;
+ printf("%s", line_prefix);
+
+ /* As many colons as there are parents */
+ for (i = 0; i < num_parent; i++)
+ putchar(':');
/* Show the modes */
- for (i = 0; i < num_parent; i++) {
- printf("%s%06o", prefix, p->parent[i].mode);
- prefix = " ";
- }
- printf("%s%06o", prefix, p->mode);
+ for (i = 0; i < num_parent; i++)
+ printf("%06o ", p->parent[i].mode);
+ printf("%06o", p->mode);
/* Show sha1's */
for (i = 0; i < num_parent; i++)
@@ -1040,8 +1222,7 @@ void show_combined_diff(struct combine_diff_path *p,
struct rev_info *rev)
{
struct diff_options *opt = &rev->diffopt;
- if (!p->len)
- return;
+
if (opt->output_format & (DIFF_FORMAT_RAW |
DIFF_FORMAT_NAME |
DIFF_FORMAT_NAME_STATUS))
@@ -1105,17 +1286,21 @@ static void handle_combined_callback(struct diff_options *opt,
q.queue = xcalloc(num_paths, sizeof(struct diff_filepair *));
q.alloc = num_paths;
q.nr = num_paths;
- for (i = 0, p = paths; p; p = p->next) {
- if (!p->len)
- continue;
+ for (i = 0, p = paths; p; p = p->next)
q.queue[i++] = combined_pair(p, num_parent);
- }
opt->format_callback(&q, opt, opt->format_callback_data);
for (i = 0; i < num_paths; i++)
free_combined_pair(q.queue[i]);
free(q.queue);
}
+static const char *path_path(void *obj)
+{
+ struct combine_diff_path *path = (struct combine_diff_path *)obj;
+
+ return path->path;
+}
+
void diff_tree_combined(const unsigned char *sha1,
const struct sha1_array *parents,
int dense,
@@ -1127,9 +1312,12 @@ void diff_tree_combined(const unsigned char *sha1,
int i, num_paths, needsep, show_log_first, num_parent = parents->nr;
diffopts = *opt;
+ copy_pathspec(&diffopts.pathspec, &opt->pathspec);
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
DIFF_OPT_SET(&diffopts, RECURSIVE);
DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
+ /* tell diff_tree to emit paths in sorted (=tree) order */
+ diffopts.orderfile = NULL;
show_log_first = !!rev->loginfo && !rev->no_commit_id;
needsep = 0;
@@ -1150,25 +1338,51 @@ void diff_tree_combined(const unsigned char *sha1,
if (show_log_first && i == 0) {
show_log(rev);
+
if (rev->verbose_header && opt->output_format)
- putchar(opt->line_termination);
+ printf("%s%c", diff_line_prefix(opt),
+ opt->line_termination);
+ }
+
+ /* if showing diff, show it in requested order */
+ if (diffopts.output_format != DIFF_FORMAT_NO_OUTPUT &&
+ opt->orderfile) {
+ diffcore_order(opt->orderfile);
}
+
diff_flush(&diffopts);
}
- /* find out surviving paths */
- for (num_paths = 0, p = paths; p; p = p->next) {
- if (p->len)
- num_paths++;
+ /* find out number of surviving paths */
+ for (num_paths = 0, p = paths; p; p = p->next)
+ num_paths++;
+
+ /* order paths according to diffcore_order */
+ if (opt->orderfile && num_paths) {
+ struct obj_order *o;
+
+ o = xmalloc(sizeof(*o) * num_paths);
+ for (i = 0, p = paths; p; p = p->next, i++)
+ o[i].obj = p;
+ order_objects(opt->orderfile, path_path, o, num_paths);
+ for (i = 0; i < num_paths - 1; i++) {
+ p = o[i].obj;
+ p->next = o[i+1].obj;
+ }
+
+ p = o[num_paths-1].obj;
+ p->next = NULL;
+ paths = o[0].obj;
+ free(o);
}
+
+
if (num_paths) {
if (opt->output_format & (DIFF_FORMAT_RAW |
DIFF_FORMAT_NAME |
DIFF_FORMAT_NAME_STATUS)) {
- for (p = paths; p; p = p->next) {
- if (p->len)
- show_raw_diff(p, num_parent, rev);
- }
+ for (p = paths; p; p = p->next)
+ show_raw_diff(p, num_parent, rev);
needsep = 1;
}
else if (opt->output_format &
@@ -1179,12 +1393,11 @@ void diff_tree_combined(const unsigned char *sha1,
if (opt->output_format & DIFF_FORMAT_PATCH) {
if (needsep)
- putchar(opt->line_termination);
- for (p = paths; p; p = p->next) {
- if (p->len)
- show_patch_diff(p, num_parent, dense,
- 0, rev);
- }
+ printf("%s%c", diff_line_prefix(opt),
+ opt->line_termination);
+ for (p = paths; p; p = p->next)
+ show_patch_diff(p, num_parent, dense,
+ 0, rev);
}
}
@@ -1194,12 +1407,14 @@ void diff_tree_combined(const unsigned char *sha1,
paths = paths->next;
free(tmp);
}
+
+ free_pathspec(&diffopts.pathspec);
}
void diff_tree_combined_merge(const struct commit *commit, int dense,
struct rev_info *rev)
{
- struct commit_list *parent = commit->parents;
+ struct commit_list *parent = get_saved_parents(rev, commit);
struct sha1_array parents = SHA1_ARRAY_INIT;
while (parent) {