Using Mercurial as a local repository for Team Foundation Server / Start Front’N

This post covers how to setup mercurial(HG) as are local source control repository to sit in front of a Team Foundation Server . I am not going to go into the details of why you would want to run this way in this post. You can look at the StackOverflow question that may give you more insight. For those of you who want to use mercurial for your day to day source control but have to synchronize your source code into a TFS server, this will allow you to do this.

The tools used for this process were lifted from blog posts all over the web.


The Tools.

  1. TFS 2010  Powertools
  2. Tortoise HG
  3. MakeWritable Mercurial Extension
  4. Rebase Mercurial Extension
  5. Two Powershell scripts to push and pull files to the TFS server (listed below)


Setting up the environment

  1. Download and install, TFS 2010 Powertools, Tortoise HG, and the MakeWritable Mercurial extension
  2. Enable the MakeWritable and Rebase extensions in mercurial.
    1. Edit your profiles Mercurial.ini file.  Add the following section to the file.

      makewritable = c:program files (x86)

  3. Configure the TFS and HG repositories on your local file system.
    1. Setup your project repository from tfs in a folder. C:codeProject-from-TFS . This is the gold repository that is only used for merging changes to and from the TFS repository. You will never make changes to code in this repository.
    2. Make that folder a Mercurial Repository and add all the files from TFS into the mercurial repository and commit them to Mercurial.
    3. Make a second folder. This is your working folder.  In this folder using mercurial clone from the gold repository.
    4. Place the push.ps1 and pull.ps1 files into the working folder and commit them to the local repository.

The Workflow

  1. Start developing your work.. If you want commit to branches and merge to the main when you want to push something to TFS.
  2. Commit your local work.
  3. Run the pull.ps1 command to pull down changes from tfs and merge them.
  4. Keep working and committing to mercurial
  5. When your ready to send your change to the TFS server commit your changes to mercurial and then run the push.ps1 command.
    1. The push.ps1 command will pop up one window for adding new files to TFS (if you have created new files as part of your dev work)
    2. The push.ps1 will pop up a commit dialog for TFS so that you can verifiy all the files going to TFS and enter a commit message.

Rinse and Repeat.


Show sample of pull.ps1


Show sample of push.ps1


This shows the results of running a pull command.  By using the Rebase command needless merge commits just go away. You see the +1 heads text below, that suggests a merge is needed, and it normally is.  By scripting the rebase command I essentially eliminate the need for the merge, except for when a true merge conflict exists.



Is this useful?  Is there a better way to do this?  Please let me know.

About Eric Hexter

I am the CTO for QuarterSpot. I (co)Founded MvcContrib, Should, Solution Factory, and Pstrami open source projects. I have co-authored MVC 2 in Action, MVC3 in Action, and MVC 4 in Action. I co-founded online events like mvcConf, aspConf, and Community for MVC. I am also a Microsoft MVP in ASP.Net.
This entry was posted in mercurial, source control, TFS. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • This is great. By providing the scripts, you have made the solution much simpler to implement.

  • Jon Newbill

    This was most useful.  I found with VS2010 I had to add options /diff and /deletes to the tftp online command in the push script to get changed and deleted files to be checked in to TFS.  Even with this script I’m getting an error from push when a file has been deleted that hg update is
    “unable to remove “FileXYZ” : access  is denied”.  I have the extension installed but apparently that is only used for modified files.  Here are my modified scripts. 

    ———————–FILE: push.ps1—————————————————-

    $projName = “TicTacToeCMMI”
    $tftp = “C:Program FilesMicrosoft Team Foundation Server 2010 Power ToolsTFPT.exe”
    $tf = “C:Program FilesMicrosoft Visual Studio 10.0Common7idetf.exe”

    hg push
    cd ..$projName-tfs

    “Syncing -tfs workspace with TFS server”
    &$tftp scorch /noprompt /exclude:.hg’,_Resharper*’,*.user

    hg update -C -y

    “Resyncing Mercurial changes with TFS Server”
    &$tftp online /adds /deletes /diff /exclude:’.hgignore,.hg,bin,obj,*.ps1,_Resharper*,*.lnk,*.user,*.suo,*.vspscc’

    &$tf checkin
    cd ..$projName-working
    cmd /c pause

    ———————–FILE: pull.ps1—————————————————-

    $projName = “TicTacToeCMMI”

    $tf = “C:Program FilesMicrosoft Visual Studio 10.0Common7idetf.exe”

    $username = cmd /c set USERNAME

    $username = $username.SubString($username.IndexOf(“=”)+1)

    function pull {

        cd ..$projName-tfs

        &$tf get

        hg commit -A -m “from tfs” –user $username

        cd ..$projName-working

        hg pull –rebase



    cmd /c pause


  • Ben

    Here is a powershell script I created with doesn’t require the and also pushs renames made in HG back into TFS….

    param([parameter(Position=0, Mandatory=$true)][string] $action)$HGDirectory = Get-Location$TfsDirectory = @(hg paths | where-object { $_.StartsWith(“default = “) })[0].SubString(10)# Pull from TFSfunction pull{    # Todo pull changes one by one brining who did it and the comment into HG    # tf history . /recursive /format:brief /noprompt /version:300~1000 /sort:ascending    # tf properties . /recursive    # Add the changes from TFS into the TFS HG repository    Set-Location $TfsDirectory    tf get . /recursive    hg commit -A -m “Update from TFS”          # Pull / merge the changes from TFS’s HG repository    Set-Location $HGDirectory    hg pull    hg merge –tool internal:fail    hg commit -m “Merged from TFS”        “”    “The you have the following conflicts which need resolving”    hg resolve -l | write-host -foregroundcolor “red”    #thg commit}# Push to TFSfunction push {    Set-Location $HGDirectory    hg push    Set-Location $TfsDirectory    $FilesModified = @()    $FilesRenamed = @{} # Key: old file name …. Val: new file name    $FilesRemoved = @()    $FilesAdded = @()    # Work out what changes have taken place    “Calculating the changes which have been made in HG…”    tfpt scorch /exclude:.hg,*.user | out-null    $AllChanges = hg status –rev .:tip -A     for($i = 0; $i -lt $AllChanges.length ; $i++)    {        $type = $AllChanges[$i].SubString(0, 2)        $fileName = $AllChanges[$i].SubString(2)                    switch($type)        {            “M ” # Modified files                  {                     $FilesModified += $fileName                }             “A ” # New Files                {                      $nextType = $null                    $nextFileName = $null                    if($AllChanges.length -gt ($i+1))                    {                        $nextType = $AllChanges[$i+1].SubString(0, 2)                        $nextFileName = $AllChanges[$i+1].SubString(2)                                    }                                        if($nextType -eq ”  ”)                    {                        # we have a rename                        $FilesRenamed[$nextFileName]=$fileName                        $i++                    }                    else                    {                        # we’re adding the file                        $FilesAdded += $fileName                    }                 }                             “R ” # Removed                {                    if($FilesRenamed.ContainsKey($fileName))                    {                        continue                    }                                        $FilesRemoved += $fileName                }                        “C ” # Same                 {                     continue                 }                             default                 {                     “Unknown HG status line: “+$AllChanges[$i]                     return -1                }        }    }    # perform the TFS operations     “Renaming files in TFS…”    foreach($file in $FilesRenamed.Keys) {           tf checkout $file | out-null        tf rename $file $FilesRenamed[$file] | out-null    }        “Checking out for edit in TFS…”    foreach($file in $FilesModified) { tf checkout $file | out-null }        “Removing files from TFS…”    foreach($file in $FilesRemoved) { tf delete $file | out-null }    # perform the Mercural update    “Pulling changes out of HG….”    hg update –rev .:tip –clean    # perform any POST TFS operations    “Adding new files to TFS…”    foreach($file in $FilesAdded) { tf add $file }        “Cleaning up…”    tfpt uu /noget    tf checkin}if ($action -eq “push”) { push }elseif ($action -eq “pull”) { pull }else { “Unknown action … please supply ‘push’ or ‘pull’” }# return to our starting pointSet-Location $HGDirectory

  • Justinas Urbanavicius

    if you would use tfs repository location:local instead of server there would be no readonly files, and no need to make them writeable

  • David Logan

    I’m trying to find a way to import a Mecurial(hg) database into Team Foundation Services( and wondering if you might could point me in the right direction?

    • erichexter

      It’s been over three years since I worked with Mecurial or TFS. Back then there was a Java app the TFS team put together that could do a history migration but I have no idea where you would find it now.

      • David Logan

        Eric, do you know how you map users when you import from Mercuial to Git? When I do the import it shows the users but when you look at “users” in Git Admin is the only one. Do I just add users with the same name?