*/
nb = 1;
}
- lost_bucket = &sline[nb-1]; /* sline is 0 based */
+ if (nn == 0)
+ lost_bucket = &sline[nb];
+ else
+ lost_bucket = &sline[nb-1];
continue;
}
if (!lost_bucket)
return ((sline->flag & all_mask) != all_mask || sline->lost_head);
}
-static unsigned long line_common_diff(struct sline *sline, unsigned long all_mask)
-{
- /*
- * Look at the line and see from which parents we have the
- * same difference.
- */
-
- /* Lower bits of sline->flag records if the parent had this
- * line, so XOR with all_mask gives us on-bits for parents we
- * have differences with.
- */
- unsigned long common_adds = (sline->flag ^ all_mask) & all_mask;
- unsigned long common_removes = all_mask;
-
- /* If all the parents have this line, that also counts as
- * having the same difference.
- */
- if (!common_adds)
- common_adds = all_mask;
-
- if (sline->lost_head) {
- /* Lost head list records the lines removed from
- * the parents, and parent_map records from which
- * parent the line was removed.
- */
- struct lline *ll;
- for (ll = sline->lost_head; ll; ll = ll->next) {
- common_removes &= ll->parent_map;
- }
- }
- return common_adds & common_removes;
-}
-
-static unsigned long line_all_diff(struct sline *sline, unsigned long all_mask)
-{
- /*
- * Look at the line and see from which parents we have some difference.
- */
- unsigned long different = (sline->flag ^ all_mask) & all_mask;
- if (sline->lost_head) {
- /* Lost head list records the lines removed from
- * the parents, and parent_map records from which
- * parent the line was removed.
- */
- struct lline *ll;
- for (ll = sline->lost_head; ll; ll = ll->next) {
- different |= ll->parent_map;
- }
- }
- return different;
-}
-
static unsigned long adjust_hunk_tail(struct sline *sline,
unsigned long all_mask,
unsigned long hunk_begin,
i = 0;
while (i < cnt) {
unsigned long j, hunk_begin, hunk_end;
- int same, diff;
- unsigned long same_diff, all_diff;
+ unsigned long same_diff;
while (i < cnt && !(sline[i].flag & mark))
i++;
if (cnt <= i)
}
hunk_end = j;
- /* [i..hunk_end) are interesting. Now does it have
- * the same change with all but one parent?
+ /* [i..hunk_end) are interesting. Now is it really
+ * interesting? We check if there are only two versions
+ * and the result matches one of them. That is, we look
+ * at:
+ * (+) line, which records lines added to which parents;
+ * this line appears in the result.
+ * (-) line, which records from what parents the line
+ * was removed; this line does not appear in the result.
+ * then check the set of parents the result has difference
+ * from, from all lines. If there are lines that has
+ * different set of parents that the result has differences
+ * from, that means we have more than two versions.
+ *
+ * Even when we have only two versions, if the result does
+ * not match any of the parents, the it should be considered
+ * interesting. In such a case, we would have all '+' line.
+ * After passing the above "two versions" test, that would
+ * appear as "the same set of parents" to be "all parents".
*/
- same_diff = all_mask;
- all_diff = 0;
- for (j = i; j < hunk_end; j++) {
- same_diff &= line_common_diff(sline + j, all_mask);
- all_diff |= line_all_diff(sline + j, all_mask);
- }
- diff = same = 0;
- for (j = 0; j < num_parent; j++) {
- if (same_diff & (1UL<<j))
- same++;
- if (all_diff & (1UL<<j))
- diff++;
+ same_diff = 0;
+ 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;
+ if (this_diff) {
+ /* This has some changes. Is it the
+ * same as others?
+ */
+ if (!same_diff)
+ same_diff = this_diff;
+ else if (same_diff != this_diff) {
+ has_interesting = 1;
+ break;
+ }
+ }
+ while (ll && !has_interesting) {
+ /* Lost this line from these parents;
+ * who are they? Are they the same?
+ */
+ this_diff = ll->parent_map;
+ if (!same_diff)
+ same_diff = this_diff;
+ else if (same_diff != this_diff) {
+ has_interesting = 1;
+ }
+ ll = ll->next;
+ }
}
- if ((num_parent - 1 <= same) || (diff == 1)) {
+
+ if (!has_interesting && same_diff != all_mask) {
/* This hunk is not that interesting after all */
for (j = hunk_begin; j < hunk_end; j++)
sline[j].flag &= ~mark;
}
}
+static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
+ int i, int j)
+{
+ /* We have already examined parent j and we know parent i
+ * and parent j are the same, so reuse the combined result
+ * of parent j for parent i.
+ */
+ unsigned long lno, imask, jmask;
+ imask = (1UL<<i);
+ jmask = (1UL<<j);
+
+ for (lno = 0; lno < cnt; lno++) {
+ struct lline *ll = sline->lost_head;
+ while (ll) {
+ if (ll->parent_map & jmask)
+ ll->parent_map |= imask;
+ ll = ll->next;
+ }
+ if (!(sline->flag & jmask))
+ sline->flag &= ~imask;
+ sline++;
+ }
+}
+
int show_combined_diff(struct combine_diff_path *elem, int num_parent,
int dense, const char *header, int show_empty)
{
sline[cnt-1].flag = (1UL<<num_parent) - 1;
}
- for (i = 0; i < num_parent; i++)
- combine_diff(elem->parent_sha1[i], ourtmp, sline, cnt, i);
+ for (i = 0; i < num_parent; i++) {
+ int j;
+ for (j = 0; j < i; j++) {
+ if (!memcmp(elem->parent_sha1[i],
+ elem->parent_sha1[j], 20)) {
+ reuse_combine_diff(sline, cnt, i, j);
+ break;
+ }
+ }
+ if (i <= j)
+ combine_diff(elem->parent_sha1[i], ourtmp, sline,
+ cnt, i);
+ }
show_hunks = make_hunks(sline, cnt, num_parent, dense);
else
printf("%s", elem->path);
putchar('\n');
+ printf("index ");
+ for (i = 0; i < num_parent; i++) {
+ printf("%s%s",
+ i ? ".." : "",
+ find_unique_abbrev(elem->parent_sha1[i],
+ DEFAULT_ABBREV));
+ }
+ printf("->%s\n",
+ find_unique_abbrev(elem->sha1, DEFAULT_ABBREV));
dump_sline(sline, cnt, num_parent);
}
if (ourtmp == ourtmp_buf)