Monday, September 07, 2009

Branching and Merging using TFS

The concept of branching and merging is simple but the mechanics of using TFS for branching and merging need to be understood carefully because it is prone to errors when users misses a step. Quick advice, practice branching and merging a few times with test projects before using it on your real project.

This section will outline a step by step walkthrough of the Branch-Merge process using TFS. But before the walkthrough, please go through the pre-requisites here and be thoroughly familiar before moving on.

Pre-requisites:
1. Read the official documentataion (this is not enough, but still need to be familiar with) at:
MSDN Library - Development Tools and Languages - Visual Studio Team System - Team Foundation - Team Foundation Project Members -
Working with Team Foundation Source Control - Branching and Merging Team Foundation Source Control.

2. Be familiar with Solution Explorer in Visual Studio (VS) - if not shown then access from View menu. Understand that Solution Explorer shows the LOCAL version of your code.

3. Know how to check-out and check-in projects between Local workspace and TFS server. This is another big area which you need to fully understand.

4. Be familiar with Source Control Explorer. This is a client to view your files that are stored in the TFS server. This is a server view of files on the server - they are not your local files.

5. Change Source Control. This is a crucial tool to check that your projects are in sync between LOCAL versions and TFS server versions. Access this by highlighting a project in Solution Explorer, then go to File - Source Control - Change Source Control.
Note that if the project is not in source control, then the link above will be: File - Source Control - Workspaces.

6. There is an existing project (create one if needed) called Test_BranchMerge in a Solution of your choice. This Solution and its project should be in your local PC and in the TFS server and is properly checked-in and the source control path properly synchronized (can be checked using Change Source Control - see step 5 above). In this project, there should be at least one source file, eg Source1.f90. This example project is a Fortran project, but it should apply to other projects recognized by VS.


Walkthrough of Branching and Merging:
1. Go to Solution Explorer and click on the Test_BranchMerge project. Check the following: i) On the Pending Change column, there is nothing pending. ii) in the Latest column, everything is Yes. iii) In the Local Path above, the path is pointing to the correct local folder.

2. BRANCH - In the Solution Explorer, right click on Test_BranchMerge project; select Branch. In the Branch dialog:
i) in the Target field, you change the last part of the name, but do not alter the other parts of the path. Example:
Target: $/aaa/bbb/ccc/ddd/Test_BranchMerge-branch
this can be changed to
Target: $/aaa/bbb/ccc/ddd/Test_BranchMerge-06
but do not change the server structure $/aaa/bbb/ccc/ddd
ii) Branch from Version: select Latest Version.
iii) Check the box "Create local working copies for the new branch.
iv) Click OK.
This process will create a branch in the TFS server as well as a copy of the project in your local directory under the same solution as the original project source.

3. VERIFY -
i) In Windows File Explorer (not in VS), the folder Test_BranchMerge-06 exist on the same level as Test_BranchMerge. All contents between these two folders should be identical.
For Advanced Users: the project files *.cproj (for C#), *.vfproj (for Fortran) which identifies the projects to VS are identical between Test_BranchMerge-06 and Test_BranchMerge. This means all systems including VS (except for TFS) will REGARD these two projects as IDENTICAL. In VS, Test_BranchMerge-06 will be recognized as Test_BranchMerge. This is the correct feature and effect we need for branching. See step 4 in using this new branch to work with.
ii) In the VS - Source Control Explorer, Test_BranchMerge-06 is visible on the Directory Tree on the same level as Test_BranchMerge, with a branching symbol next to it. Click on Test_BranchMerge-06 on the left pane and on the right pane, all the contents Test_BranchMerge-06 are visible. All contents have the branching symbol next to it. In the Pending Change column, all contents have state - branch.
iii) In the Solution Explorer, check that the Test_BranchMerge project is still visible. Note that this shows the local Solution which is still linked to the local source of the original Test_BranchMerge project. This will be re-connected manually in step 4. Click to highlight Test_BranchMerge project in Solution Explorer, then go to File - Source Control - Change Source Control. View that the Test_BranchMerge project has Server Binding pointing to $/aaa/bbb/ccc/ddd/Test_BranchMerge. Do not change anything. Click OK.
iv) Again highlight Test_BranchMerge in Solution Explorer, then look at the Properties Window (if not show, go to View menu).
Verify that the project path is still pointing to Test_BranchMerge folder in your local PC.

4. INITIAL CHECK-IN
This step is necessary if we want to work on the changes in the branched code. At the end of Step 2, although the branched project and source has been created in TFS and the local PC, it HAS NOT BEEN REGISTERED UNDER TFS.
i)In the Source Control Explorer, in the left pane, right click on Test_BranchMerge-06 and select: Checkin Pending changes.
ii) Verify - Look in the right pane, under the Pending Changes column and check that all the files under Test_BranchMerge-06 has NO pending status at all; ie. the branching symbols and branch pending status are gone.
At this stage, the new branch for the project has been cloned.


5. RE-CONNECT VS Solution to point to the new Branch.
At this stage, VS Solution is still connected to Test_BranchMerge folder locally.
i) Go to Solution Explorer, right click on Test_BranchMerge and select Remove.
ii) In the Solution Explorer, right click on the Solution (at the top) and select Add - Existing Project.
iii) In the dialog box that appears, navigate to Test_BranchMerge-06 folder on your local PC and select Test_BranchMerge.vfproj or Test_BranchMerge.csproj, etc... and click Open. Note that the project file is STILL named Test_BranchMerge.xxxx, not Test_BranchMerge-06.xxxx.

6. VERIFY - that the new branch is connected.
i) From the Solution Explorer, highlight the project Test_BranchMerge. In the Properties Window, check that the Project Path is pointing to the local folder Test_BranchMerge-06.
ii) From the Solution Explorer, highlight the project Test_BranchMerge. Go to File - Source Control - Change Source Control. Looking at the project Test_BranchMerge - check that its Server Binding is set to $/aaa/bbb/ccc/ddd/Test_BranchMerge-06. Check that the Connected box is ticked and the Status is Valid.
This shows that for all intent and purposes, the branch is now recognized as the Test_BranchMerge project (not Test_BranchMerge-06). The paths to the server and local PC shows that the project is linked to the correct branch folder Test_BranchMerge-06.

7. WORK IN THE BRANCH
In the VS environment, modify the code, run the program, do whatever as normal. The Test_BranchMerge project should work as usual before branching. Even the Check-in proces to TFS should work as normal. As noted before, the source code is now connected to the branched version Test_BranchMerge-06, both locally and on TFS.
i). In the Solution Explorer, in the Test_BranchMerge project, open up the file Source1.f90. Edit this file, save it.
ii). Note the TFS locked symbol next to Source1.f90 changed to the red tick symbol indicating that the code is updated and different to the TFS version.
iii). If the red-tick edit symbol does not appear, then in Solution Explorer, click on Source1.f90, select Check-out for Edit. Then edit the code and save.
iv). Once all code changes are done, click on the Test_BranchMerge project in Solution Explorer and select Check In.

8. MERGE - like branching, merging must be done via Source Control Explorer. Branch - Merge are TFS operations, they are not VS operations.
i) From the Source Control Explorer, right click on the Test_BranchMerge-06 project, and select Merge.
ii) In the Merge dialog, choose the following:
Source Branch: $/aaa/bbb/ccc/ddd/Test_BranchMerge-06
Select: All changes up to a specific version
Target Branch: $/aaa/bbb/ccc/ddd/Test_BranchMerge
iii) Click Next, choose Latest Version as the Version Type, click Next, click Finish.
Note the merging occurs between code in TFS server, not your local version. Hence before merging, both old and new branch must be fully checked in. Also note merging occurs from Branched version as Source to Target original version.
iv) Verify - in the Source Control Explorer, click to highlight the original project Test_BranchMerge. Looking at the right pane under the Pending Change column, note that the files which has been changed will now have the "merge, edit" status.
v) Checkin - in the Source Control Explorer, right click Test_BranchMerge and select Checkin Pending Changes.
vi) Verify - if checkin is successful, then the files with "Merge, Edit" Pending Changes (step iv) above) will now have NO pending change status.

9. CONTINUING WORK
In VS, remember that the Test_BranchMerge project is still linked to the branched version Test_BranchMerge-06 code base. The user now has many options such as:
i) Continue working with the Test_BranchMerge-06 branch. The user can keep on editing code in VS under the Test_BranchMerge project, with no extra re-configuration.
ii) Revert back to work with original branch (which now has the merged changes). In the Solution Explorer, remove the Test_BranchMerge project (which is actually the Test_BranchMerge-06 branch). Then click on Solution in the Solution Explorer and Add Existing Project; select the xxxx.xxproj file from Test_BranchMerge folder.
iii) Work from a totally new branch, eg using a new branch Test_BranchMerge-07. To do this, repeat the whole process from Step 1.



There may be variations of how the branch-merge process can be done; the walk-through shown above is just one scenario that should just work without having to spend more time investigating an error prone process.

Thursday, September 03, 2009

NotesMSBuild

NotesMSBuild
=============

Contents
=========
Paths
MSBuild schema
MSBuild summary
MSBuild complete structure
Output Element
MSBuild tasks
MSBuild conditions
MSBuild reserved properties
MSBuild command line
MSBuild Well-known item metadata


Paths
======
When MSBUILD executes, the default root path of any relative path references made in the *.proj file, is the path where the *.proj file is executing from.
For example, if *.proj is in C:\test, then any relative path reference in the *.proj file starts from C:\test.


MSBuild schema
===============
The official schema or xsd for MSBuild can be found in:
Program Files\Microsoft Visual Studio 8\Xml\Schemas\1033\Microsoft.Build.xsd


MSBuild summary
================
Reference: In the MSDN, look for .Net Development - .Net Framework SDK - General Reference - MSBuild Reference.

MSBuild is a tool that lets developer perform various operations on a set of files given some specified conditions. To those who know the Makefile utility in Linux/Unix, MSBuild performs similar build tasks. From what I've read, MSBuild should be quite similar to NUnit and similar tools.

MSBuild is defined using XML file format, its structure is shown in the section "MSBuild complete structure" below.
Being XML based, it has the typical child elements and attributes structure that are in other XML formats.
The key items that drive MSBuild as I see it are the:
i) Targets - this allow the user to specify what to do
ii) Tasks - this allow the MSBuild designer to pre-specify the various tasks to be performed for each of the defined Targets.

The MSBuild design is typical saved as fileName.proj

To make use of the names defined in the MSBuild project file:
$()  Extracts the value of a property
@()  Extracts the value of an item as a list, that is, vector
%()  Extracts value of an item as a single string, that is, scalar


Example:

MSBuild complete structure
===========================
The complete MSBuild structure is shown in the tree / hierarchy below. The purpose of this diagram is to provide a quick illustration of the child elements and attribute relationships which is not easy to see from the official schema / xsd.

The top level element is the Project element.
: denotes attributes of the element
+ denotes child elements
Element names which begin with small letters, {item, itemMetaData, property, parameter} are actually
user defined names.



Project
    : DefaultTargets  eg DefaultTargets="tarA;TarB"
    : InitialTargets  eg InitialTargets="tarC;tarD"
    : xmlns           eg xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
    + Choose
        + Otherwise
            + Choose
            + ItemGroup
            + PropertyGroup
        + When
            : Condition,  eg Condition="'StringA'=='StringB'"
            + Choose
            + ItemGroup
            + PropertyGroup
    + Import
        : Condition
        : Project,  eg Project="ProjectPath"
    + ItemGroup
        : Condition
        + item
            : Condition
            : Exclude,  eg Exclude="MyFile.cs"
            : Include,  eg Include="*.cs"
            + itemMetaData
    + ProjectExtensions
    + PropertyGroup
        : Condition
        + property
            :Condition
    + Target
        : Condition
        : DependsOnTargets
        : Inputs
        : Name
        : Outputs
        + Error
            : Condition
            : Text
        + Message
            : Condition
            : Text
        + OnError
            : Condition
            : ExecuteTargets, eg ExecuteTargets="TargetName"
        + task
            : Condition
            : ContinueOnError   eg ContinueOnError="true/false"
            : parameter         eg par1="val1" par2="val2" par3="val3"
            + Output
                : Condition
                : ItemName      either ItemName or PropertyName is required
                : PropertyName
                : TaskParameter
        + Warning
            : Condition
            : Text
    + UsingTask
        : AssemblyFile
        : AssemblyName
        : Condition
        : TaskName














Output Element
==============
Output is an element not a task. The general structure for the Output Element is:

    [PropertyName="PropertyName" | ItemName="Item name"]
    Condition = "'String A' == 'String B'" />

Either the PropertyName or the ItemName attribute must be included with each Output element.
The value for the Output's TaskParameter must be the special name of the parameter of the task.
In the example below where Output is used with the Copy Task, the parameter "CopiedFiles" is a special name and is one of the defined parameters for COPY (see Copy task reference). The list of copied files is being held it the item called "SuccessfullyCopiedFiles". This list can be used by calling @(SuccessfullyCopiedFiles)



    
        SourceFiles="@(MySourceFiles)"
DestinationFiles="............"
        DestinationFolder="@(MyDestFolder)">
        
            TaskParameter="CopiedFiles"
            ItemName="SuccessfullyCopiedFiles"/>
    


MSBuild Tasks
==============
The following tasks list is taken from http://msdn.microsoft.com/en-us/library/7z253716(VS.80).aspx


AL (Assembly Linker) Task
Describes the AL task and its parameters.

AspNetCompiler Task
Wraps aspnet_compiler.exe, a utility to precompile ASP.NET applications.

AssignCulture Task
Assigns culture identifiers to items.

Copy Task
Describes the Copy task and its parameters.

CreateItem Task
Describes the CreateItem task and its parameters.

CreateProperty Task
Describes the CreateProperty task and its parameters.

Csc Task
Describes the Csc task and its parameters.

Delete Task
Describes the Delete task and its parameters.

Exec Task
Describes the Exec task and its parameters.

FindUnderPath Task
Determines which items in the specified item collection exist in the specified folder and all of its subfolders.

GenerateApplicationManifest Task
Describes the GenerateApplicationManifest task and its parameters.

GenerateBootstrapper Task
Provides an automated way to detect, download, and install an application and its prerequisites.

GenerateDeploymentManifest Task
Describes the GenerateDeployManifest task and its parameters.

GenerateResource Task
Converts .txt and .resx files to common language runtime binary .resources files.

GetAssemblyIdentity Task
Retrieves the assembly identities from the specified files and outputs the identity information.

GetFrameworkPath Task
Retrieves the path to the .NET Framework assemblies.

GetFrameworkSdkPath Task
Retrieves the path to the .NET Framework SDK.

LC Task
Describes the LC task and its parameters.

MakeDir Task
Describes the MakeDir task and its parameters.

MSBuild Task
Describes the MSBuild task and its parameters.

ReadLinesFromFile Task
Reads a list of items from a text file.

RegisterAssembly Task
Describes the RegisterAssembly task and its parameters.

RemoveDir Task
Describes the RemoveDir task and its parameters.

ResGen Task
Describes the ResGen task and its parameters.

ResolveAssemblyReference Task
Describes the ResolveAssemblyReference task and its parameters.

ResolveComReference Task
Describes the ResolveCOMReference task and its parameters.

ResolveKeySource Task
Determines the strong name key source

ResolveNativeReference Task
Resolves native references.

SGen Task
Creates an XML serialization assembly for types in the specified assembly.

SignFile Task
Signs the specified file using the specified certificate.

Touch Task
Describes the Touch task and its parameters.

UnregisterAssembly Task
Describes the UnregisterAssembly task and its parameters.

Vbc Task
Describes the Vbc task and its parameters.

VCBuild Task
Describes the VCBuild task and its parameters.

WriteLinesToFile Task
Writes the specified items to the specified text file.


MSBuild conditions
===================
'A'=='B'      true if A equals B
'A'!='B'      not true if A equals B
<, >, <=, >=    Compares numerical values. Note: need to use < for < and > for >
Exists('sss')   Eg. Condition="!Exists('$(buildir)')"
!             negation
And           and operator
Or            or operator
()            for grouping of expressions



MSBuild reserved properties
============================
Reference: http://msdn.microsoft.com/en-us/library/ms164309(VS.80).aspx

MSBuildProjectDirectory
 The absolute path of the directory where the project file is located, for example, C:\MyCompany\MyProduct.

MSBuildProjectFile
 The complete file name of the project file, including the file name extension, for example, MyApp.proj.

MSBuildProjectExtension
 The file name extension of the project file, including the period, for example, .proj.

MSBuildProjectFullPath
 The absolute path and complete file name of the project file, for example, C:\MyCompany\MyProduct\MyApp.proj.

MSBuildProjectName
 The file name of the project file without the file name extension, for example, MyApp.

MSBuildBinPath
 The absolute path of the directory where the MSBuild binaries that are currently being used are located, for example, C:\Windows\Microsoft.Net\Framework\v2.0. This property is useful if you need to refer to files in the MSBuild directory.

MSBuildProjectDefaultTargets
 The complete list of targets specified in the DefaultTargets attribute of the Project element. For example, the following Project element would have an MSBuildDefaultTargets property value of A;B;C.


MSBuildExtensionsPath
 The MSBuild folder under the Program Files directory. This location is a useful place to put custom target files. For example, your targets files could be installed at \Program Files\MSBuild\MyFiles\Northwind.targets and then imported in project files with the following XML.



MSBuild command line
=====================

For more information on how to use command line, type:
MSBuild.exe /help

Example on a typical usage:
MSBuild.exe /nologo /targets:targetName /property:name=val /verbosity:quiet|minimal|normal|detailed|diagnostic projectFile.proj


MSBuild Well-known item metadata
=================================
Every item has a set of default metadata specified during their creation. The list given below is taken from:
http://msdn.microsoft.com/en-us/library/ms164313(VS.80).aspx


%(FullPath)
 Contains the full path of the item. For example: C:\MyProject\Source\Program.cs

%(RootDir)
 Contains the root directory of the item. For example: C:\

%(Filename)
 Contains the file name of the item, without the extension. For example: Program

%(Extension)
 Contains the file name extension of the item. For example: .cs

%(RelativeDir)
 Contains the directory path relative to the current working directory. For example: Source\

%(Directory)
 Contains the directory of the item, without the root directory. For example: MyProject\Source\

%(RecursiveDir)
 If the Include attribute contains the wildcard **, this metadata specifies the directory that replaced the wildcard to find the item. This example has no RecursiveDir metadata, but if the the following example was used to include this item, the item would contain a RecursiveDir value of MyProject\Source\.




%(Identity)
 The item specified in the Include attribute.. For example: Source\Program.cs

%(ModifiedTime)
 Contains the timestamp from the last time the item was modified. For example: 2004-07-01 00:21:31.5073316

%(CreatedTime)
 Contains the timestamp from when the item was created. For example: 2004-06-25 09:26:45.8237425

%(AccessedTime)
 Contains the timestamp from the last time the time was accessed. 2004-08-14 16:52:36.3168743