I've just reviewed the recent thread about whether we should put
conflict markers in files, or continue using .rej files as we have
been, or do something else entirely. There was no clear consensus,
but some important principles nevertheless emerged. Although many of
us started by saying "I do/don't like conflict markers", further
discussion revealed the real issue to be a perceived tradeoff between
convenience and information preservation -- people who like conflict
markers lauded the ease of editing the newly marked-up working file,
whereas people who don't like conflict markers were opposed to the way
the working file gets all mucked up (i.e., information loss).
Based on the discussion, here is a new proposal. Its guiding
principles are that
a) Update and merge should be consistent with each other in conflict
handling [I hope this is not controversial!]
b) We should (locally) preserve all information that could be
useful in resolving the conflict.
c) We should behave as similarly to CVS as possible -- the Principle
Of Least Surprise. This is really important, and was not given
enough attention in the previous discussion imho. There's no
point being gratuitously different if we can be an intuitive
The proposal is simply:
Updates and merges use 3-way diff. If there are conflicts, we put
conflict markers into the working file, and save the following
three files somewhere obvious: the old working file, the old
text-base, and the new unmodified file (i.e., the right-side merge
source, which in `svn update' is simply the new text-base).
The conflict time is recorded in .svn/entries. At commit time, we
error if the working file has not been modified since the conflict.
Otherwise, we allow the commit, and automatically remove the other
three files (which are just sitting in the working directory with
Here is a more formal description of the above. First, definitions:
OLD-BASE: The unmodified original revision of the file.
MERGE-BASE: The left-side source of the merge; in updates,
this is the same as OLD-BASE, in merges, it is
MERGE-TGT: The unmodified new revision of the file. In
updates, this also becomes the new text-base.
OLD-WORKING: OLD-BASE + pre-merge local mods
MERGED-WORKING: `diff3 -Em OLD-WORKING MERGE-BASE MERGE-TGT`
If there were no conflicts, then the merge replaces OLD-WORKING with
MERGED-WORKING (and in the update case, MERGE-TGT becomes the new
text-base; but in the merge case, we simply don't keep MERGE-TGT).
If there *were* conflicts, we still replace OLD-WORKING with
MERGED-WORKING, but we also save OLD-BASE, OLD-WORKING, and MERGE-TGT
in the working directory, with intuitive extensions. We remove them
at commit time, if the commit succeeds. The commit does not succeed
unless MERGED-WORKING has been modified since the conflict was
received, or if --force is passed.
(Also, "svn update" should probably remove those extra files whenever
it touches a conflicted file, or maybe punt or otherwise behave
specially on conflicted files; but that's bikeshed-painting at this
point, we can perfect it later.)
Note that this proposal does not preserve all the information when a
*non*-conflicting merge is done into a locally modified file.
Interestingly enough, no one seemed to consider that important. We
seem to be paranoid about information loss in the conflict case only.
Seems like a practical attitude to me, fwiw.
Further Note: Yes, this does pretty much obviate the need for Sean
Russell's nifty patchify.sh script. Sorry about that, Sean!
I think this way pretty much addresses all the concerns raised. While
awaiting comment, I'm going to proceed as if implementing the above
proposal, since under the hood it doesn't differ greatly from other
plausible solutions, and it's a lot easier to code for a known target
than for a scatter plot :-). So don't panic if you see checkin
comments referring to the above behavior as a goal.
To unsubscribe, e-mail: email@example.com
For additional commands, e-mail: firstname.lastname@example.org
Received on Sat Oct 21 14:37:09 2006