Subversion: How to merge only specific revisions into trunk when multiple consecutive changes are made in a branch?
Asked Answered
L

8

18

I have been using TortoiseSVN, svn, and subclipse and I think I understand the basics, but there's one thing that's been bugging me for a while: Merging introduces unwanted code. Here's the steps.

trunk/test.txt@r2. A test file was created with 'A' and a return:

A
[EOF]

branches/TRY-XX-Foo/test.txt@r3. Branched out the trunk to TRY-XX-Foo:

A
[EOF]

branches/TRY-XX-Foo/test.txt@r4. Made an unwanted change in TRY-XX-Foo and committed it:

A
B (unwanted change)
[EOF]

branches/TRY-XX-Foo/test.txt@r5. Made an important bug fix in TRY-XX-Foo and committed it:

A
B (unwanted change)
C (important bug fix)
[EOF]

Now, I would like to merge only the important bug fix back to trunk. So, I run merge for revision 4:5. What I end up in my working directory is a conflict.

trunk/test.txt:

A
<<<<<<< .working
=======
B (unwanted change)
C (important bug fix)
>>>>>>> .merge-right.r5
[EOF]

Against my will, Subversion has now included "unwanted change" into the trunk code, and I need to weed them out manually. Is there a way to merge only specified revisions when multiple consecutive changes are made in the branch?

The part of the problem is that B (unwated change) is included in .merge-right and I can't tell the difference between which revision it came from. I usually use TortoiseMerge and here's how it looks.

text.txt.working

Lashawnda answered 29/11, 2008 at 0:9 Comment(4)
To do a more realistic test you should add some 'context' between the lines you change. The textual diff and merge tools need a few lines of context between the changes to perform automatic merges. When the context is not large enough you will see the conflict as shown in your last example.Macrocosm
@Bert: please put it as answer, so it can be voted. I think you have a point here.Chrysarobin
can you edit your image width, it's throwing off the questions text.Profant
LFSR Consulting is very right about the picture, can someone please shrink it?Ypsilanti
L
5

The problem is that both svn

A
<<<<<<< .working
=======
B (unwanted change)
C (important bug fix)
>>>>>>> .merge-right.r341

and TortoiseSVN is treating the situation as 2-way merge. I've heard of the term 3-way merge, so I gave Beyond Compare a shot. With quick set up with TortoiseSVN, Edit Conflict now bring up the following screen. This is not perfect, since it's still requiring human intervention, but at least I can tell which changes are coming from where.

See screenshot.

Lashawnda answered 14/12, 2008 at 0:14 Comment(4)
Using the subclipse merge view you can enable the original view which will get you the three way merge view. Check the top right corner.Embarrassment
Please put this information in your question, because this is an answer.Sophrosyne
@guerda, I am posting the use of 3-way merge tool as an answer.Lashawnda
technically, you are just changing how you present your data. the text above is already a 3-way merge. just in a 1-D presentation. the regular merge is a 2-D presentation. you have to choose one of the files as the output, and add/remove changes while comparing to the other... 3-way merge is just a way to preserve the two file diff, while changing a third file. so, technically, you could solve your problem even with the 1-D diff on the text above (the one with <<<< and ==== )Phane
S
39

Merging only revisions 4,7, and 11-15 with svnmerge:

svnmerge.py merge -r4,7,11-15

And with regular svn:

svn merge -c4,7 -r10:15 http://.../branches/TRY-XX-Foo
Solstice answered 29/11, 2008 at 0:15 Comment(5)
Running from command line still produced the same result as TortoiseSVN, causing conflict and pulling in unwanted changes.Lashawnda
Sorry, I guess I don't understand your scenario. Cherry-picking revisions to merge works just like I show (and evidently, like you tried), I'm not sure what's the problem.Solstice
Orips answer should be right and give you the result you want. Maybe you didn't leave revision 5 out in your command-line statement. Then obviously you would pull the change into the merge.Kaiser
@eed3si9n: I had a already formed branch, added a (unwanted) change to a file, then added a wanted change to the same file and did an svn merge -c$revision URL into the trunk of the project. Here $revision was the revision number of the wanted change. After the merge I got only the wanted change.Kaiser
I did everything on the command line only with a -c option because for the test I only added 2 further revisions as in your example.Kaiser
L
5

The problem is that both svn

A
<<<<<<< .working
=======
B (unwanted change)
C (important bug fix)
>>>>>>> .merge-right.r341

and TortoiseSVN is treating the situation as 2-way merge. I've heard of the term 3-way merge, so I gave Beyond Compare a shot. With quick set up with TortoiseSVN, Edit Conflict now bring up the following screen. This is not perfect, since it's still requiring human intervention, but at least I can tell which changes are coming from where.

See screenshot.

Lashawnda answered 14/12, 2008 at 0:14 Comment(4)
Using the subclipse merge view you can enable the original view which will get you the three way merge view. Check the top right corner.Embarrassment
Please put this information in your question, because this is an answer.Sophrosyne
@guerda, I am posting the use of 3-way merge tool as an answer.Lashawnda
technically, you are just changing how you present your data. the text above is already a 3-way merge. just in a 1-D presentation. the regular merge is a 2-D presentation. you have to choose one of the files as the output, and add/remove changes while comparing to the other... 3-way merge is just a way to preserve the two file diff, while changing a third file. so, technically, you could solve your problem even with the 1-D diff on the text above (the one with <<<< and ==== )Phane
G
2

I believe you are including the revisions you want correctly, but the merge algorithm is failing to find the place to insert the wanted change and so including the line above it also. Here are the same steps but with a different set of changes, and I believe it works as you expected originally:

$ svnadmin create repo
$ svn mkdir -m '' file://`pwd`/repo/trunk

Committed revision 1.
$ svn mkdir -m '' file://`pwd`/repo/branches

Committed revision 2.
$ svn co file://`pwd`/repo/trunk co.trunk
Checked out revision 2.
$ cat > co.trunk/test.txt << EOF
> A
> B
> C
> EOF
$ svn add co.trunk/test.txt
A         co.trunk/test.txt
$ svn commit -m '' co.trunk
Adding         co.trunk/test.txt
Transmitting file data .
Committed revision 3.
$ svn copy -m '' file://`pwd`/repo/trunk file://`pwd`/repo/branches/testbr

Committed revision 4.
$ svn co file://`pwd`/repo/branches/testbr co.testbr
A    co.testbr/test.txt
Checked out revision 4.
$ cat > co.testbr/test.txt << EOF
> A
> A1 unwanted
> B
> C
> EOF
$ svn commit -m '' co.testbr
Sending        co.testbr/test.txt
Transmitting file data .
Committed revision 5.
$ cat > co.testbr/test.txt << EOF
> A
> A1 unwanted
> B
> B1 wanted
> C
> EOF
$ svn commit -m '' co.testbr
Sending        co.testbr/test.txt
Transmitting file data .
Committed revision 6.
$ svn merge -r 5:6 file://`pwd`/repo/branches/testbr co.trunk
--- Merging r6 into 'co.trunk':
U    co.trunk/test.txt
$ cat co.trunk/test.txt
A
B
B1 wanted
C
Gravamen answered 28/1, 2009 at 15:2 Comment(0)
Y
2

Well to clarify a thing about merge is that it actually has 2 steps.

  1. Merge
  2. Commit

So that means that after your merge is done, you can do a manual diff against head and the other branch to make sure that the merge was correct. And if something was wrong with it, like in your case, you can manually fix it before the commit.

/Johan

Ypsilanti answered 29/1, 2009 at 6:20 Comment(0)
T
2

In TortoiseSVN, you must only specify the revisions you want to merge. Unlike the command line client where you have to specify e.g. -r4:5 to merge the changes between r4 and r5, you only have to specify '5' as the revision number to merge in the TortoiseSVN merge dialog. If you're not sure, always use log dialog from the merge dialog and select the revisions you want to merge in that log dialog (then click OK and the selected revisions will automatically get set in the merge dialog).

As for resolving your conflict in TortoiseMerge: According to the screenshot in your question, TortoiseMerge shows you two conflicted lines (the ones shown as '????' in the bottom view). What you want is to include the change 'C' but not 'B'?

  • left click on the first '???' line to select it, then right-click, choose 'use block from "mine"' from the context menu
  • left click on the second '???' line to select it, then right-click, choose 'use block from "theirs"' from the context menu
  • Click the save button (or File->Save)
  • Optionally click on the "Mark as resolved" button
Terror answered 30/1, 2009 at 7:41 Comment(4)
First of all, thank you for the great tool. I've been keeping up with TortoiseSVN updates, so I know that you need to specify 5, instead of 4-5.Lashawnda
In this simplified example, it's easy to tell the "unwanted" part, but Subversion shouldn't have brought any changes from r4. In reality, it's hard to tell which part came from the unwanted revision that I did not specify. I frequently merge branch changes written by others.Lashawnda
Well, Subversion didn't actually merge r4. The problem you're seeing here is that Subversion encountered a conflict, and to indicate that conflict it not only marks the conflicting lines but also 1 line around the conflicting lines (i.e., context lines). If you had a line D, that line would alsoTerror
be included in the conflict. So actually, it still is easy to spot those 'unwanted' lines. Also, it you had more context lines (this example has almost no context lines, almost all lines are include din the merge), Subversion would be much more accurate with the merge.Terror
W
1

Another thing you could do would be to manually undo the bad commit on the branch, which would then allow you to merge the branch back into the trunk as you would normally.

TortoiseSVN

Using TortoiseSVN you open up the log view on a file, select the offending version, and choose "Revert changes from this revision" from the right click menu. Commit the changes it makes on your working copy and then you can merge the branch back in easily.

Command Line

To do this with the command line client you perform a reverse merge, (This is taken from the Pragmatic Source Control using Subversion book) where you merge the changes between the offending version and the previous version into the working copy of the file. Then as above you'd commit the changes and can then branch normally. In your example you would do something like:

svn merge -r 4:3 test.txt
Wateriness answered 28/1, 2009 at 7:6 Comment(1)
Undoing is not an option since the unwanted changes in branches/TRY-XX-Foo/ represent half-baked features, not ready to get merged into trunk.Lashawnda
J
1

As pointed out by other users (I won't take credit for noticing it because I didn't), it may be the trivial nature of this merge (i.e. lack of context around the change) that is confusing the tools.

I do a lot of merging and, as you discovered, the merge tool provided by Tortoise is awful. A three-way merge tool is an absolute must if you do this very often. Beyond Compare is my personal favorite, but there are other that are free (Meld, KDiff3) and ones that are not (Araxis).

You will notice that Beyond Compare did the right thing in the end, even if it makes you manually verify it correctness!

Jeffryjeffy answered 28/1, 2009 at 18:55 Comment(1)
Lack of context is certainly is the key, thus "multiple consecutive changes".Lashawnda
H
0

If you don't want the unwanted change, do not merge revision 4:5, but just revision 5. It means you merge the change committed in revision 5.

Head answered 29/11, 2008 at 0:58 Comment(1)
4:5 means take the difference between 4 and 5 and apply it to the working directory. I've tried -c5 command line option, but the result is the same.Lashawnda

© 2022 - 2024 — McMap. All rights reserved.