TFS Integration Tools – I only migrated VC … can I migrate WIT afterwards and maintain relationships?


The scenario starts with a team project, for example TP-A1, on a TFS Server, which has version control (VC), work item tracking (WIT) data and links between the two. A decision is then made to migrate only the VC data from TFS Server A to TFS Server B, using the TFS Integration Tools (Platform), performing ad-hoc update migrations from Server A to Server B.


Adam C. then queries “Is there anyway going forward for us to migrate WIs to the same team project where we previously migrated source and keep the relationships between WIs, change sets and source? ”.

In essence we would like to continue running the ad-hoc update migrations from Server A to Server B, but migrate VC, WIT and their links going forward as shown below.


Bill E. replies “A session group consists of multiple sessions.  When VC and WIT sessions are run in the same session group they share access to conversion history that lets linking resolve references on the target system.  We do not have a feature in place that lets a user start a separate session group and tell the tool that it intentionally wants this conversion history context to be available within a separate session group.  Generally that means that the user needs to plan ahead if they want to preserve links between WIs and VC content and run them in the same session group.”

The following journal documents a test to validate a possible work around, which involves XML editing (yuck) and is not a recommended scenario. Instead plan ahead and decide if VC, WIT and links should be preserved, migrating/synchronizing all the relevant data from the start.

Setting up a VM with a test environment

  • I used the Visual Studio Virtual Machine (VM) Factory to create a Rangers base image, running a single server TFS_ATDT and Visual Studio Ultimate environment.
  • I copied the TFS Integration Tools (Platform) HOL package and configured the environment running the HOLSetup and the SetupAdmin scripts as per readme files. This created us the following test team project with VC and WIT data, but no links as yet.
  • We are making a few assumptions, namely that (1) the simple HOL data is sufficient and that (2) the Standalone Server simulates two separate TFS Servers A and B.

Doing a simple VC Migration

  • Using the TFS Integration Admin shell and the default VersionControl template delivered with the product, we create a VC-only migration session group as shown:
  • We perform a migration, which moves the VC data from team project TP-A to team project TP-B. We have to resolve three VC conflicts, which involve a confusing dialog … see Where does one start? … part 3 (dust has settled …. did it work?) for more information.
  • We then resolve the WI:1 bug in TP-A, check-in the code changes, linking to the relevant WIT bug.
  • This creates the following environment, which is the starting point on Server A as defined by the scenario above.
  • We run another update migration using the same session and are left with the environment as documented at the start of the scenario, with migrated VC data, but no WIT or VC-WIT relationships in the team project on Server B.
  • Validation steps:
    • Review source code in TP-A … code fix is included.
    • Review work items in TP-A … bug 1 is resolved and there is a relationship between the WI #1 and the VC Changeset #43.
    • Review source code in TP-B … code fix is included.
    • Review work items in TP-B … as expected we have no work items.

Up to this point we merely created the scenario environment. Now let us do some work-around magic Smile

Doing a simple WIT Migration afterwards and maintaining relationships between VC and WIT

So, how can we get the WIT data included in the upgrade migration session we created for VC and also maintain the link relationships?

  • Using the TFS Integration Admin shell and the default WorkItemTracking template delivered with the product, we create a WIT-only migration session group as shown:
    DO NOT RUN THIS SESSION! For safety I actually never saved my session to the database, which kept the Start button disabled.
  • (1) Select the CML tab, (2) make a copy of the configuration XML from the WIT-only migration session group once you are happy with the configuration. I (3) copied mine into XML and made a safety save to c:\temp … just in case.
  • Re-open existing VC-only session group, edit current, switch to XML and carefully merge content into Providers, MigrationSources and Sessions. Save changes to database and note that we now have a WIT and a VC session in the same group. The former is “Not yet migrated”.
  • Here is a complete copy of the configuration XML:
       1: <?xml version="1.0" encoding="utf-16"?>
       2: <Configuration xmlns:xsi="" xmlns:xsd="" UniqueId="d9365cfc-b6d5-4457-bd33-f36afd1e9c0e" FriendlyName="TFS to TFS Version Control">
       3:   <Providers>
       4:     <Provider ReferenceName="febc091f-82a2-449e-aed8-133e5896c47a" FriendlyName="TFS 2010 Migration VC Provider" />
       5:     <Provider ReferenceName="04201d39-6e47-416f-98b2-07f0013f8455" FriendlyName="TFS 2010 Migration WIT Provider" />
       6:   </Providers>
       7:   <Addins />
       8:   <SessionGroup CreationTime="2011-07-07T16:33:36.582817Z" FriendlyName="TFS to TFS Version Control" SessionGroupGUID="7234b941-6f42-40b9-9b4b-0da3e7a60c55" Creator="TFS2010R32W\Administrator" SyncIntervalInSeconds="0" SyncDurationInMinutes="0">
       9:     <MigrationSources>
      10:       <MigrationSource InternalUniqueId="b12ac3f2-8613-4902-8098-660e0160106f" FriendlyName="localhost (VC)" ServerIdentifier="c392ced0-360b-41a3-b656-46fc50c8cb67" ServerUrl="http://localhost:8080/tfs/defaultcollection" SourceIdentifier="TP-A" ProviderReferenceName="febc091f-82a2-449e-aed8-133e5896c47a">
      11:         <Settings>
      12:           <Addins />
      13:           <UserIdentityLookup />
      14:           <DefaultUserIdProperty UserIdPropertyName="DisplayName" />
      15:         </Settings>
      16:         <CustomSettings />
      17:         <StoredCredential />
      18:       </MigrationSource>
      19:       <MigrationSource InternalUniqueId="bd19be62-ecbb-43c6-84eb-3e813e1a5a06" FriendlyName="localhost (VC)" ServerIdentifier="c392ced0-360b-41a3-b656-46fc50c8cb67" ServerUrl="http://localhost:8080/tfs/defaultcollection" SourceIdentifier="TP-B" ProviderReferenceName="febc091f-82a2-449e-aed8-133e5896c47a">
      20:         <Settings>
      21:           <Addins />
      22:           <UserIdentityLookup />
      23:           <DefaultUserIdProperty UserIdPropertyName="DisplayName" />
      24:         </Settings>
      25:         <CustomSettings />
      26:         <StoredCredential />
      27:       </MigrationSource>
      28:       <MigrationSource InternalUniqueId="e86ecc76-f1dd-4502-a141-8ef2e4dc9614" FriendlyName="localhost (WIT)" ServerIdentifier="c392ced0-360b-41a3-b656-46fc50c8cb67" ServerUrl="http://localhost:8080/tfs/defaultcollection" SourceIdentifier="TP-A" ProviderReferenceName="04201d39-6e47-416f-98b2-07f0013f8455" EndpointSystemName="TFS">
      29:         <Settings>
      30:           <Addins />
      31:           <UserIdentityLookup />
      32:           <DefaultUserIdProperty UserIdPropertyName="DisplayName" />
      33:         </Settings>
      34:         <CustomSettings />
      35:         <StoredCredential />
      36:       </MigrationSource>
      37:       <MigrationSource InternalUniqueId="261aa0a7-34aa-4673-a84d-ebc34866e547" FriendlyName="localhost (WIT)" ServerIdentifier="c392ced0-360b-41a3-b656-46fc50c8cb67" ServerUrl="http://localhost:8080/tfs/defaultcollection" SourceIdentifier="TP-B" ProviderReferenceName="04201d39-6e47-416f-98b2-07f0013f8455" EndpointSystemName="TFS">
      38:         <Settings>
      39:           <Addins />
      40:           <UserIdentityLookup />
      41:           <DefaultUserIdProperty UserIdPropertyName="DisplayName" />
      42:         </Settings>
      43:         <CustomSettings />
      44:         <StoredCredential />
      45:       </MigrationSource>
      46:     </MigrationSources>
      47:     <Sessions>
      48:       <Session CreationTime="2011-07-07T16:33:36.503599Z" SessionUniqueId="56593ca5-25ce-4a1f-9060-e8374a68cc09" FriendlyName="Version Control Session" LeftMigrationSourceUniqueId="b12ac3f2-8613-4902-8098-660e0160106f" RightMigrationSourceUniqueId="bd19be62-ecbb-43c6-84eb-3e813e1a5a06" SessionType="VersionControl">
      49:         <EventSinks />
      50:         <CustomSettings>
      51:           <SettingXml />
      52:           <SettingXmlSchema />
      53:         </CustomSettings>
      54:         <Filters>
      55:           <FilterPair Neglect="false">
      56:             <FilterItem MigrationSourceUniqueId="b12ac3f2-8613-4902-8098-660e0160106f" FilterString="$/TP-A" />
      57:             <FilterItem MigrationSourceUniqueId="bd19be62-ecbb-43c6-84eb-3e813e1a5a06" FilterString="$/TP-B" />
      58:           </FilterPair>
      59:         </Filters>
      60:       </Session>
      61:       <Session CreationTime="2011-07-07T16:33:36.576949Z" SessionUniqueId="5cb58782-ce7a-4d86-b4df-3f6ae937d50e" FriendlyName="Work Item Tracking Session" LeftMigrationSourceUniqueId="e86ecc76-f1dd-4502-a141-8ef2e4dc9614" RightMigrationSourceUniqueId="261aa0a7-34aa-4673-a84d-ebc34866e547" SessionType="WorkItemTracking">
      62:         <EventSinks />
      63:         <CustomSettings>
      64:           <SettingXml>
      65:             <WITSessionCustomSetting>
      66:               <Settings />
      67:               <WorkItemTypes>
      68:                 <!-- Map only Bug to Bug 
      69:                 <WorkItemType LeftWorkItemTypeName="Bug" RightWorkItemTypeName="Bug" fieldMap="@@ALL@@" />
      70:                 -->
      71:               </WorkItemTypes>
      72:               <FieldMaps>
      73:               </FieldMaps>
      74:               <ValueMaps />
      75:             </WITSessionCustomSetting>
      76:           </SettingXml>
      77:           <SettingXmlSchema />
      78:         </CustomSettings>
      79:         <Filters>
      80:           <FilterPair Neglect="false">
      81:             <FilterItem MigrationSourceUniqueId="e86ecc76-f1dd-4502-a141-8ef2e4dc9614" FilterString="[System.AreaPath] UNDER 'TP-A'" />
      82:             <FilterItem MigrationSourceUniqueId="261aa0a7-34aa-4673-a84d-ebc34866e547" FilterString="[System.Id] = 0" />
      83:           </FilterPair>
      84:         </Filters>
      85:       </Session>
      86:     </Sessions>
      87:     <Linking>
      88:       <CustomSettings />
      89:       <LinkTypeMappings />
      90:     </Linking>
      91:     <WorkFlowType Frequency="ContinuousManual" DirectionOfFlow="Unidirectional" SyncContext="Disabled" />
      92:     <CustomSettings />
      93:     <UserIdentityMappings EnableValidation="false">
      94:       <UserIdentityLookupAddins />
      95:     </UserIdentityMappings>
      96:     <ErrorManagement>
      97:       <ErrorRouters />
      98:       <ReportingSettings />
      99:     </ErrorManagement>
     100:   </SessionGroup>
     101: </Configuration>

  • Run the session group again.
  • We notice that we now have VC and WIT migrated data.

  • Validation steps:
    • Review source code in TP-B … code fix is included. Unchanged.
    • Review work items in TP-B … “Cowabunga” we now have (1) a resolved bug 2 is resolved and there is (2) a relationship between the WI #2 and the VC Changeset #44 on TP-B. Peeking (3) into the changeset, we even notice the origin of the changeset, namely #43 from TP-A, tied to TP-A Bug WI#1.


Migrating VC/WIT changes thereafter

  • Just for good measure we make another change in TP-A by adding another bug, making another code change and tying up the new changeset and the resolved bug.

  • Re-run the session group.

  • We can now validate and verify that on-going changes in TP-A VC and WIT data, as well as link relationships between VC and WIT will move from TP-A to TP-B as the migration session group is run periodically.

This post documents a “possible workaround” for this scenario. It is not available or supported out-of-the-box and it is important that you validate this workaround in your test environment before trying it on your production data.


Skip to main content