combine-diff: show mode changes as well.
[git.git] / combine-diff.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "diff.h"
4 #include "diffcore.h"
5 #include "quote.h"
6
7 static int uninteresting(struct diff_filepair *p)
8 {
9         if (diff_unmodified_pair(p))
10                 return 1;
11         if (!S_ISREG(p->one->mode) || !S_ISREG(p->two->mode))
12                 return 1;
13         return 0;
14 }
15
16 static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
17 {
18         struct diff_queue_struct *q = &diff_queued_diff;
19         struct combine_diff_path *p;
20         int i;
21
22         if (!n) {
23                 struct combine_diff_path *list = NULL, **tail = &list;
24                 for (i = 0; i < q->nr; i++) {
25                         int len;
26                         const char *path;
27                         if (uninteresting(q->queue[i]))
28                                 continue;
29                         path = q->queue[i]->two->path;
30                         len = strlen(path);
31                         p = xmalloc(combine_diff_path_size(num_parent, len));
32                         p->path = (char*) &(p->parent[num_parent]);
33                         memcpy(p->path, path, len);
34                         p->path[len] = 0;
35                         p->len = len;
36                         p->next = NULL;
37                         memset(p->parent, 0,
38                                sizeof(p->parent[0]) * num_parent);
39
40                         memcpy(p->sha1, q->queue[i]->two->sha1, 20);
41                         p->mode = q->queue[i]->two->mode;
42                         memcpy(p->parent[n].sha1, q->queue[i]->one->sha1, 20);
43                         p->parent[n].mode = q->queue[i]->one->mode;
44                         *tail = p;
45                         tail = &p->next;
46                 }
47                 return list;
48         }
49
50         for (p = curr; p; p = p->next) {
51                 int found = 0;
52                 if (!p->len)
53                         continue;
54                 for (i = 0; i < q->nr; i++) {
55                         const char *path;
56                         int len;
57
58                         if (uninteresting(q->queue[i]))
59                                 continue;
60                         path = q->queue[i]->two->path;
61                         len = strlen(path);
62                         if (len == p->len && !memcmp(path, p->path, len)) {
63                                 found = 1;
64                                 memcpy(p->parent[n].sha1,
65                                        q->queue[i]->one->sha1, 20);
66                                 p->parent[n].mode = q->queue[i]->one->mode;
67                                 break;
68                         }
69                 }
70                 if (!found)
71                         p->len = 0;
72         }
73         return curr;
74 }
75
76 /* Lines lost from parent */
77 struct lline {
78         struct lline *next;
79         int len;
80         unsigned long parent_map;
81         char line[FLEX_ARRAY];
82 };
83
84 /* Lines surviving in the merge result */
85 struct sline {
86         struct lline *lost_head, **lost_tail;
87         char *bol;
88         int len;
89         /* bit 0 up to (N-1) are on if the parent has this line (i.e.
90          * we did not change it).
91          * bit N is used for "interesting" lines, including context.
92          */
93         unsigned long flag;
94         unsigned long *p_lno;
95 };
96
97 static char *grab_blob(const unsigned char *sha1, unsigned long *size)
98 {
99         char *blob;
100         char type[20];
101         if (!memcmp(sha1, null_sha1, 20)) {
102                 /* deleted blob */
103                 *size = 0;
104                 return xcalloc(1, 1);
105         }
106         blob = read_sha1_file(sha1, type, size);
107         if (strcmp(type, "blob"))
108                 die("object '%s' is not a blob!", sha1_to_hex(sha1));
109         return blob;
110 }
111
112 #define TMPPATHLEN 50
113 #define MAXLINELEN 10240
114
115 static void write_to_temp_file(char *tmpfile, void *blob, unsigned long size)
116 {
117         int fd = git_mkstemp(tmpfile, TMPPATHLEN, ".diff_XXXXXX");
118         if (fd < 0)
119                 die("unable to create temp-file");
120         if (write(fd, blob, size) != size)
121                 die("unable to write temp-file");
122         close(fd);
123 }
124
125 static void write_temp_blob(char *tmpfile, const unsigned char *sha1)
126 {
127         unsigned long size;
128         void *blob;
129         blob = grab_blob(sha1, &size);
130         write_to_temp_file(tmpfile, blob, size);
131         free(blob);
132 }
133
134 static int parse_num(char **cp_p, unsigned int *num_p)
135 {
136         char *cp = *cp_p;
137         unsigned int num = 0;
138         int read_some;
139
140         while ('0' <= *cp && *cp <= '9')
141                 num = num * 10 + *cp++ - '0';
142         if (!(read_some = cp - *cp_p))
143                 return -1;
144         *cp_p = cp;
145         *num_p = num;
146         return 0;
147 }
148
149 static int parse_hunk_header(char *line, int len,
150                              unsigned int *ob, unsigned int *on,
151                              unsigned int *nb, unsigned int *nn)
152 {
153         char *cp;
154         cp = line + 4;
155         if (parse_num(&cp, ob)) {
156         bad_line:
157                 return error("malformed diff output: %s", line);
158         }
159         if (*cp == ',') {
160                 cp++;
161                 if (parse_num(&cp, on))
162                         goto bad_line;
163         }
164         else
165                 *on = 1;
166         if (*cp++ != ' ' || *cp++ != '+')
167                 goto bad_line;
168         if (parse_num(&cp, nb))
169                 goto bad_line;
170         if (*cp == ',') {
171                 cp++;
172                 if (parse_num(&cp, nn))
173                         goto bad_line;
174         }
175         else
176                 *nn = 1;
177         return -!!memcmp(cp, " @@", 3);
178 }
179
180 static void append_lost(struct sline *sline, int n, const char *line)
181 {
182         struct lline *lline;
183         int len = strlen(line);
184         unsigned long this_mask = (1UL<<n);
185         if (line[len-1] == '\n')
186                 len--;
187
188         /* Check to see if we can squash things */
189         if (sline->lost_head) {
190                 struct lline *last_one = NULL;
191                 /* We cannot squash it with earlier one */
192                 for (lline = sline->lost_head;
193                      lline;
194                      lline = lline->next)
195                         if (lline->parent_map & this_mask)
196                                 last_one = lline;
197                 lline = last_one ? last_one->next : sline->lost_head;
198                 while (lline) {
199                         if (lline->len == len &&
200                             !memcmp(lline->line, line, len)) {
201                                 lline->parent_map |= this_mask;
202                                 return;
203                         }
204                         lline = lline->next;
205                 }
206         }
207
208         lline = xmalloc(sizeof(*lline) + len + 1);
209         lline->len = len;
210         lline->next = NULL;
211         lline->parent_map = this_mask;
212         memcpy(lline->line, line, len);
213         lline->line[len] = 0;
214         *sline->lost_tail = lline;
215         sline->lost_tail = &lline->next;
216 }
217
218 static void combine_diff(const unsigned char *parent, const char *ourtmp,
219                          struct sline *sline, int cnt, int n, int num_parent)
220 {
221         FILE *in;
222         char parent_tmp[TMPPATHLEN];
223         char cmd[TMPPATHLEN * 2 + 1024];
224         char line[MAXLINELEN];
225         unsigned int lno, ob, on, nb, nn, p_lno;
226         unsigned long nmask = (1UL << n);
227         struct sline *lost_bucket = NULL;
228
229         write_temp_blob(parent_tmp, parent);
230         sprintf(cmd, "diff --unified=0 -La/x -Lb/x '%s' '%s'",
231                 parent_tmp, ourtmp);
232         in = popen(cmd, "r");
233         if (!in)
234                 die("cannot spawn %s", cmd);
235
236         lno = 1;
237         while (fgets(line, sizeof(line), in) != NULL) {
238                 int len = strlen(line);
239                 if (5 < len && !memcmp("@@ -", line, 4)) {
240                         if (parse_hunk_header(line, len,
241                                               &ob, &on, &nb, &nn))
242                                 break;
243                         lno = nb;
244                         if (!nb)
245                                 /* @@ -1,2 +0,0 @@ to remove the
246                                  * first two lines...
247                                  */
248                                 nb = 1;
249                         if (nn == 0)
250                                 /* @@ -X,Y +N,0 @@ removed Y lines
251                                  * that would have come *after* line N
252                                  * in the result.  Our lost buckets hang
253                                  * to the line after the removed lines,
254                                  */
255                                 lost_bucket = &sline[nb];
256                         else
257                                 lost_bucket = &sline[nb-1];
258                         if (!sline[nb-1].p_lno)
259                                 sline[nb-1].p_lno =
260                                         xcalloc(num_parent,
261                                                 sizeof(unsigned long));
262                         sline[nb-1].p_lno[n] = ob;
263                         continue;
264                 }
265                 if (!lost_bucket)
266                         continue; /* not in any hunk yet */
267                 switch (line[0]) {
268                 case '-':
269                         append_lost(lost_bucket, n, line+1);
270                         break;
271                 case '+':
272                         sline[lno-1].flag |= nmask;
273                         lno++;
274                         break;
275                 }
276         }
277         fclose(in);
278         unlink(parent_tmp);
279
280         /* Assign line numbers for this parent.
281          *
282          * sline[lno].p_lno[n] records the first line number
283          * (counting from 1) for parent N if the final hunk display
284          * started by showing sline[lno] (possibly showing the lost
285          * lines attached to it first).
286          */
287         for (lno = 0,  p_lno = 1; lno < cnt; lno++) {
288                 struct lline *ll;
289                 sline[lno].p_lno[n] = p_lno;
290
291                 /* How many lines would this sline advance the p_lno? */
292                 ll = sline[lno].lost_head;
293                 while (ll) {
294                         if (ll->parent_map & nmask)
295                                 p_lno++; /* '-' means parent had it */
296                         ll = ll->next;
297                 }
298                 if (!(sline[lno].flag & nmask))
299                         p_lno++; /* no '+' means parent had it */
300         }
301         sline[lno].p_lno[n] = p_lno; /* trailer */
302 }
303
304 static unsigned long context = 3;
305 static char combine_marker = '@';
306
307 static int interesting(struct sline *sline, unsigned long all_mask)
308 {
309         /* If some parents lost lines here, or if we have added to
310          * some parent, it is interesting.
311          */
312         return ((sline->flag & all_mask) || sline->lost_head);
313 }
314
315 static unsigned long adjust_hunk_tail(struct sline *sline,
316                                       unsigned long all_mask,
317                                       unsigned long hunk_begin,
318                                       unsigned long i)
319 {
320         /* i points at the first uninteresting line.  If the last line
321          * of the hunk was interesting only because it has some
322          * deletion, then it is not all that interesting for the
323          * purpose of giving trailing context lines.  This is because
324          * we output '-' line and then unmodified sline[i-1] itself in
325          * that case which gives us one extra context line.
326          */
327         if ((hunk_begin + 1 <= i) && !(sline[i-1].flag & all_mask))
328                 i--;
329         return i;
330 }
331
332 static unsigned long find_next(struct sline *sline,
333                                unsigned long mark,
334                                unsigned long i,
335                                unsigned long cnt,
336                                int uninteresting)
337 {
338         /* We have examined up to i-1 and are about to look at i.
339          * Find next interesting or uninteresting line.  Here,
340          * "interesting" does not mean interesting(), but marked by
341          * the give_context() function below (i.e. it includes context
342          * lines that are not interesting to interesting() function
343          * that are surrounded by interesting() ones.
344          */
345         while (i < cnt)
346                 if (uninteresting
347                     ? !(sline[i].flag & mark)
348                     : (sline[i].flag & mark))
349                         return i;
350                 else
351                         i++;
352         return cnt;
353 }
354
355 static int give_context(struct sline *sline, unsigned long cnt, int num_parent)
356 {
357         unsigned long all_mask = (1UL<<num_parent) - 1;
358         unsigned long mark = (1UL<<num_parent);
359         unsigned long i;
360
361         /* Two groups of interesting lines may have a short gap of
362          * unintersting lines.  Connect such groups to give them a
363          * bit of context.
364          *
365          * We first start from what the interesting() function says,
366          * and mark them with "mark", and paint context lines with the
367          * mark.  So interesting() would still say false for such context
368          * lines but they are treated as "interesting" in the end.
369          */
370         i = find_next(sline, mark, 0, cnt, 0);
371         if (cnt <= i)
372                 return 0;
373
374         while (i < cnt) {
375                 unsigned long j = (context < i) ? (i - context) : 0;
376                 unsigned long k;
377
378                 /* Paint a few lines before the first interesting line. */
379                 while (j < i)
380                         sline[j++].flag |= mark;
381
382         again:
383                 /* we know up to i is to be included.  where does the
384                  * next uninteresting one start?
385                  */
386                 j = find_next(sline, mark, i, cnt, 1);
387                 if (cnt <= j)
388                         break; /* the rest are all interesting */
389
390                 /* lookahead context lines */
391                 k = find_next(sline, mark, j, cnt, 0);
392                 j = adjust_hunk_tail(sline, all_mask, i, j);
393
394                 if (k < j + context) {
395                         /* k is interesting and [j,k) are not, but
396                          * paint them interesting because the gap is small.
397                          */
398                         while (j < k)
399                                 sline[j++].flag |= mark;
400                         i = k;
401                         goto again;
402                 }
403
404                 /* j is the first uninteresting line and there is
405                  * no overlap beyond it within context lines.  Paint
406                  * the trailing edge a bit.
407                  */
408                 i = k;
409                 k = (j + context < cnt) ? j + context : cnt;
410                 while (j < k)
411                         sline[j++].flag |= mark;
412         }
413         return 1;
414 }
415
416 static int make_hunks(struct sline *sline, unsigned long cnt,
417                        int num_parent, int dense)
418 {
419         unsigned long all_mask = (1UL<<num_parent) - 1;
420         unsigned long mark = (1UL<<num_parent);
421         unsigned long i;
422         int has_interesting = 0;
423
424         for (i = 0; i < cnt; i++) {
425                 if (interesting(&sline[i], all_mask))
426                         sline[i].flag |= mark;
427                 else
428                         sline[i].flag &= ~mark;
429         }
430         if (!dense)
431                 return give_context(sline, cnt, num_parent);
432
433         /* Look at each hunk, and if we have changes from only one
434          * parent, or the changes are the same from all but one
435          * parent, mark that uninteresting.
436          */
437         i = 0;
438         while (i < cnt) {
439                 unsigned long j, hunk_begin, hunk_end;
440                 unsigned long same_diff;
441                 while (i < cnt && !(sline[i].flag & mark))
442                         i++;
443                 if (cnt <= i)
444                         break; /* No more interesting hunks */
445                 hunk_begin = i;
446                 for (j = i + 1; j < cnt; j++) {
447                         if (!(sline[j].flag & mark)) {
448                                 /* Look beyond the end to see if there
449                                  * is an interesting line after this
450                                  * hunk within context span.
451                                  */
452                                 unsigned long la; /* lookahead */
453                                 int contin = 0;
454                                 la = adjust_hunk_tail(sline, all_mask,
455                                                      hunk_begin, j);
456                                 la = (la + context < cnt) ?
457                                         (la + context) : cnt;
458                                 while (j <= --la) {
459                                         if (sline[la].flag & mark) {
460                                                 contin = 1;
461                                                 break;
462                                         }
463                                 }
464                                 if (!contin)
465                                         break;
466                                 j = la;
467                         }
468                 }
469                 hunk_end = j;
470
471                 /* [i..hunk_end) are interesting.  Now is it really
472                  * interesting?  We check if there are only two versions
473                  * and the result matches one of them.  That is, we look
474                  * at:
475                  *   (+) line, which records lines added to which parents;
476                  *       this line appears in the result.
477                  *   (-) line, which records from what parents the line
478                  *       was removed; this line does not appear in the result.
479                  * then check the set of parents the result has difference
480                  * from, from all lines.  If there are lines that has
481                  * different set of parents that the result has differences
482                  * from, that means we have more than two versions.
483                  *
484                  * Even when we have only two versions, if the result does
485                  * not match any of the parents, the it should be considered
486                  * interesting.  In such a case, we would have all '+' line.
487                  * After passing the above "two versions" test, that would
488                  * appear as "the same set of parents" to be "all parents".
489                  */
490                 same_diff = 0;
491                 has_interesting = 0;
492                 for (j = i; j < hunk_end && !has_interesting; j++) {
493                         unsigned long this_diff = sline[j].flag & all_mask;
494                         struct lline *ll = sline[j].lost_head;
495                         if (this_diff) {
496                                 /* This has some changes.  Is it the
497                                  * same as others?
498                                  */
499                                 if (!same_diff)
500                                         same_diff = this_diff;
501                                 else if (same_diff != this_diff) {
502                                         has_interesting = 1;
503                                         break;
504                                 }
505                         }
506                         while (ll && !has_interesting) {
507                                 /* Lost this line from these parents;
508                                  * who are they?  Are they the same?
509                                  */
510                                 this_diff = ll->parent_map;
511                                 if (!same_diff)
512                                         same_diff = this_diff;
513                                 else if (same_diff != this_diff) {
514                                         has_interesting = 1;
515                                 }
516                                 ll = ll->next;
517                         }
518                 }
519
520                 if (!has_interesting && same_diff != all_mask) {
521                         /* This hunk is not that interesting after all */
522                         for (j = hunk_begin; j < hunk_end; j++)
523                                 sline[j].flag &= ~mark;
524                 }
525                 i = hunk_end;
526         }
527
528         has_interesting = give_context(sline, cnt, num_parent);
529         return has_interesting;
530 }
531
532 static void show_parent_lno(struct sline *sline, unsigned long l0, unsigned long l1, unsigned long cnt, int n)
533 {
534         l0 = sline[l0].p_lno[n];
535         l1 = sline[l1].p_lno[n];
536         printf(" -%lu,%lu", l0, l1-l0);
537 }
538
539 static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent)
540 {
541         unsigned long mark = (1UL<<num_parent);
542         int i;
543         unsigned long lno = 0;
544
545         while (1) {
546                 struct sline *sl = &sline[lno];
547                 int hunk_end;
548                 while (lno < cnt && !(sline[lno].flag & mark))
549                         lno++;
550                 if (cnt <= lno)
551                         break;
552                 for (hunk_end = lno + 1; hunk_end < cnt; hunk_end++)
553                         if (!(sline[hunk_end].flag & mark))
554                                 break;
555                 for (i = 0; i <= num_parent; i++) putchar(combine_marker);
556                 for (i = 0; i < num_parent; i++)
557                         show_parent_lno(sline, lno, hunk_end, cnt, i);
558                 printf(" +%lu,%lu ", lno+1, hunk_end-lno);
559                 for (i = 0; i <= num_parent; i++) putchar(combine_marker);
560                 putchar('\n');
561                 while (lno < hunk_end) {
562                         struct lline *ll;
563                         int j;
564                         unsigned long p_mask;
565                         sl = &sline[lno++];
566                         ll = sl->lost_head;
567                         while (ll) {
568                                 for (j = 0; j < num_parent; j++) {
569                                         if (ll->parent_map & (1UL<<j))
570                                                 putchar('-');
571                                         else
572                                                 putchar(' ');
573                                 }
574                                 puts(ll->line);
575                                 ll = ll->next;
576                         }
577                         p_mask = 1;
578                         for (j = 0; j < num_parent; j++) {
579                                 if (p_mask & sl->flag)
580                                         putchar('+');
581                                 else
582                                         putchar(' ');
583                                 p_mask <<= 1;
584                         }
585                         printf("%.*s\n", sl->len, sl->bol);
586                 }
587         }
588 }
589
590 static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
591                                int i, int j)
592 {
593         /* We have already examined parent j and we know parent i
594          * and parent j are the same, so reuse the combined result
595          * of parent j for parent i.
596          */
597         unsigned long lno, imask, jmask;
598         imask = (1UL<<i);
599         jmask = (1UL<<j);
600
601         for (lno = 0; lno < cnt; lno++) {
602                 struct lline *ll = sline->lost_head;
603                 sline->p_lno[i] = sline->p_lno[j];
604                 while (ll) {
605                         if (ll->parent_map & jmask)
606                                 ll->parent_map |= imask;
607                         ll = ll->next;
608                 }
609                 if (sline->flag & jmask)
610                         sline->flag |= imask;
611                 sline++;
612         }
613 }
614
615 int show_combined_diff(struct combine_diff_path *elem, int num_parent,
616                        int dense, const char *header)
617 {
618         unsigned long size, cnt, lno;
619         char *result, *cp, *ep;
620         struct sline *sline; /* survived lines */
621         int mode_differs = 0;
622         int i, show_hunks, shown_header = 0;
623         char ourtmp_buf[TMPPATHLEN];
624         char *ourtmp = ourtmp_buf;
625
626         /* Read the result of merge first */
627         if (memcmp(elem->sha1, null_sha1, 20)) {
628                 result = grab_blob(elem->sha1, &size);
629                 write_to_temp_file(ourtmp, result, size);
630         }
631         else {
632                 /* Used by diff-tree to read from the working tree */
633                 struct stat st;
634                 int fd;
635                 ourtmp = elem->path;
636                 if (0 <= (fd = open(ourtmp, O_RDONLY)) &&
637                     !fstat(fd, &st)) {
638                         int len = st.st_size;
639                         int cnt = 0;
640
641                         size = len;
642                         result = xmalloc(len + 1);
643                         while (cnt < len) {
644                                 int done = xread(fd, result+cnt, len-cnt);
645                                 if (done == 0)
646                                         break;
647                                 if (done < 0)
648                                         die("read error '%s'", ourtmp);
649                                 cnt += done;
650                         }
651                         result[len] = 0;
652                 }
653                 else {
654                         /* deleted file */
655                         size = 0;
656                         result = xmalloc(1);
657                         result[0] = 0;
658                         ourtmp = "/dev/null";
659                 }
660                 if (0 <= fd)
661                         close(fd);
662         }
663
664         for (cnt = 0, cp = result; cp - result < size; cp++) {
665                 if (*cp == '\n')
666                         cnt++;
667         }
668         if (result[size-1] != '\n')
669                 cnt++; /* incomplete line */
670
671         sline = xcalloc(cnt+1, sizeof(*sline));
672         ep = result;
673         sline[0].bol = result;
674         for (lno = 0, cp = result; cp - result < size; cp++) {
675                 if (*cp == '\n') {
676                         sline[lno].lost_tail = &sline[lno].lost_head;
677                         sline[lno].len = cp - sline[lno].bol;
678                         sline[lno].flag = 0;
679                         lno++;
680                         if (lno < cnt)
681                                 sline[lno].bol = cp + 1;
682                 }
683         }
684         if (result[size-1] != '\n') {
685                 sline[cnt-1].lost_tail = &sline[cnt-1].lost_head;
686                 sline[cnt-1].len = size - (sline[cnt-1].bol - result);
687                 sline[cnt-1].flag = 0;
688         }
689
690         sline[0].p_lno = xcalloc((cnt+1) * num_parent, sizeof(unsigned long));
691         for (lno = 0; lno < cnt; lno++)
692                 sline[lno+1].p_lno = sline[lno].p_lno + num_parent;
693
694         for (i = 0; i < num_parent; i++) {
695                 int j;
696                 for (j = 0; j < i; j++) {
697                         if (!memcmp(elem->parent[i].sha1,
698                                     elem->parent[j].sha1, 20)) {
699                                 reuse_combine_diff(sline, cnt, i, j);
700                                 break;
701                         }
702                 }
703                 if (i <= j)
704                         combine_diff(elem->parent[i].sha1, ourtmp, sline,
705                                      cnt, i, num_parent);
706                 if (elem->parent[i].mode != elem->mode)
707                         mode_differs = 1;
708         }
709
710         show_hunks = make_hunks(sline, cnt, num_parent, dense);
711
712         if (show_hunks || mode_differs) {
713                 const char *abb;
714                 char null_abb[DEFAULT_ABBREV + 1];
715
716                 memset(null_abb, '0', DEFAULT_ABBREV);
717                 null_abb[DEFAULT_ABBREV] = 0;
718                 if (header) {
719                         shown_header++;
720                         puts(header);
721                 }
722                 printf("diff --%s ", dense ? "cc" : "combined");
723                 if (quote_c_style(elem->path, NULL, NULL, 0))
724                         quote_c_style(elem->path, NULL, stdout, 0);
725                 else
726                         printf("%s", elem->path);
727                 putchar('\n');
728                 printf("index ");
729                 for (i = 0; i < num_parent; i++) {
730                         if (elem->parent[i].mode != elem->mode)
731                                 mode_differs = 1;
732                         if (memcmp(elem->parent[i].sha1, null_sha1, 20))
733                                 abb = find_unique_abbrev(elem->parent[i].sha1,
734                                                          DEFAULT_ABBREV);
735                         else
736                                 abb = null_abb;
737                         printf("%s%s", i ? "," : "", abb);
738                 }
739                 if (memcmp(elem->sha1, null_sha1, 20))
740                         abb = find_unique_abbrev(elem->sha1, DEFAULT_ABBREV);
741                 else
742                         abb = null_abb;
743                 printf("..%s\n", abb);
744
745                 if (mode_differs) {
746                         printf("mode ");
747                         for (i = 0; i < num_parent; i++) {
748                                 printf("%s%06o", i ? "," : "",
749                                        elem->parent[i].mode);
750                         }
751                         printf("..%06o\n", elem->mode);
752                 }
753                 /* if (show_hunks) perhaps */
754                 dump_sline(sline, cnt, num_parent);
755         }
756         if (ourtmp == ourtmp_buf)
757                 unlink(ourtmp);
758         free(result);
759
760         for (i = 0; i < cnt; i++) {
761                 if (sline[i].lost_head) {
762                         struct lline *ll = sline[i].lost_head;
763                         while (ll) {
764                                 struct lline *tmp = ll;
765                                 ll = ll->next;
766                                 free(tmp);
767                         }
768                 }
769         }
770         free(sline[0].p_lno);
771         free(sline);
772         return shown_header;
773 }
774
775 int diff_tree_combined_merge(const unsigned char *sha1,
776                              const char *header, int dense)
777 {
778         struct commit *commit = lookup_commit(sha1);
779         struct diff_options diffopts;
780         struct commit_list *parents;
781         struct combine_diff_path *p, *paths = NULL;
782         int num_parent, i, num_paths;
783
784         diff_setup(&diffopts);
785         diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
786         diffopts.recursive = 1;
787
788         /* count parents */
789         for (parents = commit->parents, num_parent = 0;
790              parents;
791              parents = parents->next, num_parent++)
792                 ; /* nothing */
793
794         /* find set of paths that everybody touches */
795         for (parents = commit->parents, i = 0;
796              parents;
797              parents = parents->next, i++) {
798                 struct commit *parent = parents->item;
799                 diff_tree_sha1(parent->object.sha1, commit->object.sha1, "",
800                                &diffopts);
801                 paths = intersect_paths(paths, i, num_parent);
802                 diff_flush(&diffopts);
803         }
804
805         /* find out surviving paths */
806         for (num_paths = 0, p = paths; p; p = p->next) {
807                 if (p->len)
808                         num_paths++;
809         }
810         if (num_paths) {
811                 for (p = paths; p; p = p->next) {
812                         if (!p->len)
813                                 continue;
814                         if (show_combined_diff(p, num_parent, dense, header))
815                                 header = NULL;
816                 }
817         }
818
819         /* Clean things up */
820         while (paths) {
821                 struct combine_diff_path *tmp = paths;
822                 paths = paths->next;
823                 free(tmp);
824         }
825         return 0;
826 }