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

Re: Merger not Merging -- What I would like a merge process to do.

From: Ben Collins-Sussman <sussman_at_collab.net>
Date: 2005-01-24 07:15:12 CET

On Jan 23, 2005, at 11:13 PM, matthew ford wrote:

> Yes the last one was a real mess. Try this one.
> Hi again Ben,
> I really appreciate your assistance. It is what keeps me going.
> I have never used diff, but have quite happly used CVS merge and it
> worked
> as ( I ) expected.

Can you be more specific? There is no 'cvs merge' command. The
equivalent CVS commands ('cvs up -j') behave the same way 'svn merge'
does. So I'm a bit perplexed as to why you find CVS so intuitive, and
Subversion not. Both programs are just acting as wrappers around the
unix 'diff' and 'patch' commands.

> This is what I would like 'merge' to do for me (assuming the common
> case of
> a common ancester)
> i) If the file is in the branch:HEAD and was not in the trunk at the
> time
> the branch was made add it to the trunk:WC if it does not exist.
> If it exists in trunk:WC merge differences/conflicts line by line.

Yes, 'svn merge' does this.

> ii) If the file is in the branch:HEAD and WAS in the trunk at the time
> the
> branch but has since been deleted in the trunk:WC then add and mark as
> conflict.

No. The fact that the trunk is missing the file is irrelevant. If the
file didn't change in the branch, then there's no change to apply.

> iii) If the file is deleted in the branch:HEAD and is still in the
> trunk:WC
> then mark as conflict.

Not exactly. If the file was deleted on the branch, then when you
merge the branch changes to the trunk working copy, the file will be
scheduled for deletion, just as if you had run 'svn rm' on the file.

> iv) If the files exist in both branch:HEAD and trunk:WC merge changes
> and
> mark lines that conflict.

Yes, but *only* if the file changed on the branch.

> How can I do this using subverion?

Again, here is the misconception. You want to literally blend the
contents of two trees together, as equal trees. CVS doesn't do that.
Subversion doesn't do that. I don't know of any tool that does that.

CVS and Subversion "merges" aren't about blending trees. The main goal
is to duplicate changes from one place to another. The idea is that
code 'forks' at some point. The trunk changes for a while, and the
branch changes for a while. When the branch work is done, the goal is

   1. isolate all the changes made to the branch
   2. duplicate those changes on the trunk.

That's what it means to "merge the branch to the trunk", in CVS and
Subversion terminology. The end result is that the trunk still has all
of its changes, *plus* the changes from the branch.

Step #1 is accomplished by comparing two trees. Typically, you compare
two snapshots of the branch: the way the branch looked when it was
first created, and the latest version of the branch. 'svn diff' is a
good way of isolating/previewing such changes:

        svn diff -r X:Y branchURL

... where X is the revision in which the branch was created, and Y is
the latest HEAD revision.

Step #2 is accomplished by asking 'svn merge' to apply changes to your
working copy. You would enter a working copy of the trunk, and run

        svn merge -r X:Y branchURL

The merge command, just like the diff command, compares the two branch
snapshots, and then applies the patch to the working copy. The result
is a bunch of local edits; it looks just as if you had edited the
files yourself with your editor. If you like the result, 'svn commit'
and you're done. If you don't like the result, 'svn revert'.

I've now essentially reexplained chapter 4, so I don't know how to be
any clearer.

I understand your request for smart merging: why can't svn
automatically know how to isolate the branch changes? If doing
repeated merges, why can't it remember the last time it merged? Why
can't 'svn merge' keep track of what it's doing? These are all things
that users want, and that developers want too. It's been discussed to
death. We have definite plans to add these things in the future. You
don't need to explain them to us, or ask for them, or prove to us that
they're good things. They will definitely happen someday. :-)

For now, Subversion's merging abilities are the same as CVS's. There's
no need to be "filled with dread". It works just fine. It just
requires that humans pay a bit of attention to what they're doing.
It's not optimal, but really, it's not a tremendous burden either.

> What I have is branch == trunk plus some changes and latest trunk =
> trunk
> plus some changes
> Cannot seem to get a conflict on the points where the changes
> intersect.
> In the case above there also is no common ancester between
> trunk and branch, but you should be able to handle that?

Yes, that's exactly what the --ignore-ancestry option is for: for
those times when there's no common ancestor in the repository, and you
want the merge command to do "dumb diffs" rather than "smart diffs".
Read about it here:


> C:\temp\svnTrunk>svn merge -r 13:HEAD
> svn://localhost/svnRepos/branches/1
> C oldFileInTrunk.txt
> A newInBranch.txt
> This almost worked. Now I get a conflict on the change
> <<<<<<< .working
> This file existed in trunk prior to branch b1 has been modified in
> trunk
> =======
> This file existed in trunk prior to branch b1 has been modified in b1
>>>>>>>> .merge-right.r16
> but there is no report to tell me that the trunk has deleted a file
> that is
> in the branch and which the branch may depend on.

The trunk's history is irrelevant here. You are isolating a collection
of branch changes, and applying them to a working copy. The patch
either applies cleanly, or it doesn't. There's no "report" about
differences between branch and trunk. You aren't doing a general
comparison between branch and trunk! You're trying to apply a patch to
a working copy.

The only case in which the the trunk's missing file would be relevant
is if the branch changed the file. Then the 'branch patch' would try
to change the file in the working copy, but the file wouldn't be there.
  You'd get a definite error and conflict then.

In other words: if one line of development deletes a file, and another
line of development does nothing to the file, then there's no conflict:
  the lines of development "merge" just fine. The final result is a
tree in which the file continues to be gone. That's the situation you
have here.


 From what I can tell, I think it's going to be impossible to do what
you want, given your starting data set. It sounds like you have two
lines of development, both which started out from a common ancestor.
Each line of development has changed over time. And now you want to
"merge" the lines by replicating the branch changes to the trunk. BUT:
if you don't have the common ancestor available, it CANNOT BE DONE.

In other words, if tree A is the common ancestor of B and C:

         A ----------> B
           |---------> C

What you need to do, in order to merge the lines, is compare A and B,
and apply the resulting patch to C. Or you need to compare A and C,
and apply the resulting patch to B. That's the only way to get get
*all* of the changes from both lines of development into the same line.
  If you compare B and C, then you'll end up with a patch that "adds"
the feature of C, and "removes" the features of B. That's bad.

If you don't have the common ancestor available, there's nothing
Subversion or CVS can do. Nor can the unix 'diff' and 'patch' tools
help. My official suggestion is that you get all three trees into
Subversion via 'svn import', then run

      cd working-copy-of-C
      svn merge --ignore-ancestry url-to-A url-to-B
      svn commit

To unsubscribe, e-mail: users-unsubscribe@subversion.tigris.org
For additional commands, e-mail: users-help@subversion.tigris.org
Received on Mon Jan 24 07:24:37 2005

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