You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@subversion.apache.org by Tor Ringstad <to...@tandberg.net> on 2004/07/02 17:36:18 UTC

Handling of move/rename on merge

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?

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.


- Tor Ringstad -




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@subversion.tigris.org
For additional commands, e-mail: users-help@subversion.tigris.org

Re: Handling of move/rename on merge

Posted by Tor Ringstad <to...@tandberg.net>.
> There's no lost data here.

I understand that no data is ever completely lost.

My point was that the modifications may be lost in the latest revision
of the working branch (branch B), and the user has to manually
scrutinize the merge logs to see if this has happened.

On one hand, this is no worse than CVS, so I shouldn't complain. On
the other hand it is somewhat worse, because subversion gives the
impression of supporting renames in that the "svn move" command
exists.


- Tor Ringstad -




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@subversion.tigris.org
For additional commands, e-mail: users-help@subversion.tigris.org

Re: Handling of move/rename on merge

Posted by Ben Collins-Sussman <su...@collab.net>.
On Mon, 2004-07-05 at 03:15, Tor Ringstad wrote:

> About the behaviour in scenario 2. Wouldn't you consider it
> unfortunate that the modifications to the local file is replaced
> without even a warning? I mean, in practice, this would force users to
> have to manually check every file that was deleted in a merge, first
> to see if it was part of a rename, then to see if there were any local
> modifications that were lost.

There's no lost data here.  In your second example, the merge causes the
old name to scheduled for deletion in the working copy and the
newly-named file to appear (as a copy of the earlier version of the
file).  But again, that delete operation doesn't lose data.  If the file
has local mods, it simply becomes unversioned.  If the file has no local
mods, the latest committed change isn't lost:  the "newer" text of the
file is still in the repository.  Heck, you can even 'svn revert -R' the
result of the merge if you don't like what you get.  Merges only produce
local mods anyway.






---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@subversion.tigris.org
For additional commands, e-mail: users-help@subversion.tigris.org

Re: Handling of move/rename on merge

Posted by Tor Ringstad <to...@tandberg.net>.
> Let me share with you some of the development history behind these
> issues, [...]

Thank you for taking the time to explain this. From other threads on
similar topics, I gather this isn't something that's going to be
implemented real soon. At least, for 1.1, you seem to have other
priorities.

About the behaviour in scenario 2. Wouldn't you consider it
unfortunate that the modifications to the local file is replaced
without even a warning? I mean, in practice, this would force users to
have to manually check every file that was deleted in a merge, first
to see if it was part of a rename, then to see if there were any local
modifications that were lost.


- Tor Ringstad -




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@subversion.tigris.org
For additional commands, e-mail: users-help@subversion.tigris.org

Re: Handling of move/rename on merge

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

"Tor Ringstad" <to...@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

Re: Handling of move/rename on merge

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

"Tor Ringstad" <to...@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: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org