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

Re: Handling of move/rename on merge

From: <kfogel_at_collab.net>
Date: 2004-07-02 20:09:45 CEST

[I've CC'd this response to the dev@ list, as I think it might be of
interest there too.]

"Tor Ringstad" <tor.ringstad@tandberg.net> writes:
> Consider the following two scenarios involving merging from a branch A
> into a branch B, when some file has been modified on one branch and
> renamed/moved on the other.
>
> 1) File was modified on A and moved/renamed on B
>
> (copy) (mod)
> r12 r14
> foo.c ---x--------x---> branch A
> |
> \----x-------> branch B
> r13
> (mv)
>
> A merge of r12:r14 from A to B just gives me "Skipped missing target".
>
> I would have expected subversion to merge the changes of the file on
> branch A into the "same" file on branch B, no matter what the file was
> named or where it was located on B.
>
> Am I doing something wrong, doesn't subversion support this behaviour,
> or do I simply have strange expectations?

Your expectation is not strange, but unfortunately Subversion doesn't
support this behaviour (yet). We plan to implement real merge
tracking in the future, which I trust would include this scenario.

> 2) File was moved/renamed on A and modified on B
>
> (copy) (mv)
> r12 r14
> foo.c ---x--------x---> branch A
> |
> \----x-------> branch B
> r13
> (mod)
>
> A merge of r12:r14 from A to B gives something similar to this;
>
> % svn merge -r12:14 http://.../branchA
> A foo_with_new_name.c
> D foo.c
>
> As expected, the rename is merged, and foo.c changes name to
> foo_with_new_name.c on B. What surprises me this time, is that
> foo_with_new_name.c from A completely replaces foo.c from B, i.e. the
> modification in r13 is lost.

Yup. This is mostly because we don't have real merge tracking, and
partially because our rename support is still weak.

Let me share with you some of the development history behind these
issues, just so you have a sense of why things are the way they are,
and how they can one day be better.

Ideally, a rename should not change the underlying object identity of
the renamed object. But Subversion (as currently implemented) takes a
somewhat weird view of renames. When the user requests a rename,
here's what Subversion actually does:

   svn cp oldname newname
   svn rm oldname

Why? Well, basically because of working copy semantics. We wanted
the user to be able to commit one side of the rename without being
forced to commit the other. For example:

   $ cd wc
   $ svn mv subdir1/fileA.txt subdir2/fileB.txt
   $ svn ci -m "Commit just the add of fileB.txt." subdir2

After this series of operations, the addition of fileB.txt is
committed, but the removal of fileA.txt is still just a local mod in
the working copy.

I think there's now a consensus among the developers that we were
wrong to allow renames to be split up like this. Fortunately, the fix
is backwards compatible and not that difficult: we implement a first
class rename operation in the Subversion repository code (easy), and
make sure the working copy code errors instead of allowing the user to
commit just one side of a rename. This fix would get us to the right
place regarding object identity, though by itself it wouldn't add
merge tracking, of course.

But you can imagine how, in the past, this was a controversial
proposal: Why should the client error when, conceptually, it can do
what the user asked, or some reasonable facimile thereof? (Answer:
because it turns out it isn't a reasonable facsimile after all.)

Anyway, given how Subversion behaves today, the behavior you expected
above becomes problematic. Here's why:

As we've seen, rename is currently

   svn cp oldname newname
   svn rm oldname

Clearly, it would be consistent for there to be N copies before the
'svn rm', instead of just 1 copy, thus:

   svn cp oldname newname1
   svn cp oldname newname2
   svn cp oldname newname3
   svn rm oldname

In other words, right now a rename can look like this:

  oldfile ------------------> newfile

or it can just as easily look like this:

                ,--------> newfile1
               /
              /
  oldfile ---+-----------> newfile2
              \
               \
                `--------> newfile3

Let us consider the latter case. If a change is made to oldfile on
the branch, and oldfile has been "renamed" to three new files on
/trunk, then when you merge the branch change into /trunk, which of
the new files should receive the change? All three? Just one? None?

Obviously the answer is:

Don't implement renames this way. Instead, implement them in a way
that preserves object identity completely, and therefore doesn't allow
objects to multiply as a result of a rename :-).

Hope this helps,
-Karl

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@subversion.tigris.org
For additional commands, e-mail: users-help@subversion.tigris.org
Received on Fri Jul 2 21:40:43 2004

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