olechafm
olechafm

Reputation: 131

SVN merging branch-trunk-branch

I've done something stupid. I've merged trunk into my branch for synchro and commited, and than merged my branch to trunk without -reintegrate option and commited. Of course my branch is still in development process and I need it but I'm getting

svn: E195016 ...Reintegrate can only be used if revisions x throug y were previously merged from "http://some.pl/trunk" to the reintegrate source, but this is not the case Missing ranges ...

unfortunately trunk went forwardfrom that time, so my branch isn't up to date.

What's the best solution to fix it?

Upvotes: 0

Views: 395

Answers (1)

David W.
David W.

Reputation: 107090

Did you just do that? If so, you can use svn merge to unmerge your changes. Let's say you merged branch to trunk in Revision 1234:

$ svn co $repo/trunk
$ cd $trunk
$ svn merge -c -1234 .   # Removes the merge that took place in revision 1234

Let's understand what happens when you merge trunk to branch and branch back into trunk:

When you merge trunk to branch, you are doing a three point merge. That is, you're looking at the branch, the trunk, and the most recent common ancestor (MRCA) of the two development streams. You're looking not only for the differences between the file on branch and trunk, but the changes that took place on trunk as compared to that most recent common ancestor. I don't want trunk and the branch to match, I want the changes from MRCA to trunk to be applied, and to ignore the changes that have taken place from MRCA to the tip of that branch.

Subversion uses svn:mergeinfo to track what was and wasn't merged into your branch from trunk. It can use this to figure out what changes you no longer need to move into your branch. This way, your branch may have changed something previously merged, and you don't want to reimport from trunk.

Now, let's look at merging from the branch back into trunk. If I look at trunk, I see nothing from my branch has been merged into trunk. After all, I've just been doing trunk->branch merges. If I did a standard merge, all changes that took place on my branch, will be considered.

This even includes changes on my branch that I did on trunk, and then merged to my branch. After all, Subversion has no real way of knowing this. There's nothing on the trunk that shows this merge.

However, I usually want my trunk and branch to agree at this point. (Assuming I did a final merge from trunk to branch before I did the reintegration). Therefore, you want to do a two-point merge: You want to compare your branch version with the trunk, and after the merge, the version on the trunk should look like what it does on the branch.

In older versions of Subversion, this is what the --reintegrate parameter did. It forced Subversion to use a two-point merge instead of a three point merge. However, newer versions of Subversion now automatically understand when to do a reintegration merge.

So, what's the issue with the branch after a reintegration?

  • Revsion 99: You merge from trunk to branch and commit your change. On your branch, `svn:mergeinfo shows that everything on trunk up to Revision 99 has been merged into the branch.
  • Revision 100: You commit your merge from trunk into your branch.
  • Revision 100: Still on Revision 100, you do a checkout of your trunk. You want to do your reintegration merge from your branch to trunk.
  • Revision 100: You now do your reintegration merge. You see on your trunk that svn:mergeinfo says that all revisions from trunk up to Revision 100 have been merged into your trunk.
  • Revision 101: You commit your trunk merge.
  • Revision 102: You make a change and realize this should also be put into your branch.

Now, let's checkout revision 102 on your branch, and do that merge. What does that svn:mergeinfo say? It says that all revisions from trunk up to revision 99 have been merged into my branch. What is Subversion going to do? It will want to merge the changes from revision 100, 101, and 102 into your branch.

But wait a second! Revision 100 did not happen on trunk. It happened on the branch. That's okay. Revision 102 includes that change you want on the branch. But, revision 101 is the merge you did from the branch back onto trunk. Subversion is going to attempt to merge all of the changes I originally did on my branch and merged into trunk back onto my branch! This is not good.

What to do? There are two solutions:

  • The simplest is to delete the branch and recreate it. After all, at the point where you did the reintegration merge, you've branch and trunk should have been identical. In theory, there's nothing wrong with this. However, you'll lose your branch's history.

  • The other thing you can do is to make Subversion think that you've merged the change in Revision 101 onto your branch without actually doing the merge. You could do this by editing svn:mergeinfo yourself, but this can be a bit error prone.

A better way is to use the --record-only option on the merge:

$ svn co REPO/branch/1.2
$ cd 1.2
$ svn merge -r101 --record-only $REPO/trunk
$ svn commit -m"Rev 101 was my reintegration merge from 1.2->trunk"

All better. Now, when I try to do my merge, Subversion will merge Revision 102 on trunk into my branch, but not my reintegration revision.

In fact, if I did the --record-only merge right after my reintegration merge, I could have done this:

$ cd 1.2
$ svn merge --record-only $REPO/trunk

That's because all other revisions -- except for my reintegration merge -- were already on the branch. All I've done is update svn:mergeinfo to include revision 101 from trunk.

So, for your first mistake, it may be okay. Check to see if trunk and your branch agree at that point. As I said, newer versions of Subversion understand that merging back from branch to trunk should be a reintegration merge -- even if you didn't include the --reintegration parameter. If not, you might have a bit more work to untangle the situation.

For your second mistake, do a --record-only merge from trunk to branch to update the svn:mergeinfo. If you can't, you might have to munge svn:mergeinfo by hand. It's not all that difficult to do use svn propedit, and you can edit the property in your favorite editor. The format of svn:mergeinfo is pretty obvious, so adding in an extra revision isn't that difficult.

Always remember. This is version control. Nothing is permanently damaged. You can always go back to an earlier version of your repository, and try again. The worst thing you get is a record of your blunderous ways permanently etched into svn log.

If that's the worst thing that has ever happened in your life, you have lead a highly blessed existence on this rocky little planet.

Upvotes: 1

Related Questions