views:

174

answers:

3

Part of the development I have done on a project can not be deployed, and should have been done in a separate branch. I have merged in the backwards changes (via tortoise's "revert changes from this revision" and careful editing), undoing the work that should have been in a separate branch, and committed this inverse patch to the trunk. I would now like to create a branch that includes the changes that were undone in the aforementioned patch. Here is what I did:

I created a new branch for the new development at the revision prior to the undo revision.

I merged the undo revision into the new branch via merge a range of revisions in tortoise SVN.

I opened the change log, selected "Include merged revisions", and "revert changes from this revision". This reverted these changes in my working copy. It is now what I would like the branch to be like. I committed these changes. This commit lists the undo patch under "include merged revisions"; I do not believe it should do so; there seems to be a problem here. The key is probably to record this patch (the inverse squared, or the product of the original modifications) in such a way that subversion is ignorant of the operation performed to create it.

I then merged all of the changes from trunk into the new branch via the same method (merging a range of revisions). This included the original undo patch a second time, making my branch identical to trunk (listing it now thrice as an included merged revision). This is not the desired result.

<Edit - Solution>

The following is the desired behavior, and works correctly:

First I created an empty repository with folders tags, trunk, branch. In trunk I created a file file.txt with the content (rev1):

one
two
three

Then edit the file to

one
two_edit
three

And checked in (rev2). Then I selected rev2 in the log and picked revert changes from this revision and checked in (rev3). The file now looks like this again:

one
two
three

I then created a branch of trunk from rev3 to branches\b1 (rev4, was5; this step does both). In branches\b1 the file looks like this:

one
two
three

I then reverse merge rev2 from trunk into branches/b1 ignoring ancestry (rev5). The branch now looks like this, and it is now sheer coincidence that the history contains something similar:

one
two_edit
three

I edit the trunk (rev6) to look as follows:

one
two
three
four

I merge all changes from the trunk into branches/b1 (rev7). branches/b1 now correctly looks like:

one
two_edit
three
four

</Edit - Solution>

<Edit>

How it should work

The following is the desired behavior, and works correctly if the italicized step is performed as follows:

First I created an empty repository with folders tags, trunk, branch. In trunk I created a file file.txt with the content (rev1):

one
two
three

Then edit the file to

one
two_edit
three

And checked in (rev2). Then I selected rev2 in the log and picked revert changes from this revision and checked in (rev3). The file now looks like this again:

one
two
three

I then created a branch of trunk from rev2 to branches\b1 (rev4). In branches\b1 the file looks like this:

one
two_edit
three

I then merge rev3 from trunk into branches\b1 (rev5), the branch now looks like this:

one
two
three

I edit branch 3 (rev6) as if I were branching at this point. It is now sheer coincidence that the history contains something similar:

one
two_edit
three

I edit the trunk (rev7) to look as follows:

one
two
three
four

I merge all changes from the trunk into branches/b1 (rev8). branches/b1 now looks like:

one
two_edit
three
four

How it does work

The following is the actual behaviour; it works incorrectly if the italicized step is performed, which is necessary because of the complexity of the retroactive branch. The error is in the second line of the final step.

First I created an empty repository with folders tags, trunk, branch. In trunk I created a file file.txt with the content (rev1):

one
two
three

Then edit the file to

one
two_edit
three

And checked in (rev2). Then I selected rev2 in the log and picked revert changes from this revision and checked in (rev3). The file now looks like this again:

one
two
three

I then created a branch of trunk from rev2 to branches\b1 (rev4). In branches\b1 the file looks like this:

one
two_edit
three

I then merge rev3 from trunk into branches\b1 (rev5), the branch now looks like this:

one
two
three

In branches\b1 I selected rev5 in the log and picked revert changes from this revision and checked in (rev6). The file now looks like this again:

one
two_edit
three

I edit the trunk (rev7) to look as follows:

one
two
three
four

I merge all changes from the trunk into branches/b1 (rev8). branches/b1 now looks like:

one
two
three
four

</Edit>

+1  A: 

In the TortoiseSVN branch dialog choose "Specific revision in the repository", use the ... button to pick the last revision you want to have in your new branch.

Proceed as usual when branching.

<Edit>

I tried to reproduce your problem, it is quite hard to follow what is in the trunk and what is in the branch, but this is how I did.

First I created an empty repository with folders tags, trunk, branch. In trunk I created a file file.txt with the content (rev1):

one
two
three

Then I edited the file to

one
two_edit
three

and checked in (rev2). Then I selected rev2 in the log and picked revert changes from this revision and checked in (rev3). The file now looks like this again:

one
two
three

I then created a branch of trunk from rev2 to branches\b1 (rev4). In branches\b1 the file looks like this:

one
two_edit
three

Then I edit the file like this in trunk and check in (rev5)

one
two
three
four

Then I merge from trunk to branches\b1 picking only rev5 and commit (rev6). Now branches\b1\file.txt looks like this

one
two_edit
three
four

Everything is merged as I expected.

Where in this process does it go "wrong" to you?

</Edit>

Albin Sunnanbo
That's how to start this process, not how to prevent the undo patch from being applied again after undoing it in the branch. I would like to be able to merge the branch back into trunk eventually, merging the undo of the undo in.
Cirdec
One way is to reverse merge the undo of the undo from trunk to trunk before merging the changes from the branch to the trunk. But way better and more natural would be to create a release branch of the code with the undo patch (that is your current trunk) and let the trunk be where you continue when that release is done. One way to do that is rename trunk to branches\release_whatever and then rename your branches\next_release (your current branch) to trunk.
Albin Sunnanbo
I rewrote my question in terms of your example.
Cirdec
+1  A: 

The key is probably to record this patch (the inverse squared, or the product of the original modifications) in such a way that subversion is ignorant of the operation performed to create it.

I think you are talking about trying to block merge tracking, a.k.a. mergeinfo, from being recorded in the branch. I think you can do this using svn diff or svn merge --ignore-ancestry. Read the SVN Redbook on Advanced Merging, specifically Merges Without Mergeinfo and Noticing or Ignoring Ancestry.

Rather than branching from rev2, it might be easier to create a branch off the trunk from rev3, and then apply/capture the changes from rev1 to rev2 in the branch of rev3 using svn diff or svn merge --ignore-ancestry.

Alternatively, you could look at svn merge --record-only to fake a merge in order to block a rev from future merges, i.e. convince the branch or trunk that you already merged the undo change so it doesn't get applied again.

Bert F
The first solution (merging ignoring ancestry) works like a charm. Thanks!
Cirdec
+5  A: 

Hi Cirdec.

The problem you described (and your solution) is pretty common. Of course it would have been smarter to start the development of the "not-to-go-live" changes in a separate branch right away but I know its not a perfect world we live in and things change ;).

Fortunatly with a good version controll system such as SVN you can bring any change from any time to allmost anywhere. And there is multiple different ways to do that too. So while you answered your question for yourself allready I took the freedom to draft how I understand your problem and how I would have solved it. The chart below will serve for inhouse purpose too so no harm done if it doesnt help you any more.

On a side note: I am not so familar with tortoise but I guess it makes cherrypicking (reverse cherrypicking in your case) easier than the SVN commandline. Especialy if you have many scattered commits to select. I'd still prefer the CLI for merge operations as it often gets so much clearer what the hell I am doing right now ;)

I wish you conflict-free merges my friend ;)

Christoph

repository time chart

Christoph Strasen
Great picture, except we didn't have the "fail release". The key to performing the "reverse merge" shown is in Bert F's response.
Cirdec
Thanks. Well maybe I dont get it right yet but to perform the reverse merges (multiple needed to get rid of the code, only one needed to recreate it in the branch) I would not use record-only anywhere. That is unless you want to keep out the red change from getting back into the trunk EVER :D
Christoph Strasen