在团队基础服务器上实际使用Mercurial?


68

我的商店使用TFS,除缺乏本地存储库提交/还原外,我通常对此感到满意。我开始自己在本地使用Mercurial来帮助管理较小的更改,然后将其发布到TFS。我看到Subversion有一个“桥”组件,如果中央VCS是Subversion,则可以自动启用它。我还没有为Team System找到一个。这使我感到鼓舞,其他人已经将DVCS与CVCS系统集成在一起。

(1)有人知道吗?我对此表示怀疑(快速搜索未找到任何内容)。

(2)是否有人以这种方式使用Mercurial / TFS?如果可以,可以分享您的经验。我特别想寻找任何关于可能发生的问题的见解,这些问题在通过Mercurial进行了大量活动之后对于TFS的提交并不明显。

到目前为止,只有我使用if几天似乎是一个双赢的局面,但是我知道那么多就这么简单。

Answers:


53

不知道这是否是您尚不知道的东西,但是我已经在本地使用了一段时间,到目前为止,我认为其好处超过了管理两个源代码控制系统所增加的开销。这是我一直在做的事情:

  1. 我将TFS结帐设置为HG存储库,我认为这是“主”文件。我从TFS获得更新并将它们提交到此存储库,因此它包含TFS项目的最新状态。这里重要的是,对此所做的任何更改都不会独立于TFS更新或Hg合并(这是第2部分)

  2. 每当我需要进行更改时,我都会克隆我的“主”存储库并在那里做我的工作。我发现每个功能或故事的克隆实际上很容易管理,而且感觉很干净。完成功能后,我将Hg合并回“主”存储库,该库已应用了所有TFS更新。这使我可以使用Mercurials合并功能,该功能远远优于TFS,以至于使人怀疑TFS如何声称可以完全合并代码。合并完成后,我将其提交到Hg中,然后将这些更改检查到TFS中。最好的部分是,当我对TFS进行签入时,我不必合并任何内容。非常非常棒。

现在,这是我使用这种方法发现的问题:

  1. 最大的事实是,TFS很难找到更改。有一个使可写的插件,当Mercurial更新/合并修改后的文件时,可使用该插件使它们变为可写的。我为此找到了两个选择。您可以强制TFS脱机,这时它将假定需要签入任何可写内容,或者可以使用源代码管理工具中的比较工具并选择更改的文件并逐个签出。两者都是糟糕的IMO

  2. 即使从hg存储库中排除了TFS源代码控制文件,源代码控制绑定仍在项目级别上(应该这样做)。在将文件添加到解决方案之前,这并不十分明显,此时它将尝试将其添加到源代码管理中。您可以“撤消待更改”并摆脱源代码控件的添加,但这确实很烦人。

好消息是,我使用这种方法进行了相当大的合并,如果我被迫使用TFS工具来进行合并,我认为这会使我转向某种形式的硬性药物。

我还没有将其应用于更新TFS中的分支,但是我猜想它会比为TFS进行合并提供的选项好得多。值得一提的是,由于您可以一次检入工作功能块,因此使用TFS合并将不会有太大问题,因为一个功能所需的所有更改都将集中在一个地方。

我没有试图解决的一件事是在整个团队中共享这一点。部分原因是,它实际上不一定是整个团队的事情。我是远程工作的,因此拥有本地存储库很重要,并且可以节省大量时间。我的开发团队的其他成员可能会或可能不会从这种方法中获得相同的好处,但是我发现很酷,我可以在不影响他们工作方式的情况下做到这一点。

更新资料 我一直想用评论和我在大型TFS存储库上的一些经验为基础的附加信息来更新此响应。

首先,正如@ Eric Hexter在评论中指出的那样,您可以利用rebase扩展将您的工作存储库中的提交更好地集成到您的主要TFS存储库中。但是,根据您希望提交在TFS中显示的方式,您可能希望使用折叠扩展将更改压缩到单个提交中(这可以使TFS中的回滚更加容易)。TFS PowerTools中还有一个“在线”命令,可以使TFS知道发生了什么变化的工作变得更加容易(再次感谢Eric在他的博客文章中提到)。

现在,当我最初写这篇文章时,我正在开发一个只有开发人员正在使用的TFS分支的项目,并且这个项目很小,因此克隆存储库没什么大不了的。后来我发现自己正在从事一个项目,该项目的存储库在签出后大约为1.5GB,在构建后更大,并且经常在TFS中切换分支。显然,这种方法不太适合这种环境(特别是因为有时无法在任意目录中构建解决方案。

通过使用类似于gits topic分支的技术而不是将存储库克隆到新目录,可以最好地解决大小问题。有两种选择。我认为最好的方法是使用书签扩展名并创建主题“书签”,而不是主题分支。您也可以使用命名分支,但是它们有一个永久性的缺点,即可以随身携带任何克隆(如果您想与同事共享漂亮的TFS-Hg杂种)。书签在您的存储库中是本地的,可以有效地指向提交并随脑袋旅行。实施它们是为了使它们可以在Hg希望进行修订的任何地方使用(例如合并,更新等)。您可以使用它们来创建TFS书签作为您的主要“分支”,该分支仅从TFS获取更新,并从主题工作中合并,每个主题工作都有自己的书签,一旦提交回TFS,就可以删除。如果您想使用命名分支,则可以应用完全相同的技术,这很方便。

现在,多分支问题变得更加棘手,尤其是因为TFS“分支”实际上是原始分支中每个文件的副本,这意味着每次从TFS中引入分支时,您的仓库都会变得更大。解决此问题的一种可能方法是使用命名的Hg分支和书签的组合,以便为每个TFS分支都有一个分支,然后为这些分支之外的工作创建书签。在这些情况下,真正令人头疼的实际上是通过所有这些来处理TFS工作区。您可以删除工作空间中的映射,并且可以走得很远,但是一旦映射回工作目录,就必须小心TFS踩踏文件(实际上这是TF PowerTools派上用场)。在切换分支时,尝试使工作空间保持连接状态非常麻烦。Hg是两个很不错的工具清除扩展名和TF PowerTools的“ scorch”命令。两者都有效地删除了不在版本控制中的文件(从技术上来说,“烧焦”可确保TFS与本地工作目录匹配,以便它也可以更新文件)。

但是,对我而言,此过程变得非常繁重且容易出错。我最近改用git和git-tfs,因为它可以为我管理TFS工作区,并消除了与此有关的许多负担。可悲的是,似乎在任何地方都没有“ hg-tfs”,否则我可能会选择它。


除了perforce是最受好评的中央存储库之外,我执行了类似的方法。您列出的问题也存在。我正在尝试将工作流程调整为以功能为重点,并且补丁队列功能到目前为止,我对此非常满意。
汤姆·威利斯2010年

2
使用内置工具时,合并对TFS的影响较小。詹姆斯·曼宁就如何交换出来的东西(我喜欢SourceGear的DiffMerge)更好的一个很好的文章blogs.msdn.com/b/jmanning/archive/2006/02/20/...
StingyJack

13
我在博客中介绍了使用此设置的经验。lostechies.com/blogs/hex/archive/2010/06/22/…我添加了一些powershell脚本来自动使用hg和TFS powertools。我使用的另一个扩展是hg rebase,以使HG方面的合并非常简单。我知道有两个简单的powershell命令。推和拉,这将以正确的顺序运行hg和tfs命令行。
埃里克·赫克斯特

@Eric,多数民众赞成在一些好东西。当我写这篇文章时,我并不知道rebase扩展,它可能会在不久的将来进入我的工具箱。powershell命令也很棒。
ckramer 2010年

我已经考虑了一段时间,并且...我仍然停留在如何处理现有TFS分支之间使用Mercurial进行合并的问题上。如果在分支中进行更改,通常需要使用TFS合并将其合并到根。关于在这种情况下如何利用Mercurial存储库的任何想法?每个TFS分支是否需要一个hg克隆?当有人创建TFS分支时,是否可以自动创建hg克隆?
Jeramy Rutley 2010年


5

@Eric,您在Lostchesies的帖子很有帮助。使用VS2010,我必须在推脚本中向tftp在线命令中添加选项/ diff/ deletes,以获取更改和删除的文件以检入TFS。最初,我是从推得到一个错误,当一个文件被删除(从木材加工),其汞更新是 “无法删除FileXyz:访问被拒绝”。 我安装了MakeWritable.py扩展名,但该扩展名仅在打开文件且未删除时才起作用。因此,我添加了一个对attrib的调用,以从项目中的所有文件中删除只读文件,然后再将其还原(.hg文件夹除外),我还添加了

/ diff选项,以便通过MD5校验和检测差异,而不是取决于READ-ONLY属性。似乎现在工作正常。

=====FILE: push.ps1=====
$projName = "TicTacToeCMMI"
$tftp = "C:\Program Files\Microsoft Team Foundation Server 2010 Power Tools\TFPT.exe"
$tf = "C:\Program Files\Microsoft Visual Studio 10.0\Common7\ide\tf.exe"

hg push
cd ..\$projName-tfs  
"Syncing -tfs workspace with TFS server"  
&$tftp scorch /noprompt /exclude:.hg',_Resharper*',*.user  
"Making all files in -tfs writable"
attrib -R /S /D *
"Updating -tfs with latest push from Mercurial"
hg update -C -y
attrib +R /S /D *
attrib -R /S /D .hg\*
"Resyncing Mercurial changes with TFS Server"  
&$tftp online /adds /deletes /diff /exclude:'.hgignore,.hg,bin,obj,*.ps1,_Resharper*,*.lnk,*.user,*.suo,*.vspscc'  
"Checkin"  
&$tf checkin  
cd ..\$projName-working  
cmd /c pause  

====FILE: pull.ps1=====
$projName = "TicTacToeCMMI"
$tf = "C:\Program Files\Microsoft Visual Studio 10.0\Common7\ide\tf.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
}
pull  
cmd /c pause  

我以前从未使用过的PowerShell脚本有一些学习曲线。对于像我这样的其他人,脚本是用这样的快捷方式运行的:

TARGET: C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe C:\dev\TicTacToeCMMI-working\push.ps1
START IN: C:\dev\TicTacToeCMMI-working

我将推和拉快捷方式放在任务栏上,因此只需单击一下即可向TFS推入/拉出


3

我知道有人在Subversion桥中使用了hgsubversion。我不知道它的效果如何,而且我从未使用过TFS。

据我所知,没有比使用TFS-> Subversion Bridge-> hgsubversion更“本机”的桥了,但是我也听说它能很好地工作。我对TFS的了解极为有限,这表明它的内部模型应该与Subversion足够相似,以使hgsubversion之类的东西能够很好地工作。



2

这是我用于TFS和hg的powershell脚本。要使用它,您需要在TFS文件夹中创建一个hg储存库(将TFS中的文件提交到其中),克隆该储存库并在新的储存库上工作。一旦高兴,您可以运行“ hgtfs.ps1 push”以将更改从您的Mercurial存储库推回到TFS。

hgtfs.ps1:

param([parameter(Position=0, Mandatory=$true)][string] $action)

$HGDirectory = Get-Location
$TfsDirectory = @(hg paths | where-object { $_.StartsWith("default = ") })[0].SubString(10)

# Pull from TFS
function 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 TFS
function 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 point
Set-Location $HGDirectory

此Powershell脚本的工作情况如何?任何人有使用此的经验吗?
詹姆斯

2

我只是组合了一个小工具HgTfs,它试图实现同步Mercurial和TFS存储库的目标。它非常简单,只有三个命令:clone,pull和push。这是我的Bitbucket回购:

https://bitbucket.org/thepretender/hgtfs

还有一篇博客文章描述了工作流程和使用场景(实际上,Wiki页面只是该博客文章的一部分):

http://www.olegtarasov.me/Post/2013/07/Mercurial-to-TFS-bridge-(hgtfs)

该代码是hacky,但似乎可以完成工作。我真的很感激任何反馈或分叉:)


很好,当我们从ClearCase迁移到TFS时,我将使用它(/叹气)[仍在寻找“用轨道枪选项向我射击” ...完全需要:p]
Sam Mackrill

1

我做了一个很好的尝试,使其正常工作。我可以通过svnbridge让Git和TFS一起玩(link),但是我无法通过svnbridge来工作,这让我无休止。如果您设法使其正常运行,请告诉我,因为我个人比较喜欢git而不是git(尽管两者都很棒)



据我所知,Mercurial支持是与TFS完全独立的服务器。这不是像Subversion支持那样的桥接安排。
理查德·班克斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.