使用Team Foundation Server实际使用Mercurial?

我的商店使用TFS,除了缺less本地仓库提交/还原之外,通常对此感到满意。 我开始在本地使用Mercurial来帮助pipe理更小的更改块,然后将它们发布到TFS。 我发现如果中央VCS是Subversion的话,Subversion有一个“桥”组件可以自动启用这个function。 我还没有find一个适用于团队系统。 这鼓励了我,其他人将DVCS与CVCS系统集成在一起。

(1)有人知道吗? 我有点怀疑它(快速search没有find任何东西)。

(2) 有没有人用这种方式使用Mercurial / TFS? 如果是这样,你可以分享你的经验。 我特别希望了解哪些问题可能会出现,这些问题对于通过Mercurial进行重大活动后提交给TFS并不明显。

到目前为止,这似乎是一个完全双赢的局面,只要我用了几天的时间 – 但是我知道的够多的话,就可以认为这就是那么简单。

不知道这是不是你已经知道的东西,但我已经在本地使用了一段时间的mercurial,到目前为止,我认为它的好处超过了pipe理两个源代码pipe理系统的额外开销。 以下是我一直在做的事情:

  1. 我做了我的TFS结帐HG存储库,我认为我的“主人”。 我从TFS获得更新并将它们提交到此回购站,所以这包含了TFS项目的最新状态。 这里重要的是没有任何变化,这是独立的TFS更新或汞合并(这是第2部分)

  2. 任何时候我需要改变,我克隆我的“主”回购,并在那里做我的工作。 我发现每个function或故事的克隆实际上很容易pipe理,感觉很干净。 一旦我完成了一个function,我就会将汞合并回“主”回购,这个回购已经应用了所有的TFS更新。 这使我可以使用Mercurials合并function,这些function远远优于TFS,从而引起人们质疑TFS如何声称合并代码。 一旦合并完成,我将它提交到Hg中,然后将这些更改复制到TFS中。 最好的部分是,当我做TFS签入时,我不需要合并任何东西。 非常非常棒。

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

  1. 最大的一个事实是,TFS发现变化是糟糕的。 有一个make可写插件,当Mercurial更新/合并时,可以使用它来使修改后的文件可写。 有两个选项我find了这个。 您可以强制TFS进入脱机状态,此时它将假定需要检入的任何可写操作,或者您可以使用源代码pipe理工具中的比较工具,select已更改的文件并单独检出。 两者都是蹩脚的IMO

  2. 源代码控制绑定仍然存在于项目级别,即使您从hg存储库中排除了TFS源代码控制文件(您应该这样做)。 直到你添加一个文件到这个解决scheme,这个东西并不是很明显,在这个时候它会尝试把它添加到源代码控制中。 你可以“撤消挂起的变化”,摆脱源代码控制添加,但它真的很烦人。

好消息是,我使用这种方法来进行相当大规模的合并,如果我不得不使用TFS工具来实现这种合并,我认为这会导致我转向某种forms的硬性毒品。

我还没有应用这个更新TFS内的分支,但我的猜测是,它会比你在TFS中进行合并的选项好得多。 在相关说明中,因为您可以一次检查大量的工作function,所以使用TFS合并将不太成问题,因为function所需的所有更改都集中在一个地方。

我还没有试图解决的一件事是在整个团队中分享。 部分原因是它并不一定是一个团队的事情。 我远程工作,因此有一个本地存储库是一个大问题,并节省了大量的时间。 我的开发团队的其他成员可能会也可能不会从这个方法中获得同样的好处,但是我觉得我可以在不影响他们工作的情况下很酷。

更新我一直想更新这个响应一段时间,其他信息基于评论和一些我的经验与大型TFS存储库的工作。

首先@ Eric Hexter在评论中指出,您可以利用rebase扩展来更好地将工作库中的提交集成到主要的TFS库中。 虽然,根据你希望提交到TFS的方式,你可能希望使用collapse扩展来将你的改变压缩成一个单独的提交(这可以使TFS中的回滚更容易)。 还有TFS PowerTools的“在线”命令,可以让TFS知道变化的更容易(再次感谢Eric在他的博客中提到这一点)

现在,当我写这篇文章的时候,我正在开发一个只有一个开发人员正在使用的TFS分支的项目,而且这个项目相当小,所以克隆版本库没有什么大不了的。 后来我发现自己在一个项目上做了一个项目,这个项目在结账后有大约1.5GB的回购,而且在构build之后还要大得多,并且经常在TFS的分支机构之间进行切换。 显然,这种方法并不适合这种环境(特别是因为在某个时候,不可能在任意目录中构build解决scheme。

大小问题最好通过使用类似于gits主题分支的技术来处理,而不是将存储库克隆到新的目录。 这有几个选项。 我认为最好的实际上是使用书签扩展,并创build主题“书签”,而不是主题分支。 你也可以使用命名分支,但是它们有永久性的轻微缺点,并且可能会使用任何克隆(如果你想和同事分享你漂亮的TFS-Hg混合体)。 书签是本地的回购,并有效地指向提交和头部旅行。 他们的实施,使他们可以在任何地方使用汞预计修改(所以合并,更新等)。 您可以使用这些创build一个TFS书签作为您的主要“分支”,只从TFS获取更新,并从主题工作合并,每个主题工作都有自己的书签,一旦您提交回TFS,就可以删除。 如果你想使用命名分支,那么你可以应用完全相同的技术,这是很方便的。

现在,多分支问题更加棘手,特别是因为TFS“分支”实际上是原始分支中每个文件的副本,这意味着每次从TFS引入分支时,您的回购将会变得更大。 解决这个问题的一个可能的方法是使用名为Hg分支和书签的组合,以便每个TFS分支都有一个分支,然后为这些分支的工作创build书签。 在这些场景中真正的头痛实际上是通过所有这些处理TFS工作区。 您可以删除工作区中的映射,但是一旦映射回工作目录,就必须小心TFS对文件的跺脚(实际上TF TFTools可以派上用场)。 尝试离开工作区时,您的切换分支变得丑陋快速。 在你的工具带中有一些很好的工具是Hg 清除扩展和TF PowerTools的“焦烧”命令。 这两个有效地删除不在版本控制的文件(技术上“烧焦”,确保TFS和本地工作目录匹配,所以它也可以更新文件)。

但对我而言,这个过程变得相当繁重和容易出错。 我最近开始使用git -tfs ,因为它为我pipe理TFS工作空间,并消除了与这一方相关的很多负担。 可悲的是,在任何地方似乎都没有“hg-tfs”,或者我可能会select这样做。

如果你没有被困在mercurial上,我已经使用了一个叫git-tfs的git / tfs集成项目。 这和git-svn非常相似,但是从TFS推送/取出。 在http://github.com/spraints/git-tfs查看;

@Eric,你在lostechies的post是最有帮助的。 在VS2010中,我必须在推送脚本中的tftp online命令中添加选项/比较/或删除 ,以将更改和删除的文件签入到TFS中。 最初,当一个文件被删除(从工作), hg更新时,我得到一个错误
“无法删除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是一个单一的点击

我知道有些人使用Subversion桥接器的hgsubversion。 我不知道它有多好,我从来没有使用过TFS。

据我所知,没有比使用TFS – > Subversion Bridge – > hgsubversion更“本地化”的桥梁,但是我也听说它工作得很好。 我对TFS的理解非常有限,这表明它的内部模型应该与Subversion相似,就像hgsubversion那样工作得很好。

如果你想能够使用DVCS和TFS,我相信最好的方法是安装TFS的SVNBridge ,并且使用Bazaar ,也就是AFAIK,它是唯一可以轻松集成SVN的DVCS,而且现在你的TFS看起来像一个SVN,你神奇地获得Bazaar / TFS集成

这里是我一直使用TFS&hg的PowerShell脚本。 要使用你需要在你的TFS文件夹中创build一个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 

我只是把一个小工具,HgTfs,试图实现同步Mercurial和TFS存储库的目标。 这很简单,只有三个命令:克隆,拉和推。 这是我的Bitbucket回购:

https://bitbucket.org/thepretender/hgtfs

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

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

代码是hacky,但它似乎完成了工作。 我真的很感激任何反馈或叉子:)

我有一个很好的尝试,使其工作。 我可以通过svnbridge让Git和TFS一起玩( 链接 ),但是我无法通过svnbridge工作,这让我感到沮丧。 如果你设法让它工作,让我知道,因为我个人比git更喜欢mercurial(虽然都很好)