Merge branch 'cb/maint-1.6.0-xdl-merge-fix' into maint
authorJunio C Hamano <gitster@pobox.com>
Tue, 2 Jun 2009 14:48:44 +0000 (07:48 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 2 Jun 2009 14:48:44 +0000 (07:48 -0700)
* cb/maint-1.6.0-xdl-merge-fix:
Change xdl_merge to generate output even for null merges
t6023: merge-file fails to output anything for a degenerate merge

Conflicts:
xdiff/xmerge.c

1  2 
t/t6023-merge-file.sh
xdiff/xmerge.c
diff --combined t/t6023-merge-file.sh
index f8942bc8908fb92b1b11580e3554a81377dc3ba1,796f2128da8a325a09048d3a3fbb3730244357ca..7dcf39191476f272431e19e10ebb299d6aa55bb1
@@@ -54,6 -54,12 +54,12 @@@ deduxit me super semitas jusitiae
  EOF
  printf "propter nomen suum." >> new4.txt
  
+ test_expect_success 'merge with no changes' '
+       cp orig.txt test.txt &&
+       git merge-file test.txt orig.txt orig.txt &&
+       test_cmp test.txt orig.txt
+ '
  cp new1.txt test.txt
  test_expect_success "merge without conflict" \
        "git merge-file test.txt orig.txt new2.txt"
@@@ -136,7 -142,7 +142,7 @@@ test_expect_success "expected conflict 
  
  test_expect_success 'binary files cannot be merged' '
        test_must_fail git merge-file -p \
 -              orig.txt ../test4012.png new1.txt 2> merge.err &&
 +              orig.txt "$TEST_DIRECTORY"/test4012.png new1.txt 2> merge.err &&
        grep "Cannot merge binary files" merge.err
  '
  
@@@ -150,8 -156,8 +156,8 @@@ test_expect_success 'MERGE_ZEALOUS simp
  
  '
  
 -sed -e 's/deerit./&\n\n\n\n/' -e "s/locavit,/locavit;/" < new6.txt > new8.txt
 -sed -e 's/deerit./&\n\n\n\n/' -e "s/locavit,/locavit --/" < new7.txt > new9.txt
 +sed -e 's/deerit./&%%%%/' -e "s/locavit,/locavit;/"< new6.txt | tr '%' '\012' > new8.txt
 +sed -e 's/deerit./&%%%%/' -e "s/locavit,/locavit --/" < new7.txt | tr '%' '\012' > new9.txt
  
  test_expect_success 'ZEALOUS_ALNUM' '
  
  
  '
  
 +cat >expect <<\EOF
 +Dominus regit me,
 +<<<<<<< new8.txt
 +et nihil mihi deerit;
 +
 +
 +
 +
 +In loco pascuae ibi me collocavit;
 +super aquam refectionis educavit me.
 +|||||||
 +et nihil mihi deerit.
 +In loco pascuae ibi me collocavit,
 +super aquam refectionis educavit me;
 +=======
 +et nihil mihi deerit,
 +
 +
 +
 +
 +In loco pascuae ibi me collocavit --
 +super aquam refectionis educavit me,
 +>>>>>>> new9.txt
 +animam meam convertit,
 +deduxit me super semitas jusitiae,
 +propter nomen suum.
 +Nam et si ambulavero in medio umbrae mortis,
 +non timebo mala, quoniam TU mecum es:
 +virga tua et baculus tuus ipsa me consolata sunt.
 +EOF
 +
 +test_expect_success '"diff3 -m" style output (1)' '
 +      test_must_fail git merge-file -p --diff3 \
 +              new8.txt new5.txt new9.txt >actual &&
 +      test_cmp expect actual
 +'
 +
 +test_expect_success '"diff3 -m" style output (2)' '
 +      git config merge.conflictstyle diff3 &&
 +      test_must_fail git merge-file -p \
 +              new8.txt new5.txt new9.txt >actual &&
 +      test_cmp expect actual
 +'
 +
  test_done
diff --combined xdiff/xmerge.c
index d9737f04c220645aa762d79ff14a84855721ffda,1ef1d358cef61d546a3cbcb85afe5bb3d318f5a7..1cb65a95166a8cb60af590118f59d78aa4d24b74
@@@ -30,32 -30,17 +30,32 @@@ typedef struct s_xdmerge 
         * 2 = no conflict, take second.
         */
        int mode;
 +      /*
 +       * These point at the respective postimages.  E.g. <i1,chg1> is
 +       * how side #1 wants to change the common ancestor; if there is no
 +       * overlap, lines before i1 in the postimage of side #1 appear
 +       * in the merge result as a region touched by neither side.
 +       */
        long i1, i2;
        long chg1, chg2;
 +      /*
 +       * These point at the preimage; of course there is just one
 +       * preimage, that is from the shared common ancestor.
 +       */
 +      long i0;
 +      long chg0;
  } xdmerge_t;
  
  static int xdl_append_merge(xdmerge_t **merge, int mode,
 -              long i1, long chg1, long i2, long chg2)
 +                          long i0, long chg0,
 +                          long i1, long chg1,
 +                          long i2, long chg2)
  {
        xdmerge_t *m = *merge;
        if (m && (i1 <= m->i1 + m->chg1 || i2 <= m->i2 + m->chg2)) {
                if (mode != m->mode)
                        m->mode = 0;
 +              m->chg0 = i0 + chg0 - m->i0;
                m->chg1 = i1 + chg1 - m->i1;
                m->chg2 = i2 + chg2 - m->i2;
        } else {
@@@ -64,8 -49,6 +64,8 @@@
                        return -1;
                m->next = NULL;
                m->mode = mode;
 +              m->i0 = i0;
 +              m->chg0 = chg0;
                m->i1 = i1;
                m->chg1 = chg1;
                m->i2 = i2;
@@@ -108,13 -91,11 +108,13 @@@ static int xdl_merge_cmp_lines(xdfenv_
        return 0;
  }
  
 -static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
 +static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
  {
 -      xrecord_t **recs = xe->xdf2.recs + i;
 +      xrecord_t **recs;
        int size = 0;
  
 +      recs = (use_orig ? xe->xdf1.recs : xe->xdf2.recs) + i;
 +
        if (count < 1)
                return 0;
  
        return size;
  }
  
 -static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
 -              xdfenv_t *xe2, const char *name2, xdmerge_t *m, char *dest)
 +static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
 +{
 +      return xdl_recs_copy_0(0, xe, i, count, add_nl, dest);
 +}
 +
 +static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
 +{
 +      return xdl_recs_copy_0(1, xe, i, count, add_nl, dest);
 +}
 +
 +static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
 +                            xdfenv_t *xe2, const char *name2,
 +                            int size, int i, int style,
 +                            xdmerge_t *m, char *dest)
  {
        const int marker_size = 7;
        int marker1_size = (name1 ? strlen(name1) + 1 : 0);
        int marker2_size = (name2 ? strlen(name2) + 1 : 0);
 -      int conflict_marker_size = 3 * (marker_size + 1)
 -              + marker1_size + marker2_size;
 -      int size, i1, j;
 -
 -      for (size = i1 = 0; m; m = m->next) {
 -              if (m->mode == 0) {
 -                      size += xdl_recs_copy(xe1, i1, m->i1 - i1, 0,
 -                                      dest ? dest + size : NULL);
 -                      if (dest) {
 -                              for (j = 0; j < marker_size; j++)
 -                                      dest[size++] = '<';
 -                              if (marker1_size) {
 -                                      dest[size] = ' ';
 -                                      memcpy(dest + size + 1, name1,
 -                                                      marker1_size - 1);
 -                                      size += marker1_size;
 -                              }
 -                              dest[size++] = '\n';
 -                      } else
 -                              size += conflict_marker_size;
 -                      size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
 -                                      dest ? dest + size : NULL);
 -                      if (dest) {
 -                              for (j = 0; j < marker_size; j++)
 -                                      dest[size++] = '=';
 -                              dest[size++] = '\n';
 -                      }
 -                      size += xdl_recs_copy(xe2, m->i2, m->chg2, 1,
 -                                      dest ? dest + size : NULL);
 -                      if (dest) {
 -                              for (j = 0; j < marker_size; j++)
 -                                      dest[size++] = '>';
 -                              if (marker2_size) {
 -                                      dest[size] = ' ';
 -                                      memcpy(dest + size + 1, name2,
 -                                                      marker2_size - 1);
 -                                      size += marker2_size;
 -                              }
 -                              dest[size++] = '\n';
 -                      }
 -              } else if (m->mode == 1)
 -                      size += xdl_recs_copy(xe1, i1, m->i1 + m->chg1 - i1, 0,
 -                                      dest ? dest + size : NULL);
 +      int j;
 +
 +      /* Before conflicting part */
 +      size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
 +                            dest ? dest + size : NULL);
 +
 +      if (!dest) {
 +              size += marker_size + 1 + marker1_size;
 +      } else {
 +              for (j = 0; j < marker_size; j++)
 +                      dest[size++] = '<';
 +              if (marker1_size) {
 +                      dest[size] = ' ';
 +                      memcpy(dest + size + 1, name1, marker1_size - 1);
 +                      size += marker1_size;
 +              }
 +              dest[size++] = '\n';
 +      }
 +
 +      /* Postimage from side #1 */
 +      size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
 +                            dest ? dest + size : NULL);
 +
 +      if (style == XDL_MERGE_DIFF3) {
 +              /* Shared preimage */
 +              if (!dest) {
 +                      size += marker_size + 1;
 +              } else {
 +                      for (j = 0; j < marker_size; j++)
 +                              dest[size++] = '|';
 +                      dest[size++] = '\n';
 +              }
 +              size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
 +                                    dest ? dest + size : NULL);
 +      }
 +
 +      if (!dest) {
 +              size += marker_size + 1;
 +      } else {
 +              for (j = 0; j < marker_size; j++)
 +                      dest[size++] = '=';
 +              dest[size++] = '\n';
 +      }
 +
 +      /* Postimage from side #2 */
 +      size += xdl_recs_copy(xe2, m->i2, m->chg2, 1,
 +                            dest ? dest + size : NULL);
 +      if (!dest) {
 +              size += marker_size + 1 + marker2_size;
 +      } else {
 +              for (j = 0; j < marker_size; j++)
 +                      dest[size++] = '>';
 +              if (marker2_size) {
 +                      dest[size] = ' ';
 +                      memcpy(dest + size + 1, name2, marker2_size - 1);
 +                      size += marker2_size;
 +              }
 +              dest[size++] = '\n';
 +      }
 +      return size;
 +}
 +
 +static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
 +                               xdfenv_t *xe2, const char *name2,
 +                               xdmerge_t *m, char *dest, int style)
 +{
 +      int size, i;
 +
 +      for (size = i = 0; m; m = m->next) {
 +              if (m->mode == 0)
 +                      size = fill_conflict_hunk(xe1, name1, xe2, name2,
 +                                                size, i, style, m, dest);
 +              else if (m->mode == 1)
 +                      size += xdl_recs_copy(xe1, i, m->i1 + m->chg1 - i, 0,
 +                                            dest ? dest + size : NULL);
                else if (m->mode == 2)
 -                      size += xdl_recs_copy(xe2, m->i2 - m->i1 + i1,
 -                                      m->i1 + m->chg2 - i1, 0,
 -                                      dest ? dest + size : NULL);
 +                      size += xdl_recs_copy(xe2, m->i2 - m->i1 + i,
 +                                            m->i1 + m->chg2 - i, 0,
 +                                            dest ? dest + size : NULL);
                else
                        continue;
 -              i1 = m->i1 + m->chg1;
 +              i = m->i1 + m->chg1;
        }
 -      size += xdl_recs_copy(xe1, i1, xe1->xdf2.nrec - i1, 0,
 -                      dest ? dest + size : NULL);
 +      size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0,
 +                            dest ? dest + size : NULL);
        return size;
  }
  
@@@ -386,20 -323,9 +386,20 @@@ static int xdl_simplify_non_conflicts(x
   */
  static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
                xdfenv_t *xe2, xdchange_t *xscr2, const char *name2,
 -              int level, xpparam_t const *xpp, mmbuffer_t *result) {
 +              int flags, xpparam_t const *xpp, mmbuffer_t *result) {
        xdmerge_t *changes, *c;
 -      int i1, i2, chg1, chg2;
 +      int i0, i1, i2, chg0, chg1, chg2;
 +      int level = flags & XDL_MERGE_LEVEL_MASK;
 +      int style = flags & XDL_MERGE_STYLE_MASK;
 +
 +      if (style == XDL_MERGE_DIFF3) {
 +              /*
 +               * "diff3 -m" output does not make sense for anything
 +               * more aggressive than XDL_MERGE_EAGER.
 +               */
 +              if (XDL_MERGE_EAGER < level)
 +                      level = XDL_MERGE_EAGER;
 +      }
  
        c = changes = NULL;
  
                if (!changes)
                        changes = c;
                if (xscr1->i1 + xscr1->chg1 < xscr2->i1) {
 +                      i0 = xscr1->i1;
                        i1 = xscr1->i2;
                        i2 = xscr2->i2 - xscr2->i1 + xscr1->i1;
 +                      chg0 = xscr1->chg1;
                        chg1 = xscr1->chg2;
                        chg2 = xscr1->chg1;
 -                      if (xdl_append_merge(&c, 1, i1, chg1, i2, chg2)) {
 +                      if (xdl_append_merge(&c, 1,
 +                                           i0, chg0, i1, chg1, i2, chg2)) {
                                xdl_cleanup_merge(changes);
                                return -1;
                        }
                        continue;
                }
                if (xscr2->i1 + xscr2->chg1 < xscr1->i1) {
 +                      i0 = xscr2->i1;
                        i1 = xscr1->i2 - xscr1->i1 + xscr2->i1;
                        i2 = xscr2->i2;
 +                      chg0 = xscr2->chg1;
                        chg1 = xscr2->chg1;
                        chg2 = xscr2->chg2;
 -                      if (xdl_append_merge(&c, 2, i1, chg1, i2, chg2)) {
 +                      if (xdl_append_merge(&c, 2,
 +                                           i0, chg0, i1, chg1, i2, chg2)) {
                                xdl_cleanup_merge(changes);
                                return -1;
                        }
                        xscr2 = xscr2->next;
                        continue;
                }
 -              if (level < 1 || xscr1->i1 != xscr2->i1 ||
 +              if (level == XDL_MERGE_MINIMAL || xscr1->i1 != xscr2->i1 ||
                                xscr1->chg1 != xscr2->chg1 ||
                                xscr1->chg2 != xscr2->chg2 ||
                                xdl_merge_cmp_lines(xe1, xscr1->i2,
                        int off = xscr1->i1 - xscr2->i1;
                        int ffo = off + xscr1->chg1 - xscr2->chg1;
  
 +                      i0 = xscr1->i1;
                        i1 = xscr1->i2;
                        i2 = xscr2->i2;
 -                      if (off > 0)
 +                      if (off > 0) {
 +                              i0 -= off;
                                i1 -= off;
 +                      }
                        else
                                i2 += off;
 +                      chg0 = xscr1->i1 + xscr1->chg1 - i0;
                        chg1 = xscr1->i2 + xscr1->chg2 - i1;
                        chg2 = xscr2->i2 + xscr2->chg2 - i2;
 -                      if (ffo > 0)
 -                              chg2 += ffo;
 -                      else
 +                      if (ffo < 0) {
 +                              chg0 -= ffo;
                                chg1 -= ffo;
 -                      if (xdl_append_merge(&c, 0, i1, chg1, i2, chg2)) {
 +                      } else
 +                              chg2 += ffo;
 +                      if (xdl_append_merge(&c, 0,
 +                                           i0, chg0, i1, chg1, i2, chg2)) {
                                xdl_cleanup_merge(changes);
                                return -1;
                        }
        while (xscr1) {
                if (!changes)
                        changes = c;
 +              i0 = xscr1->i1;
                i1 = xscr1->i2;
                i2 = xscr1->i1 + xe2->xdf2.nrec - xe2->xdf1.nrec;
 +              chg0 = xscr1->chg1;
                chg1 = xscr1->chg2;
                chg2 = xscr1->chg1;
 -              if (xdl_append_merge(&c, 1, i1, chg1, i2, chg2)) {
 +              if (xdl_append_merge(&c, 1,
 +                                   i0, chg0, i1, chg1, i2, chg2)) {
                        xdl_cleanup_merge(changes);
                        return -1;
                }
        while (xscr2) {
                if (!changes)
                        changes = c;
 +              i0 = xscr2->i1;
                i1 = xscr2->i1 + xe1->xdf2.nrec - xe1->xdf1.nrec;
                i2 = xscr2->i2;
 +              chg0 = xscr2->chg1;
                chg1 = xscr2->chg1;
                chg2 = xscr2->chg2;
 -              if (xdl_append_merge(&c, 2, i1, chg1, i2, chg2)) {
 +              if (xdl_append_merge(&c, 2,
 +                                   i0, chg0, i1, chg1, i2, chg2)) {
                        xdl_cleanup_merge(changes);
                        return -1;
                }
        if (!changes)
                changes = c;
        /* refine conflicts */
 -      if (level > 1 &&
 +      if (XDL_MERGE_ZEALOUS <= level &&
            (xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||
 -           xdl_simplify_non_conflicts(xe1, changes, level > 2) < 0)) {
 +           xdl_simplify_non_conflicts(xe1, changes,
 +                                      XDL_MERGE_ZEALOUS < level) < 0)) {
                xdl_cleanup_merge(changes);
                return -1;
        }
        /* output */
        if (result) {
                int size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,
 -                      changes, NULL);
 +                      changes, NULL, style);
                result->ptr = xdl_malloc(size);
                if (!result->ptr) {
                        xdl_cleanup_merge(changes);
                }
                result->size = size;
                xdl_fill_merge_buffer(xe1, name1, xe2, name2, changes,
 -                              result->ptr);
 +                                    result->ptr, style);
        }
        return xdl_cleanup_merge(changes);
  }
  
  int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
                mmfile_t *mf2, const char *name2,
 -              xpparam_t const *xpp, int level, mmbuffer_t *result) {
 +              xpparam_t const *xpp, int flags, mmbuffer_t *result) {
        xdchange_t *xscr1, *xscr2;
        xdfenv_t xe1, xe2;
        int status;
                return -1;
        }
        status = 0;
-       if (xscr1 || xscr2) {
-               if (!xscr1) {
-                       result->ptr = xdl_malloc(mf2->size);
-                       memcpy(result->ptr, mf2->ptr, mf2->size);
-                       result->size = mf2->size;
-               } else if (!xscr2) {
-                       result->ptr = xdl_malloc(mf1->size);
-                       memcpy(result->ptr, mf1->ptr, mf1->size);
-                       result->size = mf1->size;
-               } else {
-                       status = xdl_do_merge(&xe1, xscr1, name1,
-                                             &xe2, xscr2, name2,
-                                             flags, xpp, result);
-               }
-               xdl_free_script(xscr1);
-               xdl_free_script(xscr2);
+       if (!xscr1) {
+               result->ptr = xdl_malloc(mf2->size);
+               memcpy(result->ptr, mf2->ptr, mf2->size);
+               result->size = mf2->size;
+       } else if (!xscr2) {
+               result->ptr = xdl_malloc(mf1->size);
+               memcpy(result->ptr, mf1->ptr, mf1->size);
+               result->size = mf1->size;
+       } else {
+               status = xdl_do_merge(&xe1, xscr1, name1,
+                                     &xe2, xscr2, name2,
 -                                    level, xpp, result);
++                                    flags, xpp, result);
        }
+       xdl_free_script(xscr1);
+       xdl_free_script(xscr2);
        xdl_free_env(&xe1);
        xdl_free_env(&xe2);