On Tue, Oct 09, 2012 at 05:23:30PM +0200, Martin Bischoff wrote: > I have a project which is being developed on /trunk, and at the same time I > have a branch (/branches/1.x) for maintenance of version 1.x. > > Now I'd like to rename a folder of the project, e.g. /trunk/a to /trunk/b. > The same folder should also be renamed on the maintenance branch, so that > future bugfixes (made inside /trunk/b) can be merged to the branch. > > If I merge the revision (in which /trunk/a was renamed to /trunk/b) to the > branch, then it seems that files inside /branches/1.x/b will then be > identical copies of the files inside /trunk/b at the HEAD revision. This > means, that for example, any changes made directly on /branches/a/text.txt > are then lost. > > Obviously I'm doing something wrong! > > What is the correct procedure to merge a rename of a folder to a branch? > > Should I rename the folder independently on both trunk and the branch? Will > I then still be able to merge changes from /trunk/b to /branches/1.x/b?
Yes. See below for details. > BTW: I'm using the current version of TortoiseSVN, so I can't give the > exact svn commands that were used. > > Thanks a lot for any help. > > -Martin The following instructions work for me with the command line client. I'm making some assumptions though, not sure if these apply to your particular case: - The folder A is renamed to B on trunk in a revision I'll call N. Ideally, there are no unrelated changes in this revision, just the rename (not a strict requirement but it makes resolving the tree conflict much simpler). - The branch has merged all desired changes from trunk up to revison N-1. It's Ok if you haven't merged *all* revisions up to N-1 from trunk to the branch. But any changes up to N-1 you desire should have been merged to avoid conflicts if revisions older than N-1 are merged in the future. So if there are any such revisions which haven't been merged yet, merge them now. Given these assumptions, here's one way of merging the rename on the branch (there are others, but there is no need to talk about them if the below works for you): Get a working copy of the branch at HEAD. In this working copy, rename folder A to B. Don't commit! Instead of committing, merge just rN from trunk, using TortoiseSVN's "Merge a range of revisions" merge option, using just N for the revision range parameter. Two tree conflicts will be flagged. Here's what the above looks like in the command line client, with N=4: $ svn merge -c4 ^/trunk --- Merging r4 into '.': C B C A --- Recording mergeinfo for merge of r4 into '.': G . Summary of conflicts: Tree conflicts: 2 $ svn status M . D C A > local delete, incoming delete upon merge A + C B > local add, incoming add upon merge Summary of conflicts: Tree conflicts: 2 The first line showing M is a mergeinfo change. The incoming delete of A conflicts with the local delete of A. This happened because both sides (trunk, and branch) decided to rename A to B, and Subversion cannot yet tell the difference between a normal deletion and a deletion that happens as part of a move (which sucks, and we're trying to fix this, but that's a separate discussion). In this particular case, deleting A is the desired conflict resolution outcome. Since the working copy is already set up to delete A during the next commit, we can just mark the tree conflict on A as resolved: $ svn resolved A Resolved conflicted state of 'A' $ Now, what about B? Check the URL of B in the 'Subversion' tab of the directory's properties dialog in Windows. On the command line you can use the 'svn info' command for this purpose. In my case this is: $ svn info B | grep Copied\ From\ URL Copied From URL: file:///tmp/svn-sandbox/repos/branch/A So clearly it's a copy from the branch, not from trunk! This happened because we renamed the folder before running the merge, forcing a tree conflict, so that Subversion won't add 'B' as a copy from trunk. You might also want to verify that the content in files with B still matches what you expect, just to make sure (and this is where things get more complicated if you also have other changes in rN...) Since the directory B is precisely in the state we want it to be in, we can also just mark the conflict resolved: $ svn resolved B Resolved conflicted state of 'B' $ Now commit the entire working copy. This commit will mark revision N as merged from trunk and rename A to B on the branch. Future merges from trunk will expect a path B instead of A, and work as expected. For instance, merging r6 from trunk which changed a file B/zeta just works: $ svn merge -c6 ^/trunk --- Merging r5 through r6 into '.': G B/zeta --- Recording mergeinfo for merge of r5 through r6 into '.': G . $ I hope this helps. If you have further questions feel free to ask.