[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: Problems during merge

From: Neels J Hofmeyr <neels_at_elego.de>
Date: Fri, 12 Feb 2010 02:44:23 +0100

Christoph Bartoschek wrote:
> Am Donnerstag, 11. Februar 2010 schrieb Neels J Hofmeyr:
>> Hi Christoph,
>>
>> it would be nice if you could provide a way to reproduce this issue. I am
>> aware that this can be some work, and we would highly appreciate it. :)
>
> Hi,
>
> here is the script. When it comes to choosing the merge operation I choose
> (p). The file dir_b/file has the wrong conflict markers.
>
> Christoph

Hi Christoph,

I found a minimal representation of your problem and dove into the code up
to the technical paper underlying the diff algorithm.
http://research.janelia.org/myers/Papers/np_diff.pdf

The smallest representation I found is attached in script form.
It merges:

(I put some '|' in there to show the length of the three respective versions)

left:
|OLD
|

right:
|NEW
|

working:
|
|NEW

(you actually had a working of:
|
|NEW
|
but the last blank line has no effect on the merge outcome)

To understand what's going on, it helps to mark the blank line; the diff
algorithm treats blank lines the same as any other lines and thus finds them
as equal. Let's see:

left:
|OLD
|foo

right:
|NEW
|foo

working:
|foo
|NEW

What happens now is that the change from 'left' to 'right' is seen as
replacing line 1 with 'NEW'. Makes sense.

But the change from 'left' to 'working' is seen as
 i) deleting line 1 and then, independently from that,
ii) appending 'NEW' *after* 'foo'.

This is a different representation of the change than we humans would expect
with blank lines instead of 'foo', but it is a correct one. Furthermore,
'foo' nicely separates the "two changes" in 'working'.

Only one part conflicts: 'Working' deletes line one, while 'right' wanted to
replace line one. You thus see a conflict:

[[[
<<<<<<< .working
=======
NEW
>>>>>>> .merge-right.r3
]]]

The second change in working is appending 'NEW' (or anything else) to the
end, which does *not* conflict. So all you see is the second change merged
in without problems after the conflict.

[[[
<<<<<<< .working
=======
NEW
>>>>>>> .merge-right.r3

NEW
]]]

It's all correct. Sigh.

That said, while it's technically right, this *is* quite annoying. Seeing
blank lines' matching as strong as other lines is not really desirable,
IMHO. In fact, the humanly intuitive way has less diff chunks:

[[[
<<<<<<< .working

NEW
=======
NEW

>>>>>>> .merge-right.r3
]]]
(all changes accounted for in only one change chunk.)

I am wading far out of my depth when saying this, but I have a hunch that if
we were to not see blank lines as individual lines but only as tails to
non-blank lines, that we might then get more intuitive diffs.

Immediately, I get reservations. Implemented just like I said it, it would
mean that we get conflicts like this:

[[[
<<<<<<< .working
SAME THING

=======
SAME THING

>>>>>>> .merge-right.r3
]]]
(trailing blank lines, when seen as tails to non-empty lines, can make
actually identical lines appear different)

So there would also have to be an algorithm that filters out
trailing-newlines-only changes back to

[[[
SAME THING

<<<<<<< .working
=======

>>>>>>> .merge-right.r3
]]]

Christoph, do you have anything to add at this point? ;)

It would sure be nice to make blank lines less aggressive in diffs. I often
see diffs where, now that I think of it, the blanks "matching" all over are
messing up readability. (I just recalled to have thought this before, heh)

This is not about fixing an error, this is about choosing a different
correctness that better suits the eye...

~Neels

#!/bin/bash

## TO MAKE THIS RUN YOUR CUSTOM COMPILED SVN, two simple options:
## 1. Adjust your PATH to point at your custom installed location:
## export PATH="$HOME/prefix/svn_trunk/bin:$PATH"
## OR
## 2. Uncomment the four lines below to use aliases into your
## built source tree. The next line is the only line you should
## need to adjust.
# SVNDIR=/path/to/built_subversion_source_tree
# function svn() { ${SVNDIR}/subversion/svn/svn "$@"; }
# function svnserve() { ${SVNDIR}/subversion/svnserve/svnserve "$@"; }
# function svnadmin() { ${SVNDIR}/subversion/svnadmin/svnadmin "$@"; }

set -e

svn --version
REPOS="`pwd`/repos"
URL="file://$REPOS"
rm -rf repos wc
svnadmin create repos

# enable all revprop changes
cat > repos/hooks/pre-revprop-change <<EOF
#!/bin/sh
exit 0;
EOF
chmod a+x repos/hooks/pre-revprop-change

svn co -q ${URL} wc

set +e
set -x
cd wc

mkdir dir_a
##############################################################################
cat > dir_a/file << EOF
OLD
 
EOF
##############################################################################

svn add dir_a
svn ci -m "Adding dir_a"

svn cp dir_a dir_b
svn ci -m "Copying"
svn up

##############################################################################
cat > dir_a/file << EOF
NEW
 
EOF
##############################################################################

svn ci -m "Changing dir_a/file"

##############################################################################
cat > dir_b/file << EOF
 
NEW
EOF
##############################################################################

cd dir_b
svn merge --accept=postpone ${URL}/dir_a/ .
cat file

svn resolve --accept=theirs-conflict file
cat file

Received on 2010-02-12 02:45:04 CET

This is an archived mail posted to the Subversion Users mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.