+
+static void merge_broken(struct diff_filepair *p,
+ struct diff_filepair *pp,
+ struct diff_queue_struct *outq)
+{
+ /* p and pp are broken pairs we want to merge */
+ struct diff_filepair *c = p, *d = pp, *dp;
+ if (DIFF_FILE_VALID(p->one)) {
+ /* this must be a delete half */
+ d = p; c = pp;
+ }
+ /* Sanity check */
+ if (!DIFF_FILE_VALID(d->one))
+ die("internal error in merge #1");
+ if (DIFF_FILE_VALID(d->two))
+ die("internal error in merge #2");
+ if (DIFF_FILE_VALID(c->one))
+ die("internal error in merge #3");
+ if (!DIFF_FILE_VALID(c->two))
+ die("internal error in merge #4");
+
+ dp = diff_queue(outq, d->one, c->two);
+ dp->score = p->score;
+ diff_free_filespec_data(d->two);
+ diff_free_filespec_data(c->one);
+ free(d);
+ free(c);
+}
+
+void diffcore_merge_broken(void)
+{
+ struct diff_queue_struct *q = &diff_queued_diff;
+ struct diff_queue_struct outq;
+ int i, j;
+
+ outq.nr = outq.alloc = 0;
+ outq.queue = NULL;
+
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ if (!p)
+ /* we already merged this with its peer */
+ continue;
+ else if (p->broken_pair &&
+ !strcmp(p->one->path, p->two->path)) {
+ /* If the peer also survived rename/copy, then
+ * we merge them back together.
+ */
+ for (j = i + 1; j < q->nr; j++) {
+ struct diff_filepair *pp = q->queue[j];
+ if (pp->broken_pair &&
+ !strcmp(pp->one->path, pp->two->path) &&
+ !strcmp(p->one->path, pp->two->path)) {
+ /* Peer survived. Merge them */
+ merge_broken(p, pp, &outq);
+ q->queue[j] = NULL;
+ break;
+ }
+ }
+ if (q->nr <= j)
+ /* The peer did not survive, so we keep
+ * it in the output.
+ */
+ diff_q(&outq, p);
+ }
+ else
+ diff_q(&outq, p);
+ }
+ free(q->queue);
+ *q = outq;
+
+ return;
+}