commit - c6368c2e90c223c41439b12ae7f14fffbd894dfa
commit + d136cfcb987bd2fd865f8711449dc47b7f63455f
blob - e7951e14f2548e423ecb820f33291e316d6819ee
blob + d8e2403ac8b60843492a2228a507dad1ac532791
--- lib/diff3.c
+++ lib/diff3.c
struct diff {
struct line_range old;
struct line_range new;
+ struct off_range oldo;
struct off_range newo;
};
/*
* "de" is used to gather editing scripts. These are later spewed out
* in reverse order. Its first element must be all zero, the "new"
- * component of "de" contains line positions and byte positions.
+ * component of "de" contains line positions, and "oldo" and "newo"
+ * components contain byte positions.
* Array overlap indicates which sections in "de" correspond to lines
* that are different in all three files.
*/
};
-static const struct got_error *duplicate(int *, struct line_range *,
+static const struct got_error *duplicate(int *, int, struct line_range *,
struct line_range *, struct diff3_state *);
static const struct got_error *edit(struct diff *, int, int *,
struct diff3_state *);
}
/* stuff peculiar to third file or different in all */
if (d1->new.from == d2->new.from && d1->new.to == d2->new.to) {
- err = duplicate(&dpl, &d1->old, &d2->old, d3s);
+ err = duplicate(&dpl, j, &d1->old, &d2->old, d3s);
if (err)
return err;
/*
* Set *dpl to 1 or 0 according as the old range (in file 1) contains exactly
* the same data as the new range (in file 2).
+ *
+ * If this change could overlap, remember start/end offsets in file 2 so we
+ * can write out the original lines of text if a merge conflict occurs.
*/
static const struct got_error *
-duplicate(int *dpl, struct line_range *r1, struct line_range *r2,
+duplicate(int *dpl, int j, struct line_range *r1, struct line_range *r2,
struct diff3_state *d3s)
{
const struct got_error *err = NULL;
int nchar;
int nline;
size_t nskipped;
+ off_t off;
*dpl = 0;
err = skip(&nskipped, 1, r2->from, d3s);
if (err)
return err;
+
+ off = ftello(d3s->fp[1]);
+ if (off == -1)
+ return got_error_from_errno("ftello");
+ d3s->de[j + 1].oldo.from = off; /* original lines start here */
+
nchar = 0;
for (nline = 0; nline < r1->to - r1->from; nline++) {
do {
if (d == EOF)
return got_ferror(d3s->fp[1], GOT_ERR_EOF);
nchar++;
- if (c != d)
- return repos(nchar, d3s);
+ if (c != d) {
+ long orig_line_len = nchar;
+ while (d != '\n') {
+ d = getc(d3s->fp[1]);
+ if (d == EOF)
+ break;
+ orig_line_len++;
+ }
+ if (orig_line_len > nchar &&
+ fseek(d3s->fp[1], -(orig_line_len - nchar),
+ SEEK_CUR) == -1)
+ return got_ferror(d3s->fp[1],
+ GOT_ERR_IO);
+ /* original lines end here */
+ d3s->de[j + 1].oldo.to = off + orig_line_len;
+ err = repos(nchar, d3s);
+ if (err)
+ return err;
+ return NULL;
+ }
} while (c != '\n');
}
err = repos(nchar, d3s);
err = prange(&d3s->de[n].old, d3s);
if (err)
return err;
- } else {
+ } else if (d3s->de[n].oldo.from < d3s->de[n].oldo.to) {
+ /* Output a block of 3-way diff base file content. */
err = diff_output(d3s->diffbuf, "%da\n%s\n",
+ d3s->de[n].old.to -1,
+ GOT_DIFF_CONFLICT_MARKER_ORIG);
+ if (err)
+ return err;
+ if (fseeko(d3s->fp[1], d3s->de[n].oldo.from, SEEK_SET)
+ == -1)
+ return got_error_from_errno("fseeko");
+ k = (size_t)(d3s->de[n].oldo.to - d3s->de[n].oldo.from);
+ for (; k > 0; k -= len) {
+ len = k > BUFSIZ ? BUFSIZ : k;
+ if (fread(block, 1, len, d3s->fp[1]) != len)
+ return got_ferror(d3s->fp[1],
+ GOT_ERR_IO);
+ block[len] = '\0';
+ err = diff_output(d3s->diffbuf, "%s", block);
+ if (err)
+ return err;
+ }
+ err = diff_output(d3s->diffbuf, "%s\n",
+ GOT_DIFF_CONFLICT_MARKER_SEP);
+ if (err)
+ return err;
+ } else {
+ err = diff_output(d3s->diffbuf, "%da\n%s\n",
d3s->de[n].old.to -1, GOT_DIFF_CONFLICT_MARKER_SEP);
if (err)
return err;
blob - f3ddb3fb288bda4b679437664c0f0f403351969d
blob + 0d74b1bbdb78b195fcfd6b16c5042af2a781aa5f
--- lib/got_lib_diff.h
+++ lib/got_lib_diff.h
};
#define GOT_DIFF_CONFLICT_MARKER_BEGIN "<<<<<<<"
+#define GOT_DIFF_CONFLICT_MARKER_ORIG "|||||||"
#define GOT_DIFF_CONFLICT_MARKER_SEP "======="
#define GOT_DIFF_CONFLICT_MARKER_END ">>>>>>>"
blob - d5083e047e683d5211b8352a65aeb41fea0facb2
blob + 0454b55efa3ced59507448a4ccee518a3a29f74e
--- regress/cmdline/diff.sh
+++ regress/cmdline/diff.sh
fi
sed -i 's/2/22/' $testroot/repo/numbers
+ sed -i 's/8/33/' $testroot/repo/numbers
git_commit $testroot/repo -m "modified line 2"
local head_rev=`git_show_head $testroot/repo`
- # modify line 2 in a conflicting way
+ # modify lines 2 and 8 in conflicting ways
sed -i 's/2/77/' $testroot/wt/numbers
+ sed -i 's/8/88/' $testroot/wt/numbers
echo "C numbers" > $testroot/stdout.expected
echo -n "Updated to commit $head_rev" >> $testroot/stdout.expected
echo 'file + numbers' >> $testroot/stdout.expected
echo '--- numbers' >> $testroot/stdout.expected
echo '+++ numbers' >> $testroot/stdout.expected
- echo '@@ -1,5 +1,9 @@' >> $testroot/stdout.expected
+ echo '@@ -1,8 +1,20 @@' >> $testroot/stdout.expected
echo ' 1' >> $testroot/stdout.expected
echo "+<<<<<<< commit $head_rev" >> $testroot/stdout.expected
echo ' 22' >> $testroot/stdout.expected
+ echo '+|||||||' >> $testroot/stdout.expected
+ echo '+2' >> $testroot/stdout.expected
echo '+=======' >> $testroot/stdout.expected
echo '+77' >> $testroot/stdout.expected
echo '+>>>>>>> numbers' >> $testroot/stdout.expected
echo ' 3' >> $testroot/stdout.expected
echo ' 4' >> $testroot/stdout.expected
echo ' 5' >> $testroot/stdout.expected
+ echo ' 6' >> $testroot/stdout.expected
+ echo ' 7' >> $testroot/stdout.expected
+ echo "+<<<<<<< commit $head_rev" >> $testroot/stdout.expected
+ echo ' 33' >> $testroot/stdout.expected
+ echo '+|||||||' >> $testroot/stdout.expected
+ echo '+8' >> $testroot/stdout.expected
+ echo '+=======' >> $testroot/stdout.expected
+ echo '+88' >> $testroot/stdout.expected
+ echo '+>>>>>>> numbers' >> $testroot/stdout.expected
(cd $testroot/wt && got diff > $testroot/stdout)
blob - 0d64a54e87019fb4decc9861f1e2c2da67aba905 (mode 755)
blob + c94727a0b05067fb3a4deadd1017588265245e68 (mode 744)
--- regress/cmdline/rebase.sh
+++ regress/cmdline/rebase.sh
echo "<<<<<<< commit $orig_commit1" > $testroot/content.expected
echo "modified alpha on branch" >> $testroot/content.expected
+ echo "|||||||" >> $testroot/content.expected
+ echo "alpha" >> $testroot/content.expected
echo "=======" >> $testroot/content.expected
echo "modified alpha on master" >> $testroot/content.expected
echo '>>>>>>> alpha' >> $testroot/content.expected
echo "<<<<<<< commit $orig_commit1" > $testroot/content.expected
echo "modified alpha on branch" >> $testroot/content.expected
+ echo "|||||||" >> $testroot/content.expected
+ echo "alpha" >> $testroot/content.expected
echo "=======" >> $testroot/content.expected
echo "modified alpha on master" >> $testroot/content.expected
echo '>>>>>>> alpha' >> $testroot/content.expected
echo "<<<<<<< commit $orig_commit1" > $testroot/content.expected
echo "modified alpha on branch" >> $testroot/content.expected
+ echo "|||||||" >> $testroot/content.expected
+ echo "alpha" >> $testroot/content.expected
echo "=======" >> $testroot/content.expected
echo "modified alpha on master" >> $testroot/content.expected
echo '>>>>>>> alpha' >> $testroot/content.expected
echo "<<<<<<< commit $orig_commit1" > $testroot/content.expected
echo "modified alpha on branch" >> $testroot/content.expected
+ echo "|||||||" >> $testroot/content.expected
+ echo "alpha" >> $testroot/content.expected
echo "=======" >> $testroot/content.expected
echo "modified alpha on master" >> $testroot/content.expected
echo '>>>>>>> alpha' >> $testroot/content.expected
blob - 1cdd63392f3e865270de6ffdb9b10cb96f773a41 (mode 755)
blob + e6d70015b1a31739a3a1e5e9030d441b97f92102 (mode 744)
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
git_show_head $testroot/repo >> $testroot/content.expected
echo >> $testroot/content.expected
echo "modified alpha" >> $testroot/content.expected
+ echo "|||||||" >> $testroot/content.expected
+ echo "alpha" >> $testroot/content.expected
echo "=======" >> $testroot/content.expected
echo "modified alpha, too" >> $testroot/content.expected
echo '>>>>>>> alpha' >> $testroot/content.expected
git_show_head $testroot/repo >> $testroot/content.expected
echo >> $testroot/content.expected
echo "modified alpha on new branch" >> $testroot/content.expected
+ echo "|||||||" >> $testroot/content.expected
+ echo "alpha" >> $testroot/content.expected
echo "=======" >> $testroot/content.expected
echo "modified alpha in work tree" >> $testroot/content.expected
echo '>>>>>>> alpha' >> $testroot/content.expected