VersionVault Express relies on VersionVault Unified Change Management (UCM) as a set of processes for code development. In this article we’ll describe some of the concepts used in UCM and how to work as a team using VersionVault Express. In order to work with UCM in VersionVault Express the user must have the Developer role. For information on roles, refer to Roles in HCL VersionVault Express.
A few term definitions will be helpful in describing how VersionVault Express uses UCM.
The first term is baseline. A baseline specifies a version of each directory and file in a project and represents a snapshot of the project at any given time. Generally, a Builder is responsible for creating a baseline at times when the code base is known to be in a good state, such as after a successful build and test cycle.
The second term is activity. An activity identifies a set of directory and file versions created as part of a development task. An individual activity is usually created to work on a specific task.
The final UCM term of interest is stream. A stream starts from a defined baseline, and then can include activity changes as well. A stream is most analogous to a branch of the code base and resembles a workspace where developers can make code changes. The implementation of the workspace is through VersionVault views; views are handled in the background when using VersionVault Express however if you use the desktop client, VersionVault Explorer, for development activities the concept of the view is more explicit and documented further through that client.
UCM streams in VersionVault Express
VersionVault Express uses UCM streams as follows. VersionVault streams are organized into a tree structure where each single parent stream can have as many child streams as needed. In VersionVault Express each project contains an integration stream, which is the root of the tree. As individual developers join the project, VersionVault Express will create an initial individual development stream as a child of the root integration stream. The suggested approach is for the integration stream to contain code that is ready for use by other developers on the team while the individual development streams are where code is developed and tested. Once the code has been tested it can be placed into the integration stream in an operation described a little later.
While that’s the primary mode of operation for VersionVault Express, other cases are possible. A developer can create additional development streams under the integration stream to work on different tasks. A developer might want a “bug_71” stream to fix a bug as well as a “brand_new_feature” stream to implement, as the name suggests, a brand new feature. In this case the developer can switch between the streams seamlessly to work on whatever is the higher priority at the moment.
An additional use case is for larger features being worked on by multiple developers. Let’s say that a new feature requires effort from multiple developers prior to being placed into the integration stream. In this case it’s desirable to have a workspace where these multiple developers can share code prior to integration. Since streams are in a tree hierarchy, one could create what we term a feature stream, which is really a shared development stream. In this case we’d have the top level integration stream for the project, a feature stream as a child of the integration stream, and then individual developers would create development streams as children of the feature stream.
From VersionVault Explorer, the desktop client, you can see the stream hierarchy. In the below example, stream snaptweet.int is the integration stream with five child streams: bug_71 (a manually created development stream), snaptweet_new_feature (a feature stream), and three SnapTweet_tester* stream (the automatically created development streams). Feature stream snaptweet_new_feature has two child development streams: new_feature_db, and new_feature_ui. Refer to our blog about roles in HCL VersionVault Express to learn more.
Deliver and Rebase
VersionVault Express has two integration operations to merge code between streams. For VersionVault Express, code is merged between a parent stream and a child stream. This can be the integration stream and a development stream; it can also be between a feature stream and the integration stream. In the feature stream case it will also be between the development streams which are children of the feature stream and the feature stream.
The first operation is deliver. Deliver merges code from a child stream into the parent stream. The deliver operation is activity based – the user can specify which activities are to be delivered. Developers working on development streams would deliver bug fixes to the integration stream, for example. For the feature stream case, developers would deliver from development streams to the feature stream. Once code on the feature stream is ready for integration an additional deliver operation will merge the code to the integration stream.
The second operation is rebase. Rebase merges code from a parent stream into a child stream. If a developer has delivered code to the integration stream, a baseline would be created and recommended after that code has been built and tested, and then other developers will pick up the code by rebasing to that baseline.
In summary, the flow is:
- Developer develops a code change on a child stream
- Developer delivers the code to the parent stream
- Builder/developer creates a new baseline in the parent stream and recommends it (after testing)
- Developers rebase the child streams to the newly created baselines to see the code changes
Deliver and rebase operations involve two streams – the source stream and the target stream. For deliver the source stream is the child stream and the target stream is the parent. For rebase it’s inverted – the source stream is the parent stream and the target stream is the child.
Deliver and rebase are two step operations. When an operation is initiated the first step of the operation will checkout files as needed in the target stream and attempt merges, described below.
Merging is the act of resolving conflicts between the streams during the deliver and rebase operations. There are three scenarios one might encounter during merging.
The first, and easiest, scenario is when a file has been modified in one stream but not modified in the other stream. In this case, no merge is required, and no action is needed by the developer.
Next is a case where the file has been modified in both streams but in unrelated sections of the file. For example, developer A has modified one function, and developer B has modified a different function. In this case VersionVault considers this a conflict-free merge – the code, after the merge, will contain both changes without user intervention.
The final case is where conflicting changes have been made in a file. Both developer A and developer B have modified the same function and the code can’t automatically merge the two changes. This is a merge conflict.
Some screen shots from VersionVault Explorer will help make this clear. For any merge, three versions are involved – the base version, the source version, and the target version. In this example we’ll be doing a rebase of stream SnapTweet_tester2 from snaptweet.int ; first let’s take a look at the file in VersionVault Explorer.
In the above example, the base version is version 1 in the snaptweet.int stream. The source version is version 2 in the snaptweet.int stream (the source of the rebase will be MyBaseline2). The target version is version 1 in the SnapTweet_tester2 stream. The contents of the file are as follows in the three versions, from left to right as base, source, target.
In this case both source and target have made changes from the base – but the changes are distinct in the file. Let’s see what happens when we rebase. In VersionVault Express we initiate the rebase and indicate we’d like to merge from MyBaseline2 and then start the rebase operation.
After starting the rebase we see a few items of interest. First, the versions were successfully merged. This indicates there were no merge conflicts. Second, we now have the option to complete the rebase, leave it in the current state, or cancel the operation. For now, let’s opt to leave the rebase in the current state and look at the state of the code.
After selecting the leave option above, we go back to our code view and see that the file being merged is checked out, indicated by the blue triangle:
Let’s look at the contents of the file:
Note that both changes have been made automatically – the one from the baseline, and the one in our development stream. This is an automatically resolvable difference.
We can now complete the rebase and observe that the file is checked in:
Once again, from VersionVault Explorer we can see the rebase operation has completed and a merge arrow has been drawn indicating the merge is complete.
VersionVault Express will not complete a deliver or rebase operation in which merge conflicts are detected. If any file detects a merge conflict the following warning will appear and the operation will be automatically canceled; all files will be returned to their previous state.
In this case, due the complexity of the merge, VersionVault Explorer will be used to initiate and complete the operation. From within VersionVault Explorer, the deliver can be started:
And a merge window will start for each of the merge conflicts. While VersionVault Explorer has builtin compare and merge functionality, it is also possible to add support for a third party diff/merge tool if developers are already comfortable with alternate tools. Documentation on adding integrations can be found here. Below, the use of kdiff3 is shown to resolve the merge.
Once all merges have been resolved, the deliver operation can be completed.
Our final tree looks as below, indicating a rebase from the integration stream to the development stream, and a deliver from the development stream to the integration stream.
VersionVault Express versions
A major difference between VersionVault Express and other configuration management systems is that VersionVault Express will version both directories and files. Creating versions of files is common but creating versions of directories leads to potentially unexpected results. If a user creates a file for the first time in version 5 of a directory, but another user has selected version 4 of the directory then this second user will not see the file at all. During deliver and rebase operations directories are merged as well as files; if developer A added file1.java and developer B added file2.java to the same directory, but in different versions, then a merge of the directory would include both files in a new directory version.
VersionVault Express deliver and rebase operations are used to merge code between a hierarchy of streams and share code between developers. Deliver is used to merge code up from a child stream to a parent stream and rebase is used to merge code down from a parent stream to a child stream. For more information visit our blog site.