February 21, 2007
SvnMerge enables you to track which changes on another branch have been merged into your current working branch. This means that you won’t accidentally merge the same change twice. SvnMerge isn’t a trivial tool to use, so we’ll need to discuss how we are using it, and define some terminology.
Feature Branch: A branch that you are merging changes FROM. There can be more than one Feature Branch, gathering up features from multiple developers.
Target Branch: The branch that you are merging changes TO. There is generally only ONE Target Branch.
In this article, we are going to discuss how to use SvnMerge to track changes on one or more Feature Branches, into a single Target Branch. It is also possible to merge your Target Branch into one of the Feature Branches, but we won’t examine that.
SvnMerge works by storing within subversion, meta information about actions on your files/directories . By doing this it can tell whether a particular change has been merged from Feature to Target. However, because SvnMerge does not automatically commit this information, it is up to you to commit this info into Svn each time you perform an SvnMerge action. We will look into this specifics of that later.
SvnMerge is shipped with Subversion, but can also be downloaded from here: http://www.orcaware.com/svn/wiki/Svnmerge.py. ; It’s a Python script, although there is a windows executable available too. If you use the Python script you’ll need the latest version of Python: http://www.python.org/download/. ; Install Python from the installer, and put SvnMerge.py somewhere on your PATH.
Type SvnMerge.py –version to check that SvnMerge is installed correctly. It should display something along the lines of:
C:devTesttrunkmike2>svnmerge.py --version svnmerge r<unknown> modified: <unknown>Copyright (C) 2004,2005 Awarix Inc. Copyright (C) 2005, Giovanni BajoC:devTesttrunkmike2>
SvnMerge is used from the command line, so some familiarity with that is assumed. Some familiarity with the svn command-line tools is also assumed, although you can also see what’s going on using the TortoiseSvn GUI.
First we have to tell SvnMerge which changes have happened on this directory BEFORE the Feature Branch was created. This is a tricky bit. Open a command window and cd into the Feature Branch directory (e.g., c:\dev\f1222)
Note down the list of revisions before and upto the creation of the Feature Branch. For example, in this log output:
C:devTestbranchesmike2>svn log ------------------------------------------------------------------------ r2616 | e151145 | 2006-12-06 12:25:01 +0000 (Wed, 06 Dec 2006) | 1 linecreating branch ------------------------------------------------------------------------ r2615 | e151145 | 2006-12-06 12:24:33 +0000 (Wed, 06 Dec 2006) | 1 linecreated in trunk/ ------------------------------------------------------------------------
The versions in question are 2615-2616. You will also need the full Svn URL of your Feature Branch, e.g., http://subversion.ny.company.com/svn/repos/OnSite/test/branches/mike2. ; You can get this by cd’ing into your Feature Branch directory and typing “svn info”. Now that we have this information, we can initialise SvnMerge. CD into the Target Branch directory, and issue this command:
svnmerge.py init -r2615-2616 http://subversion.ny.company.com/svn/repos/OnSite/test/branches/mike2
where 2615-2616 is replaced with your versions, and the URL is replaced with your Feature Branch URL. If all goes well, you should get a message back like this:
property 'svnmerge-integrated' set on '.'
As mentioned earlier, you need to commit any changes created by using SvnMerge. SvnMerge creates a standard merge comment for you, in a file called svnmerge-commit-message.txt. If you issue the following command, you will check the changes into Subversion:
svn ci -F svnmerge-commit-message.txt
This should give you a result along the lines of
Sending mike2Committed revision 2625.
You must now delete the svnmerge-commit-message.txt file. SvnMerge requires that the branch it works on be free of uncommitted files. So do:
SvnMerge is now initialised. Note that you only have to go through this process once for each branch whose changes you want to track.
Once initialised, SvnMerge is relatively easy to use.
to show the list of available merges from all initialised branches.
To peform a merge, type: svnmerge merge -r<revisionNumber> where <revisionNumber> is the range of revisions that came up from svnmerge avail. Example flow:
C:devTesttrunkmike2>svnmerge avail 2624,2655 C:devTesttrunkmike2>svnmerge merge -r2624,2655 U file2.txt property 'svnmerge-integrated' set on '.' C:devTesttrunkmike2>svn ci -F svnmerge-commit-message.txt Sending mike2 Sending mike2file2.txt Transmitting file data . Committed revision 2656. C:devTesttrunkmike2>del svnmerge-commit-message.txt
SvnMerge is capable of integrating from more than one Feature Branch. To do this, simply perform the Initialisation against each Feature Branch in turn. When using “svnmerge avail” or “svnmerge merge” you need to add the “-S” parameter, which you use to specify the path or URL. If you are making many integrations from multiple branches, it may be worth creating some environment variables containg the Feature Branch URLs.
It is possible that you want to switch off merge tracking on a branch. It is also possible that you will enter the wrong range of revision when doing an “svnmerge init”. In both cases you can call “svnmerge uninit” in the Target Branch directory, adding the -S <branch url> parameter if you have multiple feature branches. Once you have done the uninit, you will need to do an “svn ci -F svnmerge-commit-message.txt”. You can then run another “svnmerge init -r<range-range2> <url>” as before.
February 2, 2007
I discovered recently that running “installutil.exe” on a executable actually uses references the PDB files of that program. Therefore, if you’re deploying a new version of the service into your test environment you have to call “installutil /u” before you can overwrite the PDB files.
February 2, 2007
Ah, three days of work wasted because of somebody’s misguided “optimisation”. The optimisation in question involved the removal of a long-running worker thread and replacing it with a Threadpool.QueueUserWorkItem() call. Not only that, it was a call into a hokey third-party Threadpool implementation rather than the .NET one. The Subversion comment was “performance improvement”.
Rather than bang on about how this change obviously wasn’t tested (nothing worked afterwards) or how people should be careful about committing to Trunk, I will talk instead about optimisation.
Before any optimisation is done, there should be a problem. If an area of code is “performant enough” then there is no point in incurring the developing/test/release cost of any optimisation. That cost may be very small for one-person or a small team, but is considerably larger for a large team/multiple region/development stream application. So, the first thing you need is proof that something is actually causing a problem.
Secondly, you need to identify a change and ensure that it represents an improvement. I have lost count of the number of times I have seen people say “Oh, I made that [breaking] change to improve performance”. I will respond: where is your evidence that you improved performance? And even if it did improve performance (1) did performance need improving; (2) you BROKE the environment.
Unfortunately, in 500,000 line systems like the one I’m consulting on at present, a small change in one area of the code can have a massive impact of the final software that goes out of the door. We have four geographic regions, two software “flavours” and all of them use the same code in different but similar ways. So the potential for one small change to screw everything up is magnified by 8 time.
I am coming around to the idea that the NASA approach should be taken for projects over a certain size. Each change should be justified, recorded and signed off.
February 2, 2007
This is a plea to all developers out there working on apps that have a grid as their main user interface. Please please please write an interface between your code and the grid implementation.
Grids components have loads more functionality than is ever needed in a single project, and it’s likely that you’ll only use about 10-20% of it. Therefore, creating an interface that wraps around the grid should be relatively straightforward. From the top of my head I can think of a few interface members:
It may be that you have “UpdateRow()” rather than “UpdateCell()” if you change entire rows at once.
There are a couple of good reasons for interfacing off your grid access.
- You can change your underlying grid implementation:
Almost every project group I’ve joined who have used a grid say their grid isn’t fast enough. The kind of apps I work on (processing lots of real-time financial market information) make dozens of grid updates per second. However, moving from one grid to another has been very very hard, because the business/presentation code has been intertwined with the grid code. If you interface off the grid access, the migration only involves rewriting the hooks from the interface into the grid.
- The interface makes the available functionality obvious, and it prescribes one way of performing each task. Most grids offer at least two ways of doing each thing.
So please please put an interface between your business code and the grid. It will make your life easier, and it will make my life easier when I pick up your code in 3 years time.