What's SVN's actual use of mergeinfo?

devoured elysium

I've long heard about svn's merge-conflict troubles.

I was relieved, thought, when I learnt that svn a couple of releases ago implemented a feature called mergeinfo. It almost seemed as if its introduction would allow svn to have enough information to solve its merging issues whenever they popped up. Until I got into the following situation:

enter image description here

Scripted example of the above graph:

SVN=${SVN:-svn}
SVNADMIN=${SVNAMDIN:-svnadmin}

rm -rf repo wc

$SVNADMIN create repo

$SVN co file://$PWD/repo wc
cd wc

# r1
$SVN mkdir trunk branches
$SVN ci -m 'structure'
$SVN up

# r2
echo 2 > trunk/t.txt
$SVN add trunk/t.txt
$SVN ci -m 'add t.txt'
$SVN up

# r3
$SVN cp trunk branches/A
$SVN ci -m 'create branch A'
$SVN up

# r4
echo 4 > branches/A/a.txt
$SVN add branches/A/a.txt
$SVN ci -m 'add a.txt'
$SVN up

# r5
$SVN cp trunk branches/B
$SVN ci -m 'create branch B'
$SVN up

# r6
echo 6 > branches/B/b.txt
$SVN add branches/B/b.txt
$SVN ci -m 'add b.txt'
$SVN up

# r7
$SVN merge ^/branches/B branches/A
$SVN ci -m 'merge branch B into A'
$SVN up

# r8
echo 8 > branches/A/d.txt
$SVN add branches/A/d.txt
$SVN ci -m 'add d.txt'
$SVN up

# r9
$SVN merge ^/branches/A branches/B

If svn is keeping history of where each branch is coming from, why can't it understand that b.txt was left untouched @ branch A?

if it can't figure this out, what actual use does svn make of mergeinfo?

If svn is incapable of dealing with this issue, wouldn't it be possible to create a tool to aid me (namely auto-resolving this kind of no-brainer issues..) in this front? I'd guess maybe one would already exist?

Thanks

David W.

There are two types of merging in Subversion:

  1. Three-point merges
  2. Two-point merges (aka reintegration merging)

Let's say you're working on trunk, and you have a particular feature that needs to be done. You create a Feature A branch. As you work on the feature, you want the work you do on trunk to be included in Feature A, just so you can keep up with what everyone else does. Subversion will use a three-point merge.

Subversion will look at the difference between trunk and branch Feature A from the point that the branch occurred. The most recent common ancestor. It then considers all of the changes on Feature A that was done (which you don't want to touch) as well as the changes in the code done on trunk.

Subversion will then merge the changes on trunk without overwriting the changes made on the branch. Standard merge procedure, and Subversion does that quite well.

Where does svn:mergeinfo come in? You don't want to merge twice the same changes, so Subversion tracks the changes with the svn:mergeinfo property. If Subversion sees that the change in trunk from Revision 5 has already been merged in, it won't remerge that change. It's very good with this.

Now, you're finished with your feature, and you want those changes to be merged back into trunk. You do one last trunk to branch merge, commit those changes, and now merge from the Feature branch back into trunk.

Here's a bit of a problem. We tracked what we merged from trunk into the Feature branch via svn:mergeinfo. However, since we haven't merged from the Feature branch to trunk, there's no svn:mergeinfo there. If we attempt a normal three-point merge from the Feature branch into trunk, the trunk will assume that all of the changes in the Feature branch should be merged back into the trunk. However, many of those features are actually trunk changes that had been merged.

Truthfully, at this point, we want to do a two-point merge. We want both trunk and the Feature branch to match exactly once we do the merge. After all, we've been merging trunk into the Feature branch on a regular basis now. What we want to do is to incorporate those features back into trunk. Thus, the trunk will be the same as the feature branch.

Before Subversion 1.8, you would have to force a reintegration merge by running svn merge --reintegration. Now, Subversion will look at the merge history and figure out when a reintegration merge should be done.


Now here's the tricky part. Take a careful look at the revision numbers. These will be very, very important!

  • Revision 10: I made my final changes into Trunk, and I need to merge these into the Feature branch.
  • Revision 11: I merge trunk into the Feature branch. svn:mergeinfo will show that all of trunk from Revision 1 to Revision 10 is in the Feature branch. Since the last change on trunk is Revision 10, this makes perfect sense.
  • Revision 12: I merge Revision 11 of the Feature Branch into trunk. This is a reintegration merge. After this what is on the Feature branch and what is in trunk should agree perfectly.

Now, here's the kicker!

  • Revision 13: I make another change in trunk.

Now, I want to merge this into my Feature branch (creating Revision 14). Now, what does the svn:mergeinfo on the feature branch say? It says that trunk from Revision 1 to Revision 10 has been merged into the Feature branch. However, Revision 12 and Revision 13 of trunk have not been. Therefore, Subversion will want to merge Revision 12 and Revision 13 back into the Feature branch.

But wait a second!

Revision 12 on trunk was my merge of all changes in my Feature branch back into trunk! That is, Revision 12 already contains all of the revision changes I've made in my Feature branch. If I merge Revision 12 back into my Feature branch, I'll be saying that all of these changes in Revision 12 on trunk (which were really changes made on the feature branch and merged into trunk) need to be merged onto the feature branch. But, these changes were also made on the Feature branch. Can you say Merge Conflict? I knew you could!


There are two way to handle this:

  • The recommended way: Once you reintegration your feature branch back into trunk, delete the branch. Lock it. Never use it again. Don't touch! This isn't as bad as it sounds. After the reintegration merge, your trunk and that feature branch will match anyway. Deleting and recreating the branch from trunk will not be all that bad.
  • The tricky way which works: What we need to do is to trick Subversion into thinking that Revision #12 (or reintegration merge changes) was already merged into our Feature branch. We could futz around with the svn:mergeinfo property. And, I use to do just that. Where it says trunk:1-11, I would manually change it to trunk:1-12.

    This is tricky, but way too tricky, and risky because Subversion already gives you a way to manipulate the svn:mergeinfo without manually changing it.

It's called a record only merge.

$ svn co svn://branches/feature_a
$ cd feature_a
$ svn merge --record-only -c 12 svn://trunk
$ svn commit -m "Adding in the reintegration merge back into the feature branch."

This changes the svn:mergeinfo on the feature branch without affecting the actual content of the files. No real merge is done, but Subversion now knows that Revision 12 of trunk is already in the Feature branch. Once you do that, you can reuse the feature branch.


Now look at your diagram: When you merged Branch B into Branch A, you merged all of the changes from B into A, and svn:mergeinfo tracked that. When you merge Branch B back into Branch A, you already have all of the changes from Branch B in Branch A, and you don't want these changes to be brought back into branch B. You should have used a reintegration merge:

$ cd $branch_a_working_dir
$ svn merge $REPO/branches/B
$ svn commit -m "Rev 7: All of my changes on Branch B are now in A"
$ vi d.txt
$ svn add d.txt
$ svn commit -m"Rev 8: I added d.txt"
$ cd $branch_b_working_dir
$ svn merge --reintegrate svn://branch/A  # Note this is a REINTEGRATION merge!
$ svn commit -m"Rev 9: I've reintegrated Branch A into Branch B

Now, if we want to continue using branch A for further changes:

$ cd $branch_a_working_dir
$ svn merge -c 9 --record-only $REPO/branches/b
$ svn commit -m"I've reactivated Branch A and can make further changes"

I hope this explains a bit about how svn:mergeinfo works, why you have to know whether you're using the normal three-point merge vs. the two-point reintegration merge, and how to be able to reactivate a branch after you've done a reintegration merge.

As long as you keep this in mind, Subversion merging works pretty well.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Reverse Merge and svn:mergeinfo

From Dev

What's the svn revert equivalent in git?

From Dev

What's the actual type of lambda in C#?

From Dev

What's the actual download size of Gimp?

From Dev

what's the actual difference between print and return

From Dev

What's the use of \$$ in bash?

From Dev

What's the use of lightmap?

From Dev

what is the use of %.*s in this program

From Dev

How to remove lingering svn:mergeinfo properties on reintegrate?

From Dev

What's the use for all of shutdown's options?

From Dev

Phabricator/SVN - What's the best way to manage multiple subdirectories of a repository?

From Dev

What's the best procedure for clearing out unwanted files in an SVN repo?

From Dev

What's the actual meaning of 'two requests to the server' in this context?

From Dev

What's the maximum actual bit rate of an 802.11g connection?

From Dev

What is the actual purpose of GNU grep's -X option and why is it undocumented?

From Dev

What's the difference between the initramfs and the actual main filesystem?

From Java

What are the use(s) for tags in Go?

From Dev

What's the use of AsEnumerable() on an array?

From Dev

What's the use of Open Radar?

From Dev

What's the use of a circular reference?

From Dev

What's the use of "flag" in pandas

From Dev

What's the use of complete command?

From Dev

What's (really) the use of the <a> tag?

From Dev

What's the use of search domains?

From Dev

Windows subnetmask, what's the use?

From Dev

What's the use of 'typedef in C'?

From Dev

What's wrong with this use of redirection?

From Dev

What's the use of OSchedule in OrientDB?

From Dev

What's better to use and why?

Related Related

HotTag

Archive