tfs - ¿Uso en el mundo real de Mercurial con un Team Foundation Server?
(8)
@Eric, tu publicación en lostechies fue de lo más útil. Con VS2010 tuve que agregar options / diff y / deletes al comando en línea de tftp en el script de inserción para obtener los archivos modificados y eliminados para que se comprueben en TFS. Inicialmente, recibí un error al presionar cuando se eliminó un archivo (del trabajo) que la actualización de hg es
"no se puede eliminar FileXyz : acceso denegado".
Instalé la extensión MakeWritable.py pero eso solo funciona cuando los archivos no se abren. Así que agregué una llamada a attrib para eliminar READ-SOLAMENTE de todos los archivos del proyecto y luego restaurarlo después (excluyendo la carpeta .hg). También agregué la opción / diff para que las diferencias sean detectadas por la suma de verificación MD5 en lugar de depender de el atributo LECTURA ÚNICA. Parece estar funcionando bien ahora.
=====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
Tenía un poco de una curva de aprendizaje con scripts de PowerShell que no había usado antes. Para otros como yo, los scripts se ejecutan con un atajo como este:
TARGET: C:/WINDOWS/system32/WindowsPowerShell/v1.0/powershell.exe C:/dev/TicTacToeCMMI-working/push.ps1
START IN: C:/dev/TicTacToeCMMI-working
Pongo accesos directos de inserción y extracción en la barra de tareas, por lo que presionar / arrastrar a / desde TFS es un solo clic
Mi tienda usa TFS & en general está contento con ella, con la excepción de la falta de confirmaciones / reintentos de repositorio local. Estoy comenzando a usar Mercurial localmente para ayudar a administrar pequeños fragmentos de cambios, y luego publicarlos en TFS. Veo que Subversion tiene un componente ''puente'' para habilitar esto automáticamente si el VCS central es Subversion. No he encontrado uno para Team System. Esto me alienta a que otras personas hayan seguido este camino con la integración de DVCS con sistemas CVCS.
(1) ¿Alguien sabe de uno? Lo estoy dudando (la búsqueda rápida no encontró nada).
(2) ¿Alguien está usando Mercurial / TFS de esta manera? Si es así, ¿puedes compartir tus experiencias? Estoy particularmente buscando información sobre los problemas que pueden surgir y que no son obvios con respecto a los compromisos con TFS después de una actividad significativa a través de Mercurial.
Hasta ahora, parece un total ganar-ganar con solo usarlo si durante unos días, pero sé lo suficiente como para pensar que es así de fácil.
Aquí hay un script de PowerShell que he estado usando para trabajar con TFS y hg. Para utilizarlo, deberá crear un repositorio hg en su carpeta TFS (confirmar los archivos de TFS en él), clonar este repositorio y trabajar en el nuevo repositorio. Una vez que esté contento, puede ejecutar "hgtfs.ps1 push" para volver a introducir los cambios en TFS desde su repositorio de mercurial.
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
Junté una pequeña herramienta, HgTfs, que trata de lograr el objetivo de sincronizar los repositorios Mercurial y TFS. Es realmente simple y tiene solo tres comandos: clonar, tirar y empujar. Aquí está mi repositorio Bitbucket:
https://bitbucket.org/thepretender/hgtfs
También hay una publicación de blog que describe el flujo de trabajo y los escenarios de uso (en realidad, las páginas wiki son solo partes de esta entrada de blog):
http://www.olegtarasov.me/Post/2013/07/Mercurial-to-TFS-bridge-(hgtfs)
El código es raro, pero parece hacer el trabajo. Realmente agradecería cualquier comentario o bifurcación :)
No estoy seguro de si esto es algo que aún no sabe, pero he estado utilizando mercurial localmente por un tiempo, y hasta ahora creo que los beneficios superan la carga adicional de administrar los dos sistemas de control de origen. Así es como he estado haciendo las cosas:
Hice mi TFS checkout un repositorio de HG que considero mi "maestro". Recibo actualizaciones de TFS y las comprometo con este repositorio, por lo que este contiene el estado más actual del proyecto de TFS. Lo importante aquí es que no hay cambios en esto hechos independientes de una actualización de TFS o una fusión de Hg (que es la parte 2)
Cada vez que necesito hacer un cambio, clono mi repo "maestro" y hago mi trabajo allí. Descubrí que un clon por cada característica o historia es bastante fácil de administrar y se siente bastante limpio. Una vez que complete una función, hago una fusión Hg de nuevo al repositorio "maestro", que ha tenido todas las actualizaciones de TFS aplicadas. Esto me permite usar las capacidades de fusión de Mercurials, que son muy superiores a TFS y poner en duda cómo TFS puede pretender fusionar el código. Una vez que se completa la fusión, la aplico en Hg, y luego verifico esos cambios en TFS. La mejor parte de esto es que cuando realizo el registro en TFS, no tengo que fusionar nada. Muy, muy agradable.
Ahora, aquí están los problemas que he encontrado con este enfoque:
El más grande es el hecho de que TFS es pésimo para encontrar cambios. Existe un complemento de escritura modificable que puede utilizar para hacer que los archivos modificados puedan escribirse cuando Mercurial los actualice / fusione. Hay dos opciones que he encontrado para esto. Puede forzar a TFS a desconectarse, momento en el que asumirá que debe registrarse todo lo que se pueda escribir, o puede usar la herramienta de comparación en la herramienta de control de origen y seleccionar los archivos cambiados y verificarlos individualmente. Ambos son malos IMO
Los enlaces de control de fuente todavía están allí a nivel de proyecto, incluso si excluye los archivos de control de fuente TFS de su repositorio de hg (lo cual debería hacer). Esto no es completamente obvio hasta que agregue un archivo a la solución, en cuyo momento intenta agregarlo al control de fuente. Puede "Deshacer cambios pendientes" y deshacerse del complemento de control de origen, pero es realmente molesto.
La buena noticia es que utilicé este enfoque para trabajar a través de una fusión bastante masiva que creo que me habría llevado a recurrir a alguna forma de drogas duras si me hubiera visto obligado a utilizar las herramientas TFS para hacerlo.
Todavía no he aplicado esto para actualizar las sucursales dentro de TFS, pero supongo que sería mucho mejor que las opciones que se ofrecen para fusionarse en TFS. En una nota relacionada, dado que puede verificar fragmentos de funcionalidad de trabajo al mismo tiempo, usar la fusión TFS sería menos problemático simplemente porque todos los cambios necesarios para una característica estarían juntos en un solo lugar.
Una cosa que no he intentado abordar es compartir esto en todo el equipo. Parte de la razón es que realmente no tiene que ser una cosa de todo el equipo. Trabajo de forma remota, por lo que tener un repositorio local es un gran problema, y ahorra mucho tiempo. Los otros miembros de mi equipo de desarrollo pueden o no obtener el mismo beneficio de este enfoque, pero me parece genial que puedo sin afectar la forma en que funcionan.
Actualización He estado queriendo actualizar esta respuesta por un tiempo con información adicional basada en comentarios y algunas de mis experiencias trabajando con grandes repositorios TFS.
Primero, como señala @ Eric Hexter en los comentarios, puede utilizar la extensión de rebase para integrar mejor las confirmaciones de sus repositorios de trabajo en su repositorio principal de TFS. Sin embargo, dependiendo de cómo desee que sus confirmaciones se muestren a TFS, es posible que desee utilizar la extensión de colapsar para aplastar sus cambios en una sola confirmación (esto puede facilitar las reversiones en TFS). También está el comando "en línea" de TFS PowerTools que puede hacer que el trabajo de dejar que TFS sepa lo que ha cambiado es más fácil (gracias de nuevo a Eric por mencionarlo en su publicación de blog )
Ahora, cuando originalmente escribí esto, estaba trabajando en un proyecto que tenía solo una rama TFS que los desarrolladores usaban, y era bastante pequeño, por lo que los repositorios de clonación no eran un gran problema. Más tarde me encontré trabajando en un proyecto que tenía un repositorio que era de aproximadamente 1,5 GB después de la finalización de la compra, y mucho más grande después de la compilación, e involucraba cambiar de rama en TFS con bastante frecuencia. Claramente, este enfoque no se adapta bien a este entorno (sobre todo porque en un momento dado fue imposible construir las soluciones en un directorio arbitrario).
El problema de tamaño se maneja mejor mediante la utilización de una técnica similar a las ramas de temas de gits en lugar de clonar los repositorios en nuevos directorios. Hay un par de opciones para esto. Creo que lo mejor es usar la extensión de marcador y crear un tema "marcadores" en lugar de ramas de tema. También puede usar ramas con nombre, pero tienen la ligera desventaja de ser permanentes y viajar con clones que pueda hacer (si desea compartir su ingenioso híbrido TFS-Hg con un colega). Los marcadores son locales para su repositorio, y apuntan a un compromiso y viajan con la cabeza. Se implementan para que puedan usarse en cualquier lugar donde Hg esté esperando una revisión (por lo tanto, fusiones, actualizaciones, etc.). Puede usarlos para crear un marcador TFS como su "sucursal" primaria que solo obtiene actualizaciones de TFS, y se fusiona con el trabajo del tema, que tendrá sus propios marcadores, y puede eliminar una vez que se haya comprometido nuevamente con TFS. Si prefiere usar ramas con nombre, puede aplicar exactamente las mismas técnicas, lo cual es útil.
Ahora, el problema de la bifurcación múltiple es más complicado, especialmente dado que las "sucursales" de TFS son en realidad copias de cada archivo de la sucursal original, lo que significa que cada vez que extraes ramas de TFS, tu repositorio se hará mucho más grande. Una forma posible de lidiar con esto es utilizar una combinación de ramas Hg con nombre y marcadores, para que tenga una rama para cada rama TFS y luego crear marcadores para su trabajo fuera de esas ramas. El verdadero dolor de cabeza en estos escenarios es en realidad lidiar con espacios de trabajo TFS a través de todo esto. Puede eliminar las asignaciones en sus espacios de trabajo y llegar bastante lejos, pero una vez que vuelva a su directorio de trabajo debe tener cuidado con TFS pisando fuerte en los archivos (esto es en realidad donde el TF PowerTools es útil). Tratar de dejar el espacio de trabajo conectado mientras cambias de rama se pone feo rápido. Un par de herramientas que son agradables tener en su toolbelt son la extensión de purga de Hg y el comando "scorch" de TF PowerTools. Ambos eliminan los archivos que no están en control de versiones (técnicamente "scorch" aseguran que TFS y su directorio de trabajo local coincidan, por lo que también podría actualizar los archivos).
Para mí, sin embargo, este proceso se volvió bastante pesado y propenso a errores. Recientemente cambié al uso de git con git-tfs , ya que administra espacios de trabajo TFS para mí y elimina gran parte de la carga asociada con ese lado. Lamentablemente, no parece haber un "hg-tfs" en ninguna parte, o probablemente habría elegido eso.
Sé que algunas personas han usado hgsubversión con el puente de Subversión. No sé qué tan bien funcionó, y nunca tuve que usar TFS.
Por lo que sé, no hay un puente "más nativo" que usar TFS -> Subversion Bridge -> hgsubversion, pero también he oído que funciona bastante bien. Mi comprensión extremadamente limitada de TFS sugiere que su modelo interno debería ser lo suficientemente similar a Subversion para que cosas como hgsubversion funcionen realmente bien.
Si no estás atascado en mercurial, hay un proyecto de integración dulce git / tfs que he estado usando llamado git-tfs. Es muy similar a git-svn, pero en su lugar empuja / tira de TFS. Compruébelo en http://github.com/spraints/git-tfs
Tuve una buena oportunidad para hacerlo funcionar. Pude hacer que Git y TFS jugaran juntos ( link ) a través de svnbridge, pero no pude hacer que mercurial funcionara a través de svnbridge, lo que me frustraba infinitamente. Si logras hacerlo funcionar, házmelo saber, porque personalmente prefiero mercurial over git (aunque ambos son geniales)