THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1616 lines
42KB

  1. #include "cache.h"
  2. #include "object-store.h"
  3. #include "commit.h"
  4. #include "blob.h"
  5. #include "diff.h"
  6. #include "diffcore.h"
  7. #include "quote.h"
  8. #include "xdiff-interface.h"
  9. #include "xdiff/xmacros.h"
  10. #include "log-tree.h"
  11. #include "refs.h"
  12. #include "userdiff.h"
  13. #include "sha1-array.h"
  14. #include "revision.h"
  15. static int compare_paths(const struct combine_diff_path *one,
  16. const struct diff_filespec *two)
  17. {
  18. if (!S_ISDIR(one->mode) && !S_ISDIR(two->mode))
  19. return strcmp(one->path, two->path);
  20. return base_name_compare(one->path, strlen(one->path), one->mode,
  21. two->path, strlen(two->path), two->mode);
  22. }
  23. static int filename_changed(char status)
  24. {
  25. return status == 'R' || status == 'C';
  26. }
  27. static struct combine_diff_path *intersect_paths(
  28. struct combine_diff_path *curr,
  29. int n,
  30. int num_parent,
  31. int combined_all_paths)
  32. {
  33. struct diff_queue_struct *q = &diff_queued_diff;
  34. struct combine_diff_path *p, **tail = &curr;
  35. int i, j, cmp;
  36. if (!n) {
  37. for (i = 0; i < q->nr; i++) {
  38. int len;
  39. const char *path;
  40. if (diff_unmodified_pair(q->queue[i]))
  41. continue;
  42. path = q->queue[i]->two->path;
  43. len = strlen(path);
  44. p = xmalloc(combine_diff_path_size(num_parent, len));
  45. p->path = (char *) &(p->parent[num_parent]);
  46. memcpy(p->path, path, len);
  47. p->path[len] = 0;
  48. p->next = NULL;
  49. memset(p->parent, 0,
  50. sizeof(p->parent[0]) * num_parent);
  51. oidcpy(&p->oid, &q->queue[i]->two->oid);
  52. p->mode = q->queue[i]->two->mode;
  53. oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
  54. p->parent[n].mode = q->queue[i]->one->mode;
  55. p->parent[n].status = q->queue[i]->status;
  56. if (combined_all_paths &&
  57. filename_changed(p->parent[n].status)) {
  58. strbuf_init(&p->parent[n].path, 0);
  59. strbuf_addstr(&p->parent[n].path,
  60. q->queue[i]->one->path);
  61. }
  62. *tail = p;
  63. tail = &p->next;
  64. }
  65. return curr;
  66. }
  67. /*
  68. * paths in curr (linked list) and q->queue[] (array) are
  69. * both sorted in the tree order.
  70. */
  71. i = 0;
  72. while ((p = *tail) != NULL) {
  73. cmp = ((i >= q->nr)
  74. ? -1 : compare_paths(p, q->queue[i]->two));
  75. if (cmp < 0) {
  76. /* p->path not in q->queue[]; drop it */
  77. *tail = p->next;
  78. for (j = 0; j < num_parent; j++)
  79. if (combined_all_paths &&
  80. filename_changed(p->parent[j].status))
  81. strbuf_release(&p->parent[j].path);
  82. free(p);
  83. continue;
  84. }
  85. if (cmp > 0) {
  86. /* q->queue[i] not in p->path; skip it */
  87. i++;
  88. continue;
  89. }
  90. oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
  91. p->parent[n].mode = q->queue[i]->one->mode;
  92. p->parent[n].status = q->queue[i]->status;
  93. if (combined_all_paths &&
  94. filename_changed(p->parent[n].status))
  95. strbuf_addstr(&p->parent[n].path,
  96. q->queue[i]->one->path);
  97. tail = &p->next;
  98. i++;
  99. }
  100. return curr;
  101. }
  102. /* Lines lost from parent */
  103. struct lline {
  104. struct lline *next, *prev;
  105. int len;
  106. unsigned long parent_map;
  107. char line[FLEX_ARRAY];
  108. };
  109. /* Lines lost from current parent (before coalescing) */
  110. struct plost {
  111. struct lline *lost_head, *lost_tail;
  112. int len;
  113. };
  114. /* Lines surviving in the merge result */
  115. struct sline {
  116. /* Accumulated and coalesced lost lines */
  117. struct lline *lost;
  118. int lenlost;
  119. struct plost plost;
  120. char *bol;
  121. int len;
  122. /* bit 0 up to (N-1) are on if the parent has this line (i.e.
  123. * we did not change it).
  124. * bit N is used for "interesting" lines, including context.
  125. * bit (N+1) is used for "do not show deletion before this".
  126. */
  127. unsigned long flag;
  128. unsigned long *p_lno;
  129. };
  130. static int match_string_spaces(const char *line1, int len1,
  131. const char *line2, int len2,
  132. long flags)
  133. {
  134. if (flags & XDF_WHITESPACE_FLAGS) {
  135. for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
  136. for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
  137. }
  138. if (!(flags & (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE)))
  139. return (len1 == len2 && !memcmp(line1, line2, len1));
  140. while (len1 > 0 && len2 > 0) {
  141. len1--;
  142. len2--;
  143. if (XDL_ISSPACE(line1[len1]) || XDL_ISSPACE(line2[len2])) {
  144. if ((flags & XDF_IGNORE_WHITESPACE_CHANGE) &&
  145. (!XDL_ISSPACE(line1[len1]) || !XDL_ISSPACE(line2[len2])))
  146. return 0;
  147. for (; len1 > 0 && XDL_ISSPACE(line1[len1]); len1--);
  148. for (; len2 > 0 && XDL_ISSPACE(line2[len2]); len2--);
  149. }
  150. if (line1[len1] != line2[len2])
  151. return 0;
  152. }
  153. if (flags & XDF_IGNORE_WHITESPACE) {
  154. /* Consume remaining spaces */
  155. for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
  156. for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
  157. }
  158. /* We matched full line1 and line2 */
  159. if (!len1 && !len2)
  160. return 1;
  161. return 0;
  162. }
  163. enum coalesce_direction { MATCH, BASE, NEW };
  164. /* Coalesce new lines into base by finding LCS */
  165. static struct lline *coalesce_lines(struct lline *base, int *lenbase,
  166. struct lline *newline, int lennew,
  167. unsigned long parent, long flags)
  168. {
  169. int **lcs;
  170. enum coalesce_direction **directions;
  171. struct lline *baseend, *newend = NULL;
  172. int i, j, origbaselen = *lenbase;
  173. if (newline == NULL)
  174. return base;
  175. if (base == NULL) {
  176. *lenbase = lennew;
  177. return newline;
  178. }
  179. /*
  180. * Coalesce new lines into base by finding the LCS
  181. * - Create the table to run dynamic programming
  182. * - Compute the LCS
  183. * - Then reverse read the direction structure:
  184. * - If we have MATCH, assign parent to base flag, and consume
  185. * both baseend and newend
  186. * - Else if we have BASE, consume baseend
  187. * - Else if we have NEW, insert newend lline into base and
  188. * consume newend
  189. */
  190. lcs = xcalloc(st_add(origbaselen, 1), sizeof(int*));
  191. directions = xcalloc(st_add(origbaselen, 1), sizeof(enum coalesce_direction*));
  192. for (i = 0; i < origbaselen + 1; i++) {
  193. lcs[i] = xcalloc(st_add(lennew, 1), sizeof(int));
  194. directions[i] = xcalloc(st_add(lennew, 1), sizeof(enum coalesce_direction));
  195. directions[i][0] = BASE;
  196. }
  197. for (j = 1; j < lennew + 1; j++)
  198. directions[0][j] = NEW;
  199. for (i = 1, baseend = base; i < origbaselen + 1; i++) {
  200. for (j = 1, newend = newline; j < lennew + 1; j++) {
  201. if (match_string_spaces(baseend->line, baseend->len,
  202. newend->line, newend->len, flags)) {
  203. lcs[i][j] = lcs[i - 1][j - 1] + 1;
  204. directions[i][j] = MATCH;
  205. } else if (lcs[i][j - 1] >= lcs[i - 1][j]) {
  206. lcs[i][j] = lcs[i][j - 1];
  207. directions[i][j] = NEW;
  208. } else {
  209. lcs[i][j] = lcs[i - 1][j];
  210. directions[i][j] = BASE;
  211. }
  212. if (newend->next)
  213. newend = newend->next;
  214. }
  215. if (baseend->next)
  216. baseend = baseend->next;
  217. }
  218. for (i = 0; i < origbaselen + 1; i++)
  219. free(lcs[i]);
  220. free(lcs);
  221. /* At this point, baseend and newend point to the end of each lists */
  222. i--;
  223. j--;
  224. while (i != 0 || j != 0) {
  225. if (directions[i][j] == MATCH) {
  226. baseend->parent_map |= 1<<parent;
  227. baseend = baseend->prev;
  228. newend = newend->prev;
  229. i--;
  230. j--;
  231. } else if (directions[i][j] == NEW) {
  232. struct lline *lline;
  233. lline = newend;
  234. /* Remove lline from new list and update newend */
  235. if (lline->prev)
  236. lline->prev->next = lline->next;
  237. else
  238. newline = lline->next;
  239. if (lline->next)
  240. lline->next->prev = lline->prev;
  241. newend = lline->prev;
  242. j--;
  243. /* Add lline to base list */
  244. if (baseend) {
  245. lline->next = baseend->next;
  246. lline->prev = baseend;
  247. if (lline->prev)
  248. lline->prev->next = lline;
  249. }
  250. else {
  251. lline->next = base;
  252. base = lline;
  253. }
  254. (*lenbase)++;
  255. if (lline->next)
  256. lline->next->prev = lline;
  257. } else {
  258. baseend = baseend->prev;
  259. i--;
  260. }
  261. }
  262. newend = newline;
  263. while (newend) {
  264. struct lline *lline = newend;
  265. newend = newend->next;
  266. free(lline);
  267. }
  268. for (i = 0; i < origbaselen + 1; i++)
  269. free(directions[i]);
  270. free(directions);
  271. return base;
  272. }
  273. static char *grab_blob(struct repository *r,
  274. const struct object_id *oid, unsigned int mode,
  275. unsigned long *size, struct userdiff_driver *textconv,
  276. const char *path)
  277. {
  278. char *blob;
  279. enum object_type type;
  280. if (S_ISGITLINK(mode)) {
  281. struct strbuf buf = STRBUF_INIT;
  282. strbuf_addf(&buf, "Subproject commit %s\n", oid_to_hex(oid));
  283. *size = buf.len;
  284. blob = strbuf_detach(&buf, NULL);
  285. } else if (is_null_oid(oid)) {
  286. /* deleted blob */
  287. *size = 0;
  288. return xcalloc(1, 1);
  289. } else if (textconv) {
  290. struct diff_filespec *df = alloc_filespec(path);
  291. fill_filespec(df, oid, 1, mode);
  292. *size = fill_textconv(r, textconv, df, &blob);
  293. free_filespec(df);
  294. } else {
  295. blob = read_object_file(oid, &type, size);
  296. if (type != OBJ_BLOB)
  297. die("object '%s' is not a blob!", oid_to_hex(oid));
  298. }
  299. return blob;
  300. }
  301. static void append_lost(struct sline *sline, int n, const char *line, int len)
  302. {
  303. struct lline *lline;
  304. unsigned long this_mask = (1UL<<n);
  305. if (line[len-1] == '\n')
  306. len--;
  307. FLEX_ALLOC_MEM(lline, line, line, len);
  308. lline->len = len;
  309. lline->next = NULL;
  310. lline->prev = sline->plost.lost_tail;
  311. if (lline->prev)
  312. lline->prev->next = lline;
  313. else
  314. sline->plost.lost_head = lline;
  315. sline->plost.lost_tail = lline;
  316. sline->plost.len++;
  317. lline->parent_map = this_mask;
  318. }
  319. struct combine_diff_state {
  320. unsigned int lno;
  321. int ob, on, nb, nn;
  322. unsigned long nmask;
  323. int num_parent;
  324. int n;
  325. struct sline *sline;
  326. struct sline *lost_bucket;
  327. };
  328. static void consume_hunk(void *state_,
  329. long ob, long on,
  330. long nb, long nn,
  331. const char *funcline, long funclen)
  332. {
  333. struct combine_diff_state *state = state_;
  334. state->ob = ob;
  335. state->on = on;
  336. state->nb = nb;
  337. state->nn = nn;
  338. state->lno = state->nb;
  339. if (state->nn == 0) {
  340. /* @@ -X,Y +N,0 @@ removed Y lines
  341. * that would have come *after* line N
  342. * in the result. Our lost buckets hang
  343. * to the line after the removed lines,
  344. *
  345. * Note that this is correct even when N == 0,
  346. * in which case the hunk removes the first
  347. * line in the file.
  348. */
  349. state->lost_bucket = &state->sline[state->nb];
  350. if (!state->nb)
  351. state->nb = 1;
  352. } else {
  353. state->lost_bucket = &state->sline[state->nb-1];
  354. }
  355. if (!state->sline[state->nb-1].p_lno)
  356. state->sline[state->nb-1].p_lno =
  357. xcalloc(state->num_parent, sizeof(unsigned long));
  358. state->sline[state->nb-1].p_lno[state->n] = state->ob;
  359. }
  360. static void consume_line(void *state_, char *line, unsigned long len)
  361. {
  362. struct combine_diff_state *state = state_;
  363. if (!state->lost_bucket)
  364. return; /* not in any hunk yet */
  365. switch (line[0]) {
  366. case '-':
  367. append_lost(state->lost_bucket, state->n, line+1, len-1);
  368. break;
  369. case '+':
  370. state->sline[state->lno-1].flag |= state->nmask;
  371. state->lno++;
  372. break;
  373. }
  374. }
  375. static void combine_diff(struct repository *r,
  376. const struct object_id *parent, unsigned int mode,
  377. mmfile_t *result_file,
  378. struct sline *sline, unsigned int cnt, int n,
  379. int num_parent, int result_deleted,
  380. struct userdiff_driver *textconv,
  381. const char *path, long flags)
  382. {
  383. unsigned int p_lno, lno;
  384. unsigned long nmask = (1UL << n);
  385. xpparam_t xpp;
  386. xdemitconf_t xecfg;
  387. mmfile_t parent_file;
  388. struct combine_diff_state state;
  389. unsigned long sz;
  390. if (result_deleted)
  391. return; /* result deleted */
  392. parent_file.ptr = grab_blob(r, parent, mode, &sz, textconv, path);
  393. parent_file.size = sz;
  394. memset(&xpp, 0, sizeof(xpp));
  395. xpp.flags = flags;
  396. memset(&xecfg, 0, sizeof(xecfg));
  397. memset(&state, 0, sizeof(state));
  398. state.nmask = nmask;
  399. state.sline = sline;
  400. state.lno = 1;
  401. state.num_parent = num_parent;
  402. state.n = n;
  403. if (xdi_diff_outf(&parent_file, result_file, consume_hunk,
  404. consume_line, &state, &xpp, &xecfg))
  405. die("unable to generate combined diff for %s",
  406. oid_to_hex(parent));
  407. free(parent_file.ptr);
  408. /* Assign line numbers for this parent.
  409. *
  410. * sline[lno].p_lno[n] records the first line number
  411. * (counting from 1) for parent N if the final hunk display
  412. * started by showing sline[lno] (possibly showing the lost
  413. * lines attached to it first).
  414. */
  415. for (lno = 0, p_lno = 1; lno <= cnt; lno++) {
  416. struct lline *ll;
  417. sline[lno].p_lno[n] = p_lno;
  418. /* Coalesce new lines */
  419. if (sline[lno].plost.lost_head) {
  420. struct sline *sl = &sline[lno];
  421. sl->lost = coalesce_lines(sl->lost, &sl->lenlost,
  422. sl->plost.lost_head,
  423. sl->plost.len, n, flags);
  424. sl->plost.lost_head = sl->plost.lost_tail = NULL;
  425. sl->plost.len = 0;
  426. }
  427. /* How many lines would this sline advance the p_lno? */
  428. ll = sline[lno].lost;
  429. while (ll) {
  430. if (ll->parent_map & nmask)
  431. p_lno++; /* '-' means parent had it */
  432. ll = ll->next;
  433. }
  434. if (lno < cnt && !(sline[lno].flag & nmask))
  435. p_lno++; /* no '+' means parent had it */
  436. }
  437. sline[lno].p_lno[n] = p_lno; /* trailer */
  438. }
  439. static unsigned long context = 3;
  440. static char combine_marker = '@';
  441. static int interesting(struct sline *sline, unsigned long all_mask)
  442. {
  443. /* If some parents lost lines here, or if we have added to
  444. * some parent, it is interesting.
  445. */
  446. return ((sline->flag & all_mask) || sline->lost);
  447. }
  448. static unsigned long adjust_hunk_tail(struct sline *sline,
  449. unsigned long all_mask,
  450. unsigned long hunk_begin,
  451. unsigned long i)
  452. {
  453. /* i points at the first uninteresting line. If the last line
  454. * of the hunk was interesting only because it has some
  455. * deletion, then it is not all that interesting for the
  456. * purpose of giving trailing context lines. This is because
  457. * we output '-' line and then unmodified sline[i-1] itself in
  458. * that case which gives us one extra context line.
  459. */
  460. if ((hunk_begin + 1 <= i) && !(sline[i-1].flag & all_mask))
  461. i--;
  462. return i;
  463. }
  464. static unsigned long find_next(struct sline *sline,
  465. unsigned long mark,
  466. unsigned long i,
  467. unsigned long cnt,
  468. int look_for_uninteresting)
  469. {
  470. /* We have examined up to i-1 and are about to look at i.
  471. * Find next interesting or uninteresting line. Here,
  472. * "interesting" does not mean interesting(), but marked by
  473. * the give_context() function below (i.e. it includes context
  474. * lines that are not interesting to interesting() function
  475. * that are surrounded by interesting() ones.
  476. */
  477. while (i <= cnt)
  478. if (look_for_uninteresting
  479. ? !(sline[i].flag & mark)
  480. : (sline[i].flag & mark))
  481. return i;
  482. else
  483. i++;
  484. return i;
  485. }
  486. static int give_context(struct sline *sline, unsigned long cnt, int num_parent)
  487. {
  488. unsigned long all_mask = (1UL<<num_parent) - 1;
  489. unsigned long mark = (1UL<<num_parent);
  490. unsigned long no_pre_delete = (2UL<<num_parent);
  491. unsigned long i;
  492. /* Two groups of interesting lines may have a short gap of
  493. * uninteresting lines. Connect such groups to give them a
  494. * bit of context.
  495. *
  496. * We first start from what the interesting() function says,
  497. * and mark them with "mark", and paint context lines with the
  498. * mark. So interesting() would still say false for such context
  499. * lines but they are treated as "interesting" in the end.
  500. */
  501. i = find_next(sline, mark, 0, cnt, 0);
  502. if (cnt < i)
  503. return 0;
  504. while (i <= cnt) {
  505. unsigned long j = (context < i) ? (i - context) : 0;
  506. unsigned long k;
  507. /* Paint a few lines before the first interesting line. */
  508. while (j < i) {
  509. if (!(sline[j].flag & mark))
  510. sline[j].flag |= no_pre_delete;
  511. sline[j++].flag |= mark;
  512. }
  513. again:
  514. /* we know up to i is to be included. where does the
  515. * next uninteresting one start?
  516. */
  517. j = find_next(sline, mark, i, cnt, 1);
  518. if (cnt < j)
  519. break; /* the rest are all interesting */
  520. /* lookahead context lines */
  521. k = find_next(sline, mark, j, cnt, 0);
  522. j = adjust_hunk_tail(sline, all_mask, i, j);
  523. if (k < j + context) {
  524. /* k is interesting and [j,k) are not, but
  525. * paint them interesting because the gap is small.
  526. */
  527. while (j < k)
  528. sline[j++].flag |= mark;
  529. i = k;
  530. goto again;
  531. }
  532. /* j is the first uninteresting line and there is
  533. * no overlap beyond it within context lines. Paint
  534. * the trailing edge a bit.
  535. */
  536. i = k;
  537. k = (j + context < cnt+1) ? j + context : cnt+1;
  538. while (j < k)
  539. sline[j++].flag |= mark;
  540. }
  541. return 1;
  542. }
  543. static int make_hunks(struct sline *sline, unsigned long cnt,
  544. int num_parent, int dense)
  545. {
  546. unsigned long all_mask = (1UL<<num_parent) - 1;
  547. unsigned long mark = (1UL<<num_parent);
  548. unsigned long i;
  549. int has_interesting = 0;
  550. for (i = 0; i <= cnt; i++) {
  551. if (interesting(&sline[i], all_mask))
  552. sline[i].flag |= mark;
  553. else
  554. sline[i].flag &= ~mark;
  555. }
  556. if (!dense)
  557. return give_context(sline, cnt, num_parent);
  558. /* Look at each hunk, and if we have changes from only one
  559. * parent, or the changes are the same from all but one
  560. * parent, mark that uninteresting.
  561. */
  562. i = 0;
  563. while (i <= cnt) {
  564. unsigned long j, hunk_begin, hunk_end;
  565. unsigned long same_diff;
  566. while (i <= cnt && !(sline[i].flag & mark))
  567. i++;
  568. if (cnt < i)
  569. break; /* No more interesting hunks */
  570. hunk_begin = i;
  571. for (j = i + 1; j <= cnt; j++) {
  572. if (!(sline[j].flag & mark)) {
  573. /* Look beyond the end to see if there
  574. * is an interesting line after this
  575. * hunk within context span.
  576. */
  577. unsigned long la; /* lookahead */
  578. int contin = 0;
  579. la = adjust_hunk_tail(sline, all_mask,
  580. hunk_begin, j);
  581. la = (la + context < cnt + 1) ?
  582. (la + context) : cnt + 1;
  583. while (la && j <= --la) {
  584. if (sline[la].flag & mark) {
  585. contin = 1;
  586. break;
  587. }
  588. }
  589. if (!contin)
  590. break;
  591. j = la;
  592. }
  593. }
  594. hunk_end = j;
  595. /* [i..hunk_end) are interesting. Now is it really
  596. * interesting? We check if there are only two versions
  597. * and the result matches one of them. That is, we look
  598. * at:
  599. * (+) line, which records lines added to which parents;
  600. * this line appears in the result.
  601. * (-) line, which records from what parents the line
  602. * was removed; this line does not appear in the result.
  603. * then check the set of parents the result has difference
  604. * from, from all lines. If there are lines that has
  605. * different set of parents that the result has differences
  606. * from, that means we have more than two versions.
  607. *
  608. * Even when we have only two versions, if the result does
  609. * not match any of the parents, the it should be considered
  610. * interesting. In such a case, we would have all '+' line.
  611. * After passing the above "two versions" test, that would
  612. * appear as "the same set of parents" to be "all parents".
  613. */
  614. same_diff = 0;
  615. has_interesting = 0;
  616. for (j = i; j < hunk_end && !has_interesting; j++) {
  617. unsigned long this_diff = sline[j].flag & all_mask;
  618. struct lline *ll = sline[j].lost;
  619. if (this_diff) {
  620. /* This has some changes. Is it the
  621. * same as others?
  622. */
  623. if (!same_diff)
  624. same_diff = this_diff;
  625. else if (same_diff != this_diff) {
  626. has_interesting = 1;
  627. break;
  628. }
  629. }
  630. while (ll && !has_interesting) {
  631. /* Lost this line from these parents;
  632. * who are they? Are they the same?
  633. */
  634. this_diff = ll->parent_map;
  635. if (!same_diff)
  636. same_diff = this_diff;
  637. else if (same_diff != this_diff) {
  638. has_interesting = 1;
  639. }
  640. ll = ll->next;
  641. }
  642. }
  643. if (!has_interesting && same_diff != all_mask) {
  644. /* This hunk is not that interesting after all */
  645. for (j = hunk_begin; j < hunk_end; j++)
  646. sline[j].flag &= ~mark;
  647. }
  648. i = hunk_end;
  649. }
  650. has_interesting = give_context(sline, cnt, num_parent);
  651. return has_interesting;
  652. }
  653. static void show_parent_lno(struct sline *sline, unsigned long l0, unsigned long l1, int n, unsigned long null_context)
  654. {
  655. l0 = sline[l0].p_lno[n];
  656. l1 = sline[l1].p_lno[n];
  657. printf(" -%lu,%lu", l0, l1-l0-null_context);
  658. }
  659. static int hunk_comment_line(const char *bol)
  660. {
  661. int ch;
  662. if (!bol)
  663. return 0;
  664. ch = *bol & 0xff;
  665. return (isalpha(ch) || ch == '_' || ch == '$');
  666. }
  667. static void show_line_to_eol(const char *line, int len, const char *reset)
  668. {
  669. int saw_cr_at_eol = 0;
  670. if (len < 0)
  671. len = strlen(line);
  672. saw_cr_at_eol = (len && line[len-1] == '\r');
  673. printf("%.*s%s%s\n", len - saw_cr_at_eol, line,
  674. reset,
  675. saw_cr_at_eol ? "\r" : "");
  676. }
  677. static void dump_sline(struct sline *sline, const char *line_prefix,
  678. unsigned long cnt, int num_parent,
  679. int use_color, int result_deleted)
  680. {
  681. unsigned long mark = (1UL<<num_parent);
  682. unsigned long no_pre_delete = (2UL<<num_parent);
  683. int i;
  684. unsigned long lno = 0;
  685. const char *c_frag = diff_get_color(use_color, DIFF_FRAGINFO);
  686. const char *c_func = diff_get_color(use_color, DIFF_FUNCINFO);
  687. const char *c_new = diff_get_color(use_color, DIFF_FILE_NEW);
  688. const char *c_old = diff_get_color(use_color, DIFF_FILE_OLD);
  689. const char *c_context = diff_get_color(use_color, DIFF_CONTEXT);
  690. const char *c_reset = diff_get_color(use_color, DIFF_RESET);
  691. if (result_deleted)
  692. return; /* result deleted */
  693. while (1) {
  694. unsigned long hunk_end;
  695. unsigned long rlines;
  696. const char *hunk_comment = NULL;
  697. unsigned long null_context = 0;
  698. while (lno <= cnt && !(sline[lno].flag & mark)) {
  699. if (hunk_comment_line(sline[lno].bol))
  700. hunk_comment = sline[lno].bol;
  701. lno++;
  702. }
  703. if (cnt < lno)
  704. break;
  705. else {
  706. for (hunk_end = lno + 1; hunk_end <= cnt; hunk_end++)
  707. if (!(sline[hunk_end].flag & mark))
  708. break;
  709. }
  710. rlines = hunk_end - lno;
  711. if (cnt < hunk_end)
  712. rlines--; /* pointing at the last delete hunk */
  713. if (!context) {
  714. /*
  715. * Even when running with --unified=0, all
  716. * lines in the hunk needs to be processed in
  717. * the loop below in order to show the
  718. * deletion recorded in lost_head. However,
  719. * we do not want to show the resulting line
  720. * with all blank context markers in such a
  721. * case. Compensate.
  722. */
  723. unsigned long j;
  724. for (j = lno; j < hunk_end; j++)
  725. if (!(sline[j].flag & (mark-1)))
  726. null_context++;
  727. rlines -= null_context;
  728. }
  729. printf("%s%s", line_prefix, c_frag);
  730. for (i = 0; i <= num_parent; i++) putchar(combine_marker);
  731. for (i = 0; i < num_parent; i++)
  732. show_parent_lno(sline, lno, hunk_end, i, null_context);
  733. printf(" +%lu,%lu ", lno+1, rlines);
  734. for (i = 0; i <= num_parent; i++) putchar(combine_marker);
  735. if (hunk_comment) {
  736. int comment_end = 0;
  737. for (i = 0; i < 40; i++) {
  738. int ch = hunk_comment[i] & 0xff;
  739. if (!ch || ch == '\n')
  740. break;
  741. if (!isspace(ch))
  742. comment_end = i;
  743. }
  744. if (comment_end)
  745. printf("%s%s %s%s", c_reset,
  746. c_context, c_reset,
  747. c_func);
  748. for (i = 0; i < comment_end; i++)
  749. putchar(hunk_comment[i]);
  750. }
  751. printf("%s\n", c_reset);
  752. while (lno < hunk_end) {
  753. struct lline *ll;
  754. int j;
  755. unsigned long p_mask;
  756. struct sline *sl = &sline[lno++];
  757. ll = (sl->flag & no_pre_delete) ? NULL : sl->lost;
  758. while (ll) {
  759. printf("%s%s", line_prefix, c_old);
  760. for (j = 0; j < num_parent; j++) {
  761. if (ll->parent_map & (1UL<<j))
  762. putchar('-');
  763. else
  764. putchar(' ');
  765. }
  766. show_line_to_eol(ll->line, -1, c_reset);
  767. ll = ll->next;
  768. }
  769. if (cnt < lno)
  770. break;
  771. p_mask = 1;
  772. fputs(line_prefix, stdout);
  773. if (!(sl->flag & (mark-1))) {
  774. /*
  775. * This sline was here to hang the
  776. * lost lines in front of it.
  777. */
  778. if (!context)
  779. continue;
  780. fputs(c_context, stdout);
  781. }
  782. else
  783. fputs(c_new, stdout);
  784. for (j = 0; j < num_parent; j++) {
  785. if (p_mask & sl->flag)
  786. putchar('+');
  787. else
  788. putchar(' ');
  789. p_mask <<= 1;
  790. }
  791. show_line_to_eol(sl->bol, sl->len, c_reset);
  792. }
  793. }
  794. }
  795. static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
  796. int i, int j)
  797. {
  798. /* We have already examined parent j and we know parent i
  799. * and parent j are the same, so reuse the combined result
  800. * of parent j for parent i.
  801. */
  802. unsigned long lno, imask, jmask;
  803. imask = (1UL<<i);
  804. jmask = (1UL<<j);
  805. for (lno = 0; lno <= cnt; lno++) {
  806. struct lline *ll = sline->lost;
  807. sline->p_lno[i] = sline->p_lno[j];
  808. while (ll) {
  809. if (ll->parent_map & jmask)
  810. ll->parent_map |= imask;
  811. ll = ll->next;
  812. }
  813. if (sline->flag & jmask)
  814. sline->flag |= imask;
  815. sline++;
  816. }
  817. /* the overall size of the file (sline[cnt]) */
  818. sline->p_lno[i] = sline->p_lno[j];
  819. }
  820. static void dump_quoted_path(const char *head,
  821. const char *prefix,
  822. const char *path,
  823. const char *line_prefix,
  824. const char *c_meta, const char *c_reset)
  825. {
  826. static struct strbuf buf = STRBUF_INIT;
  827. strbuf_reset(&buf);
  828. strbuf_addstr(&buf, line_prefix);
  829. strbuf_addstr(&buf, c_meta);
  830. strbuf_addstr(&buf, head);
  831. quote_two_c_style(&buf, prefix, path, 0);
  832. strbuf_addstr(&buf, c_reset);
  833. puts(buf.buf);
  834. }
  835. static void show_combined_header(struct combine_diff_path *elem,
  836. int num_parent,
  837. int dense,
  838. struct rev_info *rev,
  839. const char *line_prefix,
  840. int mode_differs,
  841. int show_file_header)
  842. {
  843. struct diff_options *opt = &rev->diffopt;
  844. int abbrev = opt->flags.full_index ? the_hash_algo->hexsz : DEFAULT_ABBREV;
  845. const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/";
  846. const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/";
  847. const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO);
  848. const char *c_reset = diff_get_color_opt(opt, DIFF_RESET);
  849. const char *abb;
  850. int added = 0;
  851. int deleted = 0;
  852. int i;
  853. if (rev->loginfo && !rev->no_commit_id)
  854. show_log(rev);
  855. dump_quoted_path(dense ? "diff --cc " : "diff --combined ",
  856. "", elem->path, line_prefix, c_meta, c_reset);
  857. printf("%s%sindex ", line_prefix, c_meta);
  858. for (i = 0; i < num_parent; i++) {
  859. abb = find_unique_abbrev(&elem->parent[i].oid,
  860. abbrev);
  861. printf("%s%s", i ? "," : "", abb);
  862. }
  863. abb = find_unique_abbrev(&elem->oid, abbrev);
  864. printf("..%s%s\n", abb, c_reset);
  865. if (mode_differs) {
  866. deleted = !elem->mode;
  867. /* We say it was added if nobody had it */
  868. added = !deleted;
  869. for (i = 0; added && i < num_parent; i++)
  870. if (elem->parent[i].status !=
  871. DIFF_STATUS_ADDED)
  872. added = 0;
  873. if (added)
  874. printf("%s%snew file mode %06o",
  875. line_prefix, c_meta, elem->mode);
  876. else {
  877. if (deleted)
  878. printf("%s%sdeleted file ",
  879. line_prefix, c_meta);
  880. printf("mode ");
  881. for (i = 0; i < num_parent; i++) {
  882. printf("%s%06o", i ? "," : "",
  883. elem->parent[i].mode);
  884. }
  885. if (elem->mode)
  886. printf("..%06o", elem->mode);
  887. }
  888. printf("%s\n", c_reset);
  889. }
  890. if (!show_file_header)
  891. return;
  892. if (rev->combined_all_paths) {
  893. for (i = 0; i < num_parent; i++) {
  894. char *path = filename_changed(elem->parent[i].status)
  895. ? elem->parent[i].path.buf : elem->path;
  896. if (elem->parent[i].status == DIFF_STATUS_ADDED)
  897. dump_quoted_path("--- ", "", "/dev/null",
  898. line_prefix, c_meta, c_reset);
  899. else
  900. dump_quoted_path("--- ", a_prefix, path,
  901. line_prefix, c_meta, c_reset);
  902. }
  903. } else {
  904. if (added)
  905. dump_quoted_path("--- ", "", "/dev/null",
  906. line_prefix, c_meta, c_reset);
  907. else
  908. dump_quoted_path("--- ", a_prefix, elem->path,
  909. line_prefix, c_meta, c_reset);
  910. }
  911. if (deleted)
  912. dump_quoted_path("+++ ", "", "/dev/null",
  913. line_prefix, c_meta, c_reset);
  914. else
  915. dump_quoted_path("+++ ", b_prefix, elem->path,
  916. line_prefix, c_meta, c_reset);
  917. }
  918. static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
  919. int dense, int working_tree_file,
  920. struct rev_info *rev)
  921. {
  922. struct diff_options *opt = &rev->diffopt;
  923. unsigned long result_size, cnt, lno;
  924. int result_deleted = 0;
  925. char *result, *cp;
  926. struct sline *sline; /* survived lines */
  927. int mode_differs = 0;
  928. int i, show_hunks;
  929. mmfile_t result_file;
  930. struct userdiff_driver *userdiff;
  931. struct userdiff_driver *textconv = NULL;
  932. int is_binary;
  933. const char *line_prefix = diff_line_prefix(opt);
  934. context = opt->context;
  935. userdiff = userdiff_find_by_path(opt->repo->index, elem->path);
  936. if (!userdiff)
  937. userdiff = userdiff_find_by_name("default");
  938. if (opt->flags.allow_textconv)
  939. textconv = userdiff_get_textconv(opt->repo, userdiff);
  940. /* Read the result of merge first */
  941. if (!working_tree_file)
  942. result = grab_blob(opt->repo, &elem->oid, elem->mode, &result_size,
  943. textconv, elem->path);
  944. else {
  945. /* Used by diff-tree to read from the working tree */
  946. struct stat st;
  947. int fd = -1;
  948. if (lstat(elem->path, &st) < 0)
  949. goto deleted_file;
  950. if (S_ISLNK(st.st_mode)) {
  951. struct strbuf buf = STRBUF_INIT;
  952. if (strbuf_readlink(&buf, elem->path, st.st_size) < 0) {
  953. error_errno("readlink(%s)", elem->path);
  954. return;
  955. }
  956. result_size = buf.len;
  957. result = strbuf_detach(&buf, NULL);
  958. elem->mode = canon_mode(st.st_mode);
  959. } else if (S_ISDIR(st.st_mode)) {
  960. struct object_id oid;
  961. if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0)
  962. result = grab_blob(opt->repo, &elem->oid,
  963. elem->mode, &result_size,
  964. NULL, NULL);
  965. else
  966. result = grab_blob(opt->repo, &oid, elem->mode,
  967. &result_size, NULL, NULL);
  968. } else if (textconv) {
  969. struct diff_filespec *df = alloc_filespec(elem->path);
  970. fill_filespec(df, &null_oid, 0, st.st_mode);
  971. result_size = fill_textconv(opt->repo, textconv, df, &result);
  972. free_filespec(df);
  973. } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
  974. size_t len = xsize_t(st.st_size);
  975. ssize_t done;
  976. int is_file, i;
  977. elem->mode = canon_mode(st.st_mode);
  978. /* if symlinks don't work, assume symlink if all parents
  979. * are symlinks
  980. */
  981. is_file = has_symlinks;
  982. for (i = 0; !is_file && i < num_parent; i++)
  983. is_file = !S_ISLNK(elem->parent[i].mode);
  984. if (!is_file)
  985. elem->mode = canon_mode(S_IFLNK);
  986. result_size = len;
  987. result = xmallocz(len);
  988. done = read_in_full(fd, result, len);
  989. if (done < 0)
  990. die_errno("read error '%s'", elem->path);
  991. else if (done < len)
  992. die("early EOF '%s'", elem->path);
  993. /* If not a fake symlink, apply filters, e.g. autocrlf */
  994. if (is_file) {
  995. struct strbuf buf = STRBUF_INIT;
  996. if (convert_to_git(rev->diffopt.repo->index,
  997. elem->path, result, len, &buf, global_conv_flags_eol)) {
  998. free(result);
  999. result = strbuf_detach(&buf, &len);
  1000. result_size = len;
  1001. }
  1002. }
  1003. }
  1004. else {
  1005. deleted_file:
  1006. result_deleted = 1;
  1007. result_size = 0;
  1008. elem->mode = 0;
  1009. result = xcalloc(1, 1);
  1010. }
  1011. if (0 <= fd)
  1012. close(fd);
  1013. }
  1014. for (i = 0; i < num_parent; i++) {
  1015. if (elem->parent[i].mode != elem->mode) {
  1016. mode_differs = 1;
  1017. break;
  1018. }
  1019. }
  1020. if (textconv)
  1021. is_binary = 0;
  1022. else if (userdiff->binary != -1)
  1023. is_binary = userdiff->binary;
  1024. else {
  1025. is_binary = buffer_is_binary(result, result_size);
  1026. for (i = 0; !is_binary && i < num_parent; i++) {
  1027. char *buf;
  1028. unsigned long size;
  1029. buf = grab_blob(opt->repo,
  1030. &elem->parent[i].oid,
  1031. elem->parent[i].mode,
  1032. &size, NULL, NULL);
  1033. if (buffer_is_binary(buf, size))
  1034. is_binary = 1;
  1035. free(buf);
  1036. }
  1037. }
  1038. if (is_binary) {
  1039. show_combined_header(elem, num_parent, dense, rev,
  1040. line_prefix, mode_differs, 0);
  1041. printf("Binary files differ\n");
  1042. free(result);
  1043. return;
  1044. }
  1045. for (cnt = 0, cp = result; cp < result + result_size; cp++) {
  1046. if (*cp == '\n')
  1047. cnt++;
  1048. }
  1049. if (result_size && result[result_size-1] != '\n')
  1050. cnt++; /* incomplete line */
  1051. sline = xcalloc(st_add(cnt, 2), sizeof(*sline));
  1052. sline[0].bol = result;
  1053. for (lno = 0, cp = result; cp < result + result_size; cp++) {
  1054. if (*cp == '\n') {
  1055. sline[lno].len = cp - sline[lno].bol;
  1056. lno++;
  1057. if (lno < cnt)
  1058. sline[lno].bol = cp + 1;
  1059. }
  1060. }
  1061. if (result_size && result[result_size-1] != '\n')
  1062. sline[cnt-1].len = result_size - (sline[cnt-1].bol - result);
  1063. result_file.ptr = result;
  1064. result_file.size = result_size;
  1065. /* Even p_lno[cnt+1] is valid -- that is for the end line number
  1066. * for deletion hunk at the end.
  1067. */
  1068. sline[0].p_lno = xcalloc(st_mult(st_add(cnt, 2), num_parent), sizeof(unsigned long));
  1069. for (lno = 0; lno <= cnt; lno++)
  1070. sline[lno+1].p_lno = sline[lno].p_lno + num_parent;
  1071. for (i = 0; i < num_parent; i++) {
  1072. int j;
  1073. for (j = 0; j < i; j++) {
  1074. if (oideq(&elem->parent[i].oid,
  1075. &elem->parent[j].oid)) {
  1076. reuse_combine_diff(sline, cnt, i, j);
  1077. break;
  1078. }
  1079. }
  1080. if (i <= j)
  1081. combine_diff(opt->repo,
  1082. &elem->parent[i].oid,
  1083. elem->parent[i].mode,
  1084. &result_file, sline,
  1085. cnt, i, num_parent, result_deleted,
  1086. textconv, elem->path, opt->xdl_opts);
  1087. }
  1088. show_hunks = make_hunks(sline, cnt, num_parent, dense);
  1089. if (show_hunks || mode_differs || working_tree_file) {
  1090. show_combined_header(elem, num_parent, dense, rev,
  1091. line_prefix, mode_differs, 1);
  1092. dump_sline(sline, line_prefix, cnt, num_parent,
  1093. opt->use_color, result_deleted);
  1094. }
  1095. free(result);
  1096. for (lno = 0; lno < cnt; lno++) {
  1097. if (sline[lno].lost) {
  1098. struct lline *ll = sline[lno].lost;
  1099. while (ll) {
  1100. struct lline *tmp = ll;
  1101. ll = ll->next;
  1102. free(tmp);
  1103. }
  1104. }
  1105. }
  1106. free(sline[0].p_lno);
  1107. free(sline);
  1108. }
  1109. static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct rev_info *rev)
  1110. {
  1111. struct diff_options *opt = &rev->diffopt;
  1112. int line_termination, inter_name_termination, i;
  1113. const char *line_prefix = diff_line_prefix(opt);
  1114. line_termination = opt->line_termination;
  1115. inter_name_termination = '\t';
  1116. if (!line_termination)
  1117. inter_name_termination = 0;
  1118. if (rev->loginfo && !rev->no_commit_id)
  1119. show_log(rev);
  1120. if (opt->output_format & DIFF_FORMAT_RAW) {
  1121. printf("%s", line_prefix);
  1122. /* As many colons as there are parents */
  1123. for (i = 0; i < num_parent; i++)
  1124. putchar(':');
  1125. /* Show the modes */
  1126. for (i = 0; i < num_parent; i++)
  1127. printf("%06o ", p->parent[i].mode);
  1128. printf("%06o", p->mode);
  1129. /* Show sha1's */
  1130. for (i = 0; i < num_parent; i++)
  1131. printf(" %s", diff_aligned_abbrev(&p->parent[i].oid,
  1132. opt->abbrev));
  1133. printf(" %s ", diff_aligned_abbrev(&p->oid, opt->abbrev));
  1134. }
  1135. if (opt->output_format & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) {
  1136. for (i = 0; i < num_parent; i++)
  1137. putchar(p->parent[i].status);
  1138. putchar(inter_name_termination);
  1139. }
  1140. for (i = 0; i < num_parent; i++)
  1141. if (rev->combined_all_paths) {
  1142. if (filename_changed(p->parent[i].status))
  1143. write_name_quoted(p->parent[i].path.buf, stdout,
  1144. inter_name_termination);
  1145. else
  1146. write_name_quoted(p->path, stdout,
  1147. inter_name_termination);
  1148. }
  1149. write_name_quoted(p->path, stdout, line_termination);
  1150. }
  1151. /*
  1152. * The result (p->elem) is from the working tree and their
  1153. * parents are typically from multiple stages during a merge
  1154. * (i.e. diff-files) or the state in HEAD and in the index
  1155. * (i.e. diff-index).
  1156. */
  1157. void show_combined_diff(struct combine_diff_path *p,
  1158. int num_parent,
  1159. int dense,
  1160. struct rev_info *rev)
  1161. {
  1162. struct diff_options *opt = &rev->diffopt;
  1163. if (opt->output_format & (DIFF_FORMAT_RAW |
  1164. DIFF_FORMAT_NAME |
  1165. DIFF_FORMAT_NAME_STATUS))
  1166. show_raw_diff(p, num_parent, rev);
  1167. else if (opt->output_format & DIFF_FORMAT_PATCH)
  1168. show_patch_diff(p, num_parent, dense, 1, rev);
  1169. }
  1170. static void free_combined_pair(struct diff_filepair *pair)
  1171. {
  1172. free(pair->two);
  1173. free(pair);
  1174. }
  1175. /*
  1176. * A combine_diff_path expresses N parents on the LHS against 1 merge
  1177. * result. Synthesize a diff_filepair that has N entries on the "one"
  1178. * side and 1 entry on the "two" side.
  1179. *
  1180. * In the future, we might want to add more data to combine_diff_path
  1181. * so that we can fill fields we are ignoring (most notably, size) here,
  1182. * but currently nobody uses it, so this should suffice for now.
  1183. */
  1184. static struct diff_filepair *combined_pair(struct combine_diff_path *p,
  1185. int num_parent)
  1186. {
  1187. int i;
  1188. struct diff_filepair *pair;
  1189. struct diff_filespec *pool;
  1190. pair = xmalloc(sizeof(*pair));
  1191. pool = xcalloc(st_add(num_parent, 1), sizeof(struct diff_filespec));
  1192. pair->one = pool + 1;
  1193. pair->two = pool;
  1194. for (i = 0; i < num_parent; i++) {
  1195. pair->one[i].path = p->path;
  1196. pair->one[i].mode = p->parent[i].mode;
  1197. oidcpy(&pair->one[i].oid, &p->parent[i].oid);
  1198. pair->one[i].oid_valid = !is_null_oid(&p->parent[i].oid);
  1199. pair->one[i].has_more_entries = 1;
  1200. }
  1201. pair->one[num_parent - 1].has_more_entries = 0;
  1202. pair->two->path = p->path;
  1203. pair->two->mode = p->mode;
  1204. oidcpy(&pair->two->oid, &p->oid);
  1205. pair->two->oid_valid = !is_null_oid(&p->oid);
  1206. return pair;
  1207. }
  1208. static void handle_combined_callback(struct diff_options *opt,
  1209. struct combine_diff_path *paths,
  1210. int num_parent,
  1211. int num_paths)
  1212. {
  1213. struct combine_diff_path *p;
  1214. struct diff_queue_struct q;
  1215. int i;
  1216. q.queue = xcalloc(num_paths, sizeof(struct diff_filepair *));
  1217. q.alloc = num_paths;
  1218. q.nr = num_paths;
  1219. for (i = 0, p = paths; p; p = p->next)
  1220. q.queue[i++] = combined_pair(p, num_parent);
  1221. opt->format_callback(&q, opt, opt->format_callback_data);
  1222. for (i = 0; i < num_paths; i++)
  1223. free_combined_pair(q.queue[i]);
  1224. free(q.queue);
  1225. }
  1226. static const char *path_path(void *obj)
  1227. {
  1228. struct combine_diff_path *path = (struct combine_diff_path *)obj;
  1229. return path->path;
  1230. }
  1231. /*
  1232. * Diff stat formats which we always compute solely against the first parent.
  1233. */
  1234. #define STAT_FORMAT_MASK (DIFF_FORMAT_NUMSTAT \
  1235. | DIFF_FORMAT_SHORTSTAT \
  1236. | DIFF_FORMAT_SUMMARY \
  1237. | DIFF_FORMAT_DIRSTAT \
  1238. | DIFF_FORMAT_DIFFSTAT)
  1239. /* find set of paths that every parent touches */
  1240. static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
  1241. const struct oid_array *parents,
  1242. struct diff_options *opt,
  1243. int combined_all_paths)
  1244. {
  1245. struct combine_diff_path *paths = NULL;
  1246. int i, num_parent = parents->nr;
  1247. int output_format = opt->output_format;
  1248. const char *orderfile = opt->orderfile;
  1249. opt->output_format = DIFF_FORMAT_NO_OUTPUT;
  1250. /* tell diff_tree to emit paths in sorted (=tree) order */
  1251. opt->orderfile = NULL;
  1252. /* D(A,P1...Pn) = D(A,P1) ^ ... ^ D(A,Pn) (wrt paths) */
  1253. for (i = 0; i < num_parent; i++) {
  1254. /*
  1255. * show stat against the first parent even when doing
  1256. * combined diff.
  1257. */
  1258. int stat_opt = output_format & STAT_FORMAT_MASK;
  1259. if (i == 0 && stat_opt)
  1260. opt->output_format = stat_opt;
  1261. else
  1262. opt->output_format = DIFF_FORMAT_NO_OUTPUT;
  1263. diff_tree_oid(&parents->oid[i], oid, "", opt);
  1264. diffcore_std(opt);
  1265. paths = intersect_paths(paths, i, num_parent,
  1266. combined_all_paths);
  1267. /* if showing diff, show it in requested order */
  1268. if (opt->output_format != DIFF_FORMAT_NO_OUTPUT &&
  1269. orderfile) {
  1270. diffcore_order(orderfile);
  1271. }
  1272. diff_flush(opt);
  1273. }
  1274. opt->output_format = output_format;
  1275. opt->orderfile = orderfile;
  1276. return paths;
  1277. }
  1278. /*
  1279. * find set of paths that everybody touches, assuming diff is run without
  1280. * rename/copy detection, etc, comparing all trees simultaneously (= faster).
  1281. */
  1282. static struct combine_diff_path *find_paths_multitree(
  1283. const struct object_id *oid, const struct oid_array *parents,
  1284. struct diff_options *opt)
  1285. {
  1286. int i, nparent = parents->nr;
  1287. const struct object_id **parents_oid;
  1288. struct combine_diff_path paths_head;
  1289. struct strbuf base;
  1290. ALLOC_ARRAY(parents_oid, nparent);
  1291. for (i = 0; i < nparent; i++)
  1292. parents_oid[i] = &parents->oid[i];
  1293. /* fake list head, so worker can assume it is non-NULL */
  1294. paths_head.next = NULL;
  1295. strbuf_init(&base, PATH_MAX);
  1296. diff_tree_paths(&paths_head, oid, parents_oid, nparent, &base, opt);
  1297. strbuf_release(&base);
  1298. free(parents_oid);
  1299. return paths_head.next;
  1300. }
  1301. void diff_tree_combined(const struct object_id *oid,
  1302. const struct oid_array *parents,
  1303. int dense,
  1304. struct rev_info *rev)
  1305. {
  1306. struct diff_options *opt = &rev->diffopt;
  1307. struct diff_options diffopts;
  1308. struct combine_diff_path *p, *paths;
  1309. int i, num_paths, needsep, show_log_first, num_parent = parents->nr;
  1310. int need_generic_pathscan;
  1311. /* nothing to do, if no parents */
  1312. if (!num_parent)
  1313. return;
  1314. show_log_first = !!rev->loginfo && !rev->no_commit_id;
  1315. needsep = 0;
  1316. if (show_log_first) {
  1317. show_log(rev);
  1318. if (rev->verbose_header && opt->output_format &&
  1319. opt->output_format != DIFF_FORMAT_NO_OUTPUT &&
  1320. !commit_format_is_empty(rev->commit_format))
  1321. printf("%s%c", diff_line_prefix(opt),
  1322. opt->line_termination);
  1323. }
  1324. diffopts = *opt;
  1325. copy_pathspec(&diffopts.pathspec, &opt->pathspec);
  1326. diffopts.flags.recursive = 1;
  1327. diffopts.flags.allow_external = 0;
  1328. /* find set of paths that everybody touches
  1329. *
  1330. * NOTE
  1331. *
  1332. * Diffcore transformations are bound to diff_filespec and logic
  1333. * comparing two entries - i.e. they do not apply directly to combine
  1334. * diff.
  1335. *
  1336. * If some of such transformations is requested - we launch generic
  1337. * path scanning, which works significantly slower compared to
  1338. * simultaneous all-trees-in-one-go scan in find_paths_multitree().
  1339. *
  1340. * TODO some of the filters could be ported to work on
  1341. * combine_diff_paths - i.e. all functionality that skips paths, so in
  1342. * theory, we could end up having only multitree path scanning.
  1343. *
  1344. * NOTE please keep this semantically in sync with diffcore_std()
  1345. */
  1346. need_generic_pathscan = opt->skip_stat_unmatch ||
  1347. opt->flags.follow_renames ||
  1348. opt->break_opt != -1 ||
  1349. opt->detect_rename ||
  1350. (opt->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) ||
  1351. opt->filter;
  1352. if (need_generic_pathscan) {
  1353. /*
  1354. * NOTE generic case also handles --stat, as it computes
  1355. * diff(sha1,parent_i) for all i to do the job, specifically
  1356. * for parent0.
  1357. */
  1358. paths = find_paths_generic(oid, parents, &diffopts,
  1359. rev->combined_all_paths);
  1360. }
  1361. else {
  1362. int stat_opt;
  1363. paths = find_paths_multitree(oid, parents, &diffopts);
  1364. /*
  1365. * show stat against the first parent even
  1366. * when doing combined diff.
  1367. */
  1368. stat_opt = opt->output_format & STAT_FORMAT_MASK;
  1369. if (stat_opt) {
  1370. diffopts.output_format = stat_opt;
  1371. diff_tree_oid(&parents->oid[0], oid, "", &diffopts);
  1372. diffcore_std(&diffopts);
  1373. if (opt->orderfile)
  1374. diffcore_order(opt->orderfile);
  1375. diff_flush(&diffopts);
  1376. }
  1377. }
  1378. /* find out number of surviving paths */
  1379. for (num_paths = 0, p = paths; p; p = p->next)
  1380. num_paths++;
  1381. /* order paths according to diffcore_order */
  1382. if (opt->orderfile && num_paths) {
  1383. struct obj_order *o;
  1384. ALLOC_ARRAY(o, num_paths);
  1385. for (i = 0, p = paths; p; p = p->next, i++)
  1386. o[i].obj = p;
  1387. order_objects(opt->orderfile, path_path, o, num_paths);
  1388. for (i = 0; i < num_paths - 1; i++) {
  1389. p = o[i].obj;
  1390. p->next = o[i+1].obj;
  1391. }
  1392. p = o[num_paths-1].obj;
  1393. p->next = NULL;
  1394. paths = o[0].obj;
  1395. free(o);
  1396. }
  1397. if (num_paths) {
  1398. if (opt->output_format & (DIFF_FORMAT_RAW |
  1399. DIFF_FORMAT_NAME |
  1400. DIFF_FORMAT_NAME_STATUS)) {
  1401. for (p = paths; p; p = p->next)
  1402. show_raw_diff(p, num_parent, rev);
  1403. needsep = 1;
  1404. }
  1405. else if (opt->output_format & STAT_FORMAT_MASK)
  1406. needsep = 1;
  1407. else if (opt->output_format & DIFF_FORMAT_CALLBACK)
  1408. handle_combined_callback(opt, paths, num_parent, num_paths);
  1409. if (opt->output_format & DIFF_FORMAT_PATCH) {
  1410. if (needsep)
  1411. printf("%s%c", diff_line_prefix(opt),
  1412. opt->line_termination);
  1413. for (p = paths; p; p = p->next)
  1414. show_patch_diff(p, num_parent, dense,
  1415. 0, rev);
  1416. }
  1417. }
  1418. /* Clean things up */
  1419. while (paths) {
  1420. struct combine_diff_path *tmp = paths;
  1421. paths = paths->next;
  1422. for (i = 0; i < num_parent; i++)
  1423. if (rev->combined_all_paths &&
  1424. filename_changed(tmp->parent[i].status))
  1425. strbuf_release(&tmp->parent[i].path);
  1426. free(tmp);
  1427. }
  1428. clear_pathspec(&diffopts.pathspec);
  1429. }
  1430. void diff_tree_combined_merge(const struct commit *commit, int dense,
  1431. struct rev_info *rev)
  1432. {
  1433. struct commit_list *parent = get_saved_parents(rev, commit);
  1434. struct oid_array parents = OID_ARRAY_INIT;
  1435. while (parent) {
  1436. oid_array_append(&parents, &parent->item->object.oid);
  1437. parent = parent->next;
  1438. }
  1439. diff_tree_combined(&commit->object.oid, &parents, dense, rev);
  1440. oid_array_clear(&parents);
  1441. }