Cross-Platform Development – Version Control

This is a follow-on article in the series about setting up both Linux and Windows for cross-platform development. The previous articles are:

The Master-Copy Problem

A key problem when developing for multiple platforms, such as developing Linux/Windows cross-platform programs, is how to manage different versions of the software. If you have a separate copy of the code on several different platforms, how do you know which is up to date? And fixing a bug on one platform while ongoing development is happening on the others means that no version is the most up to date one.

Of course, this is an ancient problem and occurs most often when working in teams, but it is a problem even if you are the only programmer when doing cross-platform development.

The Version-Controlled Master-Copy Paradigm

The only real solution to this problem is version control. Version control solves the master copy problem neatly and with a low overhead in administering the system. A centralised version control system has a central repository, and the idea is that the latest version in the repository is the “master” copy, and each copy outside of the repository is a “working” copy. So, in this example, there will be at least one working copy on each development platform. There will be many more working copies if there are multiple developers. But there will always be only one master copy.

Having made a change to one working copy, it can be committed to the master copy, at which point the changes become “legitimate”. Changes that haven’t been committed are not legitimate. You sometimes hear developers say “it doesn’t exist if it’s not committed”, but a more accurate statement is “it only exists for you and no-one else until it is committed” by which I mean that others cannot know about your work unless you’ve committed them to the master copy.

Software releases should only be made from a legitimate source, i.e. a working copy which has been entirely committed to the repository. This prevents bugs creeping back into code – a common problem where there is no such procedure where a release is made from a local copy with fixes that haven’t been committed, or have not been merged into the main code base. This means future releases will not have the fix…

Committing changes means that the master copy has changed. At some time, other working copies will need to be brought up to date with the master copy by merging the committed changes with their own working copy. This means, for example, that a bug fix on one platform will be merged with the working copy on the other platform. The other working copy can then be re-tested (to make sure the merge hasn’t broken anything) then committed itself, to become the latest master copy. And so on.

My preferred version control system is Subversion, since it has all the functionality I need and is familiar after years of use. In particular, it is a centralised version control system, meaning that it is based on the master copy concept. This type of version control is the best fit for the task at hand – cross-platform development for an individual or small team.

I also find centralised version control systems in general are much easier to use, easier to maintain and control than the latest distributed version control systems which are much more complex and require a larger effort in maintenance and procedures. I also suspect that the convenience reported by end-users of distributed version control is at the expense of a huge overhead for one or two key people who have to do the merging of different versions to make a release candidate.

However, I am not interested in arguments about whether it is the “best” – I use centralised version control because I prefer it; I find the centralised pattern simpler and more intuitive than the distributed pattern for the kind of projects that I work on.

Version Control for Cross-Platform Development

In order to implement the version-controlled master-copy paradigm when working on cross-platform development, you need version control client software installed on all platforms, and you need to have a repository running version control server software that is accessible to all developers on all platforms.

In a large company, you might achieve this by having a designated version-control server. However, if you are a small or one-person team, as I am, then a better solution is to use online or cloud storage for the repository.

There are many cloud storage systems about, although not all run version control server software. My research uncovered rsync.net which is perfectly set up for both Windows and Linux/BSD use with online help for setting up shell scripted utilities and version control systems. It runs Subversion servers and so can be used to host Subversion repositories.

Of course, you should do your own research and find your own solution.

Installing Subversion

Subversion needs to be installed and tested on each platform. It also uses the Secure Shell or ssh package, and the rsync package, so those need to be installed too.

Installing on Gnu/Linux

I use the Ubuntu distribution of Gnu/Linux. This uses the Aptitude package manager. Other distributions also use this package manager, in which case the instructions are the same. If your distribution uses a different package manager, then you will need to find instructions online for that package manager.

On Gnu/Linux, the ssh and rsync commands are usually built-in and can be used from a terminal. However, to be sure, type the following command at a terminal:

sudo apt-get install ssh rsync

Subversion is available as an aptitude package on Gnu/Linux, so simply install that:

sudo apt-get install subversion

Test the installation by typing:

svn --version

Installing on Windows

On Windows, the configuration is done from the MSYS shell. To install the ssh and rsync packages:

mingw-get install msys-openssh msys-rsync

Unfortunately, subversion is not available as a MinGW package, so needs to be installed the old fashioned way.

You need to download a Windows build of Subversion and then hand-install it into the MinGW installation.

Go to the Download directory of the “Subversion for Windows” project. Find the latest release and drill down to the latest Apache release and then download the plain Zip file with no suffix. For example, I downloaded: svn-win32-1.7.8-ap24.zip to get Subversion v1.7.8.

Unzip this file to a temporary location and then copy all the .exe and .dll files into the MinGW /local/bin folder, the Windows path of which is C:\msys\msys\1.0\local\bin if you followed the Windows installation instructions, C:\msys64\msys\1.0\local\bin if you followed the Windows 64-bit instructions.

Test the installation in the MSYS shell by typing:

svn --version

Installing on BSD

I’ve only tried PC-BSD – a distribution of FreeBSD, but I expect that all distributions of BSD will work in a similar way. It’s just a case of checking that all the packages required for version control are installed. Which they probably are!

I installed a meta-package called “Development-VCS” by using the Control Panel application called “System Manager” – see the tab called “System Packages”, look under “Development”.

To do this from the command-line, it is only necessary to ensure that Subversion is installed:

sudo pkg_add -r subversion

Configuring the Subversion Server

Once you have subscribed to the cloud storage server and got your login details, the first stage in setting up a subversion server is to configure it for password-free secure shell access. This is done using the ssh command and needs to be done on each platform and by each user.

This part of the tutorial is based on the online documentation provided by rsync.net.

Generate a Key

The first step in setting up the cloud service for password-free login is to generate an encryption key pair using the “ssh-keygen” command:

ssh-keygen -t rsa

Follow the instructions and it will generate a pair of key files in the directory ~/.ssh – id_rsa is the private key file and should be protected and never given away. The id_rsa.pub file however is the public key for export to any server to allow you to connect directly.

Note: if you get the error “Agent admitted failure to sign using the key” later in the process of using this new key, then this means your version of ssh requires an extra step to acknowledge the existence of a new key:

ssh-add

Upload a Single Key

If this is the first key to be exported, you can just copy the public key file to the server:

scp ~/.ssh/id_rsa.pub 123@abc.rsync.net:.ssh/authorized_keys

Where 123@abc should be replaced by your specific login details. Note the US spelling of authorized! I spent a long time not noticing that on one occasion. On this occasion, you will be asked for the password. However, if this succeeds, you will be able to access the server without a password. Test this:

ssh 123@abc.rsync.net ls -al

This runs the “ls -al” command on the remote server and should give a directory listing without having to type in a password.

Warning: this procedure for uploading the new key overwrites any previously-installed keys, so if you are setting up multiple connections, you need to append each key to the authorized_keys file instead.

Managing Multiple Keys

In practice, you will be accessing the subversion server from multiple platforms and possibly with multiple users. Each user/platform combination should have its own key. Keys are generated the same way, then all the keys need to be added to the server’s authorized_keys file. Or, to put it another way, each key should be appended, by the key owner, to the server’s authorized_keys file.

One way of appending a key is to create a local copy of the authorized_keys file, append your key to it, then upload the updated file:

scp 123@abc.rsync.net:.ssh/authorized_keys local_copy
cat ~/.ssh/id_rsa.pub >> local_copy
scp local_copy 123@abc.rsync.net:.ssh/authorized_keys

Note the >> append operator on the second line. You will need to type your password twice – once for the download and again for the upload. After that, you will be able to access the server without a password. Test this:

ssh 123@abc.rsync.net ls -al

Creating a Repository

Now that there is a password-free login route to the server over the secure ssh connection, it is possible to create a Subversion repository on that server. This is a one-off operation – once you have a repository you won’t need another one, the repository can be used to store many projects, although I tend to go against the convention and have a separate repository per project.

The way to create a repository depends on whether the server supports the “svnadmin” command and the way to find out is to try it.

This is the command
I use to create a repository called controls (for the controls example):

ssh 123@abc.rsync.net svnadmin create svn/controls

This runs the “svnadmin” command on the server over a secure connection, creating a repository called controls in the remote directory “~/svn/controls”. I prefer to keep all Subversion repositories in this “svn” directory.

If this fails it is because some servers are configured to allow svn, but disallow svnadmin. I’m not sure what the logic of this is, since svnadmin is required to create a repository. However, there is a workaround for this problem, which is to create the repository on your local machine and upload it:

svnadmin create controls
rsync -avz "controls/" "123@abc.rsync.net:svn/controls"

This only works if your local copy of Subversion creates a repository that is compatible with your server’s copy.

I also like to configure the repository with subdirectories called “trunk” which represents the latest master copy; “branches” to contain branches from the main trunk and “tags” to contain tagged copies – usually releases.

This is done with the Subversion mkdir command:

svn mkdir -m "Creating trunk" svn+ssh://123@abc.rsync.net/xyz/svn/controls/trunk
svn mkdir -m "Creating branches" svn+ssh://123@abc.rsync.net/xyz/svn/controls/branches
svn mkdir -m "Creating tags" svn+ssh://123@abc.rsync.net/xyz/svn/controls/tags

Note also the syntax of the repository URL used by Subversion once the repository has been created.

  • svn+ssh: – this is the subversion protocol via a secure shell
  • 123@abc.rsync.net – this is your login on the server
  • xyz – this is the full path to the home directory on the server
  • svn/controls – the repository location
  • trunk – the subdirectory within that repository

The full path to the home directory can be obtained using:

ssh 123@abc.rsync.net pwd

In fact I use a simple script to generate this path which I call rsync-net-svn-directory:

#!/bin/bash
echo "svn+ssh://${RSYNCNET:?Rsync account RSYNCNET has not been set}$(ssh ${RSYNCNET} pwd)/svn"

And in my ~/.profile I define the variable RSYNCNET:

export RSYNCNET="123@abc.rsync.net"

To get a working copy from the repository to start working on a project, checkout the trunk subdirectory of the repository:

svn checkout $(rsync-net-svn-directory)/controls/trunk

For details of how to use subversion now you have a working copy, see the online Subversion text book.

There are a number of Subversion clients around, and the best integrated GUI is probably TortoiseSVN, so I’d recommend that if you want a Windows GUI for version control. I prefer to use Subversion from within Emacs.

Subversion and Gnu Emacs

To use subversion from within Emacs, you need to install the “psvn” package. This is available from the author’s website.

The convention with Emacs is to store local additional packages in a sub-directory of the Emacs configuration directory. I use ~/.emacs.d/elisp as my extensions folder. Save the psvn.el file there.

Then, modify the initialisation file ~/.emacs.d/init.el as follows:

First add the local extensions directory to the load path:

(add-to-list 'load-path "~/.emacs.d/elisp")

Then, make the subversion package available:

(require 'psvn)

You will need to restart Emacs to apply these changes.

Then, to use subversion on a working copy, open that directory in Dired and then:

M-x svn-status

This will then list the current status of all the files in the project. There is an SVN menu with all the most useful commands.

Emacs Running svn status

Emacs Running svn status

Note that the file heapdebug.hpp has been Modified (M in the left-most column) relative to the master copy.

Leave a Reply