views:

240

answers:

4

The situation is that I've spent some time messing around with some experimental code. I now want to move part of that code - about 500 lines - into another file, but I don't want to lose the history, as I would if I do a simple text-editor cut and paste.

As close as I know how to get is separating the code out of the original file - svn copy, then delete unwanted stuff from both copies. But I don't know how to then append that partial copy onto an existing file, keeping the history from both.

The reason this is important is basically that the code is just pretty specialised stuff, to help implement some higher level functions. I don't want it polluting global namespaces, so I want it all in the one file where it will be used and wrapped in an anonymous namespace.

I realise this sounds like merging a branch back into the trunk. The thing is, there is no branch. The experimental code didn't start as a copy of anything - it's just a bunch of started-from-scratch code. The file I want to cut from and the one I want to paste into are completely independent files.

I mostly use TortoiseSVN, but have command-line subversion installed too.

+1  A: 

If you want to copy in a new file and delete the old file :

svn mv

If you want to duplicate in a new file :

svn copy

If both file already exists :

# copy/paste with a text editor

You can delete a file an keep its history with :

svn del

With SVN you cannot keep trace of the history of a merge of two file. You can merge it by hand and keep a trace in the commit message.

Natim
None of these give me a file containing text (and history) from two source files. Text editor copy/paste preserves the history from both in the repository, true - nothing is ever deleted - but the history from the file you cut from is detached from the file that you pasted to. In TortoiseSVN terms, Blame will blame everything on the cut-and-paster, and not on the people who made the coding decisions.
Steve314
It all the tools that Subversion give you. You should probably using some DVCS. TortoiseMercurial exists for Windows users.
Natim
By the way I don't understand exactly what you expect by merging the history of two file. it doesn't make sense. What kind of rollback do you have in mind ? You can add a comment at the beginning of your file to say that it is a merge of this file and another in revision rXXXX
Natim
Rollback isn't the issue. It's about keeping track of design decisions. The log is excellent design documentation, explaining why you made the decisions you made. The ability to view differences between versions, or to see why each line was last changed in blame, is invaluable.
Steve314
This would of course call for a bit of discipline on everyone's part but I think adding meaningful commit comments explaining why you made the changes each time would help when you extract a log.
Critical Skill
+4  A: 

I don't think you can preserve history in the way you are describing. SVN keeps track of history on a file-by-file basis, and it won't keep track of two separate files that are combined together on the same code line.

If you started out with two separate files and then combine them together into a third, then the history of both will be preserved. If you combine one into the other, then the history of one of them will be "lost" in the sense that you won't be able to link back to the history of the "deleted" file just from looking at the history.

I guess what you could do is in the commit message just note that the content from the other file was combined and then commit the delete in the same commit.

Ken Liu
I had a feeling that was the answer. Not accepted yet on the off-chance - I'll have another look tomorrow just in case.
Steve314
+7  A: 

You can merge all revisions (or specific revisions) of one file into another like this

svn merge sourcefile targetfile -r 0:HEAD

At first I thought one would have to use the --ignore-ancestry option (since both files don't share any common history) but apparently this is not necessary. I tested with svn 1.6.3.

You are of course very likely to get alot of conflicts markers in the merge result. It may be easier to do the merge by hand (a copy and paste merge as you say), and then run the above merge command with --record-only to tell subversion about it.

After the merge, the targetfile will have a svn:mergeinfo property which indicates which commits from sourcefile where merged into it. When you examine the log of targetfile, you can see the history of both files by using the --use-merge-history option. TortoiseSVN has the same feature in the form of a checkbox in the log form.

Wim Coenen
That's pretty clever.
msemack
I suspect that this won't quite do what I want, but I'm convinced it's the best I'll get (short of svn dump hacking), so I'm accepting. Thanks.
Steve314
You'll have the commit log, but all the lines in your changes will have the same revision marker in the 'blame'.
Xavier Nodet
wow, I stand corrected. I guess I'm not that familiar with the new merge tracking features. I think this will only work on svn 1.5+ (maybe 1.6+).
Ken Liu
A: 

Can't you leave the code in its own file (after trimming the parts you don't want to keep) and include this file into your 'real' source file?

// file foo.cpp:
...
namespace {
#  include "util_code.inc"
}

Not really orthodox, but should work...

Xavier Nodet
I don't like that style of #include use. Got used to this-is-the-spec, that-is-the-body conventions in other languages a long time ago. That's probably why the idea didn't even occur to me - but it's not that bad, I suppose, given a range of imperfect choices. Too late this time - but there's always a next time.
Steve314
Thanks. I would of course not recommend a general use of such #include directives. But I did use them to include generated code:#define THE_CLASS MyClass#include method_bodies.incwith method_bodies.inc looking like this:void THE_CLASS::generatedMethod() { ...}I was thus able to generate some, but not all, methods of a class without the generator knowing the name of the class.
Xavier Nodet