Automation for the people: Parallel development for mere mortals

Branching, tagging, and merging in Subversion

 

It seems that most software development teams fall into two camps when it comes to source-code branching: They don't branch at all, or there's such a proliferation of branches (or worse, repositories) that developers are unsure where to check in changes — or find merging changes so painful that they riskily put it off until immediately before a software release.

Terminology

The trunk (sometimes referred to as the head ) is used for mainline development. A branch is a copy of a code line used for making changes that are different from the mainline development. A tag (sometimes referred to as a label ) is a time-stamped copy of a codeline that identifies it so you can get back to it later in the development cycle.

In a perfect world, we would always work on the trunk. This would limit the complexity of merging changes between two or more codelines. However, in the real world of software development, you might be developing for a future release and at some point need to make an emergency patch to a version that's already in use. You need access to a copy of the source code for that released version — without disrupting the new code that's under development.

But when teams try to use separate codelines, problems can occur. Some may choose not to create branches, which leads to delayed releases and developer bottlenecks. Other times, developers merge less frequently, leading to merge conflicts, bottlenecks, and delayed releases. A proliferation of branches can make it difficult to navigate the project repository, causing developers to make inadvertent changes to the wrong code.

When a team develops in parallel, it's important to merge code back to the mainline (trunk) as often as feasible. If it's not possible to commit the merged code back to the trunk frequently, test runs can determine if any merge conflicts will occur so that merges are less painful when they are committed. In order to develop in parallel effectively, you can use tags and branches in Subversion (SVN), an open source and freely available source-code management system. By tagging, your team can get back safely to a previous version of the source code.

I'll demonstrate how to develop in parallel in SVN by covering:

  • How to create an SVN release tag from the trunk
  • Creating an SVN branch based on a release tag
  • Techniques to merge changes back to the mainline (trunk)
  • How to run Continuous Integration (CI) against a branch that is under development and regularly test the merge against the trunk
  • Demonstrations of applying changes from branch back to the trunk
  • Examples of tagging source code for a branch

About this series

As developers, we work to automate processes for users; yet, many of us overlook opportunities to automate our own development processes. To that end, Automation for the people is a series of articles dedicated to exploring the practical uses of automating software development processes and teaching you when and how to apply automation successfully.

Figure 1 shows a rudimentary workflow of several concurrent codelines:


Figure 1. Developing in parallel
A typical development timeline for parallel development

In Figure 1, the active development occurs between versions 1.0.0 and 1.1.0 off the SVN trunk. One set of developers can work on the version 1.0.1 branch while others develop off the mainline.

Many strategies and techniques are available when multiple developers work on different codelines. In this article, I demonstrate a common approach that I've used on projects using SVN.

Configuring Subversion for parallel development

Installing and configuring an SVN server is beyond this article's scope. Assuming that you have access to a functioning SVN server, you're ready to run through these steps:

  1. Download the SVN client software to your workstation.
  2. Create standard local directories in private workspace.
  3. Add directories to the SVN repository.
  4. Commit directories to the SVN repository.

Download SVN client software for your operating system from the Tigris.org Web site (see Resources ) and install it on your workstation. Be sure that the SVN executable is in your workstation's system path. Perform an SVN checkout of the repository using svn co URL .

Next, create three local directories:

  • branches: Used to maintain software outside mainline development.
  • tags: Used when you release software to identify a changeset for later use.
  • trunk: Used for mainline development.

Listing 1 shows how to create these directories from the command line on Windows®, Macintosh, and *nix-based systems:


Listing 1. Creating local directories to prepare to add to Subversion

$ mkdir branches
$ mkdir tags
$ mkdir trunk

 

Now that the directories have been created in the operating system, you can add and commit them to SVN using the SVN add and commit commands. From the directory where I created the directories in Listing 1, I type the commands shown in Listing 2 (replacing the user credentials, as appropriate):


Listing 2. Adding and committing local directories to remote SVN repository

$ svn add *.*
$ svn commit -m "Setting up standard SVN branches, tags and trunk directories" /
--username tjefferson --password Mont!cello

 

After I perform the actions in Listings 1 and 2, my SVN repository looks something like Figure 2:


Figure 2. Standard SVN directories created in repository
Standard SVN directories created in repository

With my basic SVN repository setup in place, I'm ready to create a release tag.


Creating a release tag based on trunk

The purpose of a tag is to uniquely identify a copy of a codeline at a particular point in time so that you can get back to this version later. Figure 3 shows a tag named brewery-1.0.0 that is created for the 1.0.0 release. (A tag can be created at any point in time, but tags are most often created when software is released.)


Figure 3. Create a unique tag for the SVN trunk
A release tag based on the trunk

Assuming the trunk contains source code of released software, the first task is to create an SVN tag based on the trunk. Listing 3 is an example of how to create this release tag:


Listing 3. Creating a release tag based on trunk

<path id="svn.classpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar" />
</fileset>
</path>
<taskdef name="svn" classpathref="svn.classpath"
classname="org.tigris.subversion.svnant.SvnTask"/>

<target name="create-tag-from-trunk">
<svn username="jhancock" password="S!gnhere">
<copy srcUrl="https://brewery-ci.googlecode.com/svn/trunk"
destUrl="https://brewery-ci.googlecode.com/svn/tags/brewery-1.0.0"
message="Tag created by jhancock on ${TODAY}" />
</svn>
</target>

 

Securely failing

When first running an SVN server that uses Hypertext Transfer Protocol over Secure Socket Layer (HTTPS), you must accept the security certificate. If you're connecting to a secure SVN server like this for the first time from your Ant script, it will fail without much diagnostic information. So, you must run your first SVN command from the command line to connect to this server. You can subsequently run any SVN Ant script from your workstation to connect to this server.

Listing 3 uses the SVN Ant task provided by the Subclipse open source project (to download, see Resources ). The JARs provided with the SVN Ant task — svnant.jar, svnClientAdapter.jar, and svnjavahl.jar — must be included in your classpath when you run the Ant script. The first part of Listing 3 defines the classpath. The second defines the SVN Ant task using taskdef . Finally, I perform an SVN copy from the trunk to the tags directory, providing a unique name for this release: brewery-1.0.0 .

After you run the script in Listing 3 to create a new tag, your SVN repository should look similar to Figure 4. Under the root level of the repository is the tags directory (created in Listing 2 ). Under it is the new tag (directory) created in Listing 3: brewery-1.0.0. It contains a copy of the trunk.


Figure 4. Create tag based on trunk
Create tag based on trunk

Although it is possible to modify tag contents in Subversion, you should never do so.


Create a branch based on release tag

Creating a branch based on a release tag is similar, in technique, to creating a tag based on the trunk. Each involves the use of SVN's copy command. You always want to create a branch based on a tag because the tag is a copy of the code when it was released — rather than the code currently under development, which may have been modified. Figure 5 illustrates creating a 1.0.1 branch based on the 1.0.0 release tag:

Version naming

Coming up with a version-naming scheme is something people tend to trivialize, but it can be more than annoying when a slightly different version-naming pattern is used from one version to the next or between different projects. Many versioning patterns are possible. Choose one that is simple but will be flexible in dealing with future releases. A simple pattern I use is major-version.minor-version.patch. Version 1.1.2 is an example version number based on this naming pattern. Some teams choose to append a build number to the version as well.


Figure 5. Creating branch 1.0.1 based on 1.0.0 release tag
Creating branch 1.0.1 based on 1.0.0 release tag

Listing 4 calls the SVN copy command via the SVN Ant task to copy all files from the brewery-1.0.0 tag to the branches location:


Listing 4. Ant script to create branch from release tag

<target name="create-branch-from-tag">
<svn username="sadams" password="b0stonM@ss">
<copy srcUrl="https://brewery-ci.googlecode.com/svn/tags/brewery-1.0.0"
destUrl="https://brewery-ci.googlecode.com/svn/branches/brewery-1.0.1"
message="Branch created by sadams on ${TODAY}" />
</svn>
</target>

 

After you run the script in Listing 4, the SVN repository should look something like Figure 6:


Figure 6. Creating branch from release tag
Creating branch from release tag

Remembering the trunk

Some teams take branch development to the extreme by beginning all development on a branch. Remember that it is less complex and more manageable to develop exclusively off the trunk. The reason for branching is to be able to support separate development efforts in parallel. Try not to misuse it by creating a branch for everything you do.

By remembering always to use tags when creating branches and using the SVN Ant task, you can provide a repeatable process that gives you an easy way to maintain, and get back to previous versions of, your source code.

Run CI against branch

The process of CI is typically run against the repository's mainline: the trunk. This can be extended to branches as well, with the intent of integrating changes among developers working on the branch and checking the merge with the mainline.

Figure 7 shows the SVN location. From this Hudson configuration page, you can also define the Ant target to call.


Figure 7. Hudson CI server building branches and testing merges against the trunk
Hudson CI server building branches and testing merges against the trunk

Running a CI server such as Hudson to test merges can give you an early warning system that alerts you to potential merge conflicts that could occur later on in the development cycle.


Merge changes from branch back to the trunk

One of the primary reasons to create a branch is to prevent disruption to mainline development. However, once you've completed work on the branch, the changes should be merged back to the trunk. Figure 8 illustrates a merge from version 1.0.1 back to mainline, which is developing version 1.1.0 of the software:


Figure 8. SVN timeline
Merging changes from branch back to the trunk

In Listing 5, I use the merge command from Subversion. I type svn merge followed by the URL to merge to, then the URL to merge from, followed by the local directory location:


Listing 5. Using SVN's merge command to merge branch development back to the trunk

$ svn merge https://brewery-ci.googlecode.com/svn/trunk /
https://brewery-ci.googlecode.com/svn/branches/brewery-1.0.1 /
/dev/brewery --username pduvall --password password!

 

The SVN Ant task does not provide a merge command, so the merge command needs to be run from the command line. Or you can run it using Ant's exec task.

The results of running the command in Listing 5 are similar to those shown in Figure 9:


Figure 9. Results of merging branch back to the trunk
Results of merging branch back to the trunk

If the merge is successful, you need to commit the change in Subversion, as shown in Listing 6. From the command line, type svn commit along with the message description and the SVN URL for the trunk:


Listing 6. Committing merged changes to the trunk

<target name="commit-branch-to-trunk">
<svn username="gwbush" password="IL0veTHEG00g!e">
<commit dir="${basedir}"
message="Committing changes from brewery-1.0.1">
</commit>
</svn>
</target>

 

Merge changes from the branch back to the trunk as often as possible to prevent difficult merges and so that the different codelines don't grow apart over time.


Create a tag based on branch

To prepare a release based on a particular branch, I create an SVN tag. This follows a similar approach to some of the previous listings. Figure 10 shows the creation of a tag called brewery-1.0.1 based on the brewery-1.0.1 branch:


Figure 10. Creating a tag based on a branch
Creating a tag based on a branch

When development is finished on a particular branch, it needs to be tagged in Subversion. Listing 7 shows an example of creating this tag based on the branch:


Listing 7. Creating an SVN tag based on a branch

<svn username="jbartlett" password="newHampsh!re">
<copy srcUrl="https://brewery-ci.googlecode.com/svn/branches/brewery-1.0.1"
destUrl="https://brewery-ci.googlecode.com/svn/tags/brewery-1.0.1"
message="Branch created by jbartlett on ${TODAY}" />
</svn>

 

By creating a tag based on a particular branch, you can get back to this version later in the development cycle.


Right on track with parallel development

Developing in parallel isn't brain surgery, but it can be monumentally difficult to manage without planning and continually improving based on project needs. If you remember one thing, remember that all roads should lead back to the mainline — eventually. Look at branches as a temporary home for source code that could interrupt mainline development. The last point to consider is to test the merge early and often. There are probably version-control systems that support parallel development better than Subversion, but in my experience the policies that teams adhere to when developing are much more important than how a tool technically solves the problem.

 

Resources

Learn

Get products and technologies

  • Subversion : Download Subversion to manage source code versions.
  • Ant : Download Ant and start building software in a predictable and repeatable manner.
  • SVN Ant task : Download an Ant task for operating Subversion to provide a repeatable process for managing source changes.
  • Hudson : Download the Hudson Continuous Integration Server to begin running builds with every change to Subversion (or other SCM server).

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值