Team Foundation Server-Mover Fuente con Historial


Me preguntaba cuál podría ser el mejor enfoque para mover el código fuente, con el historial, de un Proyecto de Equipo a otro Proyecto de Equipo. No me preocupan los elementos de trabajo, los informes o los sitios de SharePoint, ya que el sistema desde el que vamos a restaurar no usó estas funcionalidades. La razón para querer pasar a un proyecto de Equipo diferente también está impulsada por el hecho de que la implementación original (que se restaura a partir de una copia de seguridad que fue mantenida por un tercero) estaba utilizando un plantilla de proceso de terceros que no deseamos utilizar en el futuro. Queremos comenzar a utilizar el seguimiento y los informes de los elementos de trabajo después de que se complete la migración.

La Plataforma de Integración TFS parece ser un escenario probable. Se puede utilizar para cambiar la plantilla de proceso, de acuerdo con la documentación. Sin embargo, tenía curiosidad si el tf.¿la sintaxis de movimiento exe podría funcionar? Algo como:

Tf.exe move move / ProjectA {/ProjectB

Tengo entendido que esto el comando funciona como una operación de cambio de nombre, mientras que moverse con el elemento del menú contextual" Mover " en el Explorador de Control de código fuente es más como una operación de eliminar y agregar. Además, sería el tf.exe move path en realidad asocia el código bajo las carpetas con el Proyecto de Equipo apropiado, asumiendo que $/ProjectA es la carpeta de control de código raíz para un proyecto y $/ProjectB es la carpeta de control de código raíz para el otro? La clave es ser capaz de preservar la historia, si es posible.

Cualquiera consejos o consejos serían muy apreciados!

Editar - Podría ramificar a otro proyecto manejar este escenario - al igual que Microsoft discute en el Guía de ramificación documentación? Creo que esta podría ser la respuesta, ya que la historia probablemente se conservaría con la rama. Sin embargo, no tengo acceso a una instancia de Team Foundation Server 2008 en este momento para probarlo.

Author: Joseph Ferris, 2010-02-07

4 answers

Mover y renombrar son alias. No hay absolutamente ninguna diferencia, en cualquier versión de TFS, de la línea de comandos o la interfaz de usuario.

Ambos preservan la historia. Al menos en 2005/2008, se mantiene el mismo elemento físico en la tabla VersionedItem sin importar con qué frecuencia o cuán drásticamente cambie el nombre y/o la ruta principal. En realidad, no hay manera de obtener un cambio de nombre "falso" (eliminar + agregar) sin mucho trabajo manual de su parte.

Sin embargo, mientras que este modelo de versionado es muy puro en un sentido teórico, tiene algunas trampas prácticas. Debido a que diferentes elementos pueden ocupar el mismo nombre en diferentes momentos, TFS necesita el nombre completo + versión para identificar de forma única cualquier entrada que se envíe. Normalmente no te das cuenta de esta restricción, pero una vez que hayas renombrado elementos en el sistema, si dices tf [doSomething] / / newname-version:oldversion entonces se confundirá y lanzará un error u operará en un elemento que puede que no hayas pretendido. Tienes que tener cuidado para pasar combinaciones válidas (newname + newversion o oldname + oldversion) para asegurarse de que los comandos se comportan de la manera que desee.

TFS 2010 cambia un poco la historia: es una rama+borrar debajo de las portadas, haciendo que el ItemId cambie. Aun así, los comandos cotidianos como Get e History son "falsos" muy bien; los clientes antiguos son aproximadamente 95% compatibles. La ventaja es que cuando tiene varios renombres en el sistema y las búsquedas de elementos basadas en rutas comienzan a ser ambiguas, como se mencionó anteriormente, el servidor simplemente aceptará el nombre que especifique y ejecutará con él. Esto mejora el rendimiento general del sistema y elimina varias trampas en las que los usuarios desconocidos a menudo caían, a costa de no ser tan flexibles y no preservar el historial con 100% de precisión (por ejemplo, cuando hay colisiones de nombres durante una fusión de dos ramas).

Volviendo al problema en cuestión...

No es tan simple como decir tf rename {/ProjectA {/ProjectB . Carpetas de nivel superior en el control de origen los árboles están reservados para el Asistente de Creación de Proyectos de Equipo; no puede ejecutar comandos tf estándar contra ellos. Lo que necesitas es un script como:

Get-TfsChildItem $/ProjectA |
    select -Skip 1 |  # skip the root dir
    foreach {
        tf rename $_.serveritem $_.serveritem.replace("$/ProjectA", "$/ProjectB")
    }

[por supuesto, puedes hacerlo a mano si no hay demasiados niños bajo Proj/ProjectA]

En cuanto a los gotchas que mencioné, voy a elaborar uno ahora mismo, ya que buscar la vieja historia parece muy importante para ti. Una vez que compruebe el cambio de nombre, tf history history/ProjectA/somefile.cs NO funcionará. Por defecto, los comandos tf asumen version = " latest."Cualquiera de estas alternativas tendrá la historia completa que desea:

  • tf history history/ProjectA/somefile.cs; 1234 donde el conjunto de cambios 1234 estaba antes del movimiento
  • tf history history/ProjectB/somefile.cs; 5678 donde el conjunto de cambios 5678 estaba después del movimiento. O podrías omitir la versión.

Una alternativa final para fines de integridad y depuración:

  • tf history history/ProjectA/somefile.cs-slotmode . Sólo vea los cambios que ocurrieron antes del movimiento; sin embargo, también verá el historial de cualquier otro elemento que pueda haber vivido en el archivo some/ProjectA/somefile.cs "slot" anterior o posterior al objeto que moviste debajo de B.

(En TFS 2010, "slot mode" es el comportamiento predeterminado; hay una opción-ItemMode para solicitar que su búsqueda se rastree a través del historial como si fuera 2008 en lugar de basarse en la ruta.)

EDITAR - no, la ramificación no es una gran alternativa. Mientras que la ramificación hace deje suficientes metadatos en el sistema para rastrear el historial completo desde y hacia ProjectB, no es terriblemente fácil de usar en 2008. Planee pasar mucho tiempo aprendiendo el comando tf merges (sin equivalente de interfaz de usuario). 2010 mejora drásticamente su capacidad para visualizar los cambios en varias ramas, pero todavía no es la experiencia unificada limpia que obtendría de un cambio de nombre.

 37
Author: Richard Berg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-07 02:47:30

La respuesta de Richard arriba está bien escrita y explica bien la situación. Sin embargo, tenía un par más práctico que agregar.

En TFS2010, el comportamiento predeterminado hace que parezca como mover un archivo hace que pierda todo el historial anterior al movimiento. El comando que mis usuarios probablemente usarán (y el utilizado, al parecer, por la GUI VS2010) es:

tf history $/ProjectB/somefile.cs

Mis usuarios tienen la intención de obtener todo el historial de somefile.cs, antes y después de la mudanza. Quieren " la historia del código que está actualmente almacenado en $ / ProjectB / somefile.cs", independientemente del nombre del archivo en cualquier momento. Tal vez otras personas lo ven diferente.

El primer gotcha es que la GUI que aparece para mí en VS2010 usando TFS2010 muestra inicialmente solo el historial desde el movimiento. El elemento menos reciente de la lista es la operación renombrar. Se puede ampliar con una pequeña flecha desplegable sutil. Debajo está la historia de la ubicación anterior. Si no sabes buscar esto, puede parecer que tu historia se ha ido.

El segundo gotcha es que si luego eliminas ProjectA (porque has terminado la migración a ProjectB, por ejemplo), el historial realmente se ha ido. Expandiendo el menú desplegable en el historial para $ / ProjectB / somefile.cs no produce la historia más antigua.

 16
Author: solublefish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-15 04:06:26

Otra opción (y creo que más fácil) es importar a Git y luego exportar a TFS usando las herramientas de línea de comandos Git-TF.

  • Instala Git-TF desde código binario, Choclatey o fuente.

  • Clonar una carpeta TFS:

git tf clone https://myAcc.visualstudio.com/mycollection $/TeamProjectA/Main --deep

  • Disociar el repositorio Git del servidor TFS eliminando la carpeta .Git/tf y el archivo .Git/git-tf.

  • Configure el nuevo repositorio de Git para conectarse a un TFS vacío carpeta.

git tf configure https://myAcc.visualstudio.com/mycollection $/TeamProjectB/Main --deep

  • No olvides el --deep

git tf pull

Debería recibir un mensaje en este punto "git-tf: este es un repositorio recién configurado. No hay nada que recuperar de tfs."

git commit -a -m "merge commit"

git tf checkin --deep

 1
Author: david004,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-30 12:38:27

Con respecto al comando original anterior: -

Get-TfsChildItem $/ProjectA |
select -Skip 1 |  # skip the root dir
foreach {
    tf rename $_.serveritem $_.serveritem.replace("$/ProjectA", "$/ProjectB")
}

Tanto el nombre de origen como el de destino deben estar rodeados de comillas en caso de que haya espacios en el nombre de ruta completo. Me resultó difícil hacer esto en $_.ServerItem al rodearlo con escaped " devuelve ese objeto hijo completo y no solo el .Cadena serverItem. O si logré obtener la cadena, obtuve retornos de carro no deseados como

"
pro proj / folder / file
"

Finalmente conseguí el comando para trabajar con lo siguiente, pero me di cuenta de que la historia todavía no se transfiere, que era todo el punto! Así que creo que este comando es el equivalente directo de simplemente usar un clic derecho del ratón en el explorador de fuentes y seleccionar renombrar (o mover).

$tfsServerString = "http://machine:8080/tfs/DefaultCollection"
$tfs = Get-TfsServer $tfsServerString
Get-TfsChildItem -server $tfs "$/Dest Project/MyTestProject" | select -Skip 1 | foreach { $sourceName = $_.serveritem; $targetName = $_.serveritem.replace("$/Dest Project/MyTestProject/", "$/Dest Project/Source/StoreControllers/dSprint/dSprint2/") ; ./tf rename `"$sourceName`" `"$targetName`" /login:myUser }

También tenga en cuenta que requiere el uso de la tecla 'para escapar"

 0
Author: Philip Beck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-02 16:40:00