Obteniendo la list de files comprometidos en un push para TFS Git Repository

¿Cómo puedo iterar a través de todos los files en un commit / push a un repository de Git en TFS? Estoy escribiendo un complemento del lado del server y necesito acceder a la list de files comprometidos durante un empujón. Tengo el complemento funcionando y recibiendo el post de confirmación, pero también necesito la list de files.

Además, ¿hay alguna manera de modificar el post de confirmación una vez que se envía al server? Queremos indicar si la ID (# 12345) es una PBI, Tarea o Error

Gracias

Scott

¿Cómo puedo iterar a través de todos los files en un commit / push a un repository de Git en TFS? Estoy escribiendo un complemento del lado del server y necesito acceder a la list de files comprometidos durante un empujón. Tengo el complemento funcionando y recibiendo el post de confirmación, pero también necesito la list de files.

Un commit es una instantánea completa de un tree de trabajo, por lo que cada commit tiene todos los files en él. Estoy seguro de que no es lo que quieres, pero es una key para entender cómo get lo que quieres, y tal vez lo más importante, cómo averiguar lo que quieres para compromisos de fusión en particular.

Por ejemplo, supongamos que en el server, en un gancho, obtienes una línea de input antes o después de recibir, o los arguments de un gancho de actualización, diciendo:

  • Tengo la intención de cambiar los refs/heads/foo reference refs/heads/foo .
  • El valor anterior era / es c13f98a...
  • El nuevo valor es / will-be 0b4a13e...

(Así es como la información llega a un anzuelo. En un anzuelo previo o posterior a la recepción, lee una serie de líneas de la input estándar y cada línea tiene el hash antiguo y nuevo y el nombre de reference, en ese order. un gancho de actualización, los tres arguments del guión proporcionan el nombre de reference y los hash antiguos y nuevos, en ese order. Tanto en los ganchos de pre-recepción como de actualización, la actualización no ha sucedido todavía y su secuencia de commands puede prohibirlo, mientras que en el gancho post-recepción, la reference ya se ha actualizado y simplemente se le da una segunda oportunidad para inspeccionar el resultado).

Como máximo, uno de los dos hashes puede ser el hash nulo absoluto. En este caso, la reference (twig, label, notas o lo que sea) se está creando o eliminando. De lo contrario, ambos hash son válidos y la reference se está moviendo.

Si la reference es un nombre de twig, comienza con refs/heads/ ; el rest del nombre, que posiblemente incluya más barras, es el nombre de la sucursal; luego, la actualización puede hacer que algunos compromisos sean alcanzables y / o hacer que otras confirmaciones sean inalcanzables desde el nuevo hash, es decir, poner algunas confirmaciones en y / o eliminar algunas se compromete desde esa twig. (Lo mismo es cierto para todas las demás actualizaciones, incluidas las tags, aunque normalmente las actualizaciones de tags simplemente se rechazan por completo, y normalmente no intentamos atravesar el DAG de confirmación desde una label).

Tenga en count que aunque algunas confirmaciones se vuelven alcanzables o inalcanzables a través de este nombre, no hay garantía de que esas confirmaciones fueran totalmente inalcanzables antes, o que ahora sean totalmente inalcanzables. Por ejemplo, supongamos que el gráfico de confirmación existente, antes de invocar su gancho, incluye este fragment:

 ... - E - F - H <-- refs/heads/foo \ / G <-- refs/heads/bar 

donde E , F y H se comprometen "en la twig foo " siendo H una confluencia de fusión, y E y G se comprometen "en la bar ramificación". Luego obtienes una request de actualización que dice "move bar to point to commit H " (para que foo y bar apunten al mismo commit). Merge commit H no es nuevo, simplemente se vuelve accesible a través de la bar ramificación : ya se podía acceder a través de branch foo . Un empuje de fuerza posterior que restablece la bar para volver al punto G (si el empuje original fue un error) hace que H pueda alcanzar desde la bar , pero sigue siendo accesible desde foo .

Por lo tanto, dependiendo de lo que usted desee, generalmente comenzará por get y trabajar a través de una list de identificadores de compromiso que se han vuelto alcanzables o inalcanzables, usando git rev-list , que está diseñado para hacer justamente eso:

 for i in $(git rev-list $old..$new); ... done # newly reachable for i in $(git rev-list $new..$old); ... done # newly unreachable 

(Puede get estas lists por adelantado, y quizás contarlas). En un enlace de pre-recepción, también puede verificar si alguna de las otras actualizaciones de reference hará que las confirmaciones de nuevo scope sean accesibles (a través de algún otro nombre), y en cualquiera un enlace de pre-recepción o de actualización, puede consultar las references actuales que aún no se han actualizado (usando git for-each-ref por ejemplo, o git rev-list --all , o lo que sea que necesite) para ver si está recién compromisos alcanzables ya son alcanzables por algún otro nombre. (En un enganche posterior a la recepción, podría hacer lo mismo, pero es más difícil ya que las references ya están actualizadas, y tendría que calcular mediante progtwigción sus valores previos a la actualización, incluida la simulación de restaurar cualquier reference eliminada).

Cada commit $i en cada list puede ser una confirmación ordinaria, sin fusión, que tiene un padre soltero; o puede ser un compromiso de fusión, que por definición tiene dos o más padres.

Para las confirmaciones ordinarias, sin fusión, get el set de cambios en comparación con su padre es fácil: simplemente ejecute git diff en los dos hashes (usando --name-only o --name-status para get el tipo de información que soy seguro que estás buscando).

Sin embargo, para las asignaciones de fusión, es más difícil, porque una fusión tiene dos o más padres. xyzzy decidir qué significa si, por ejemplo, el file xyzzy es exactamente el mismo que en uno de los padres de la fusión, pero diferente del otro, y si le importa de qué padre (s) difiere. Las posibilidades son bastante buenas de que lo que más te importa es cómo se comparan estos files con el primer padre (lo que significa que puedes usar el mismo código que para un no combinar, usando ${i}^ para get el primer padre de commit $i haciendo el git diff ), pero también es posible que necesite algo diferente o algo más aquí.

(Tenga en count que no sé nada del software que ya tiene, pero puedo decir que muchos escritores de ganchos obtienen muchos de estos detalles erróneos, porque no han considerado (o ni siquiera están conscientes de) la posibilidad de que una fuerza … push puede agregar 5 commits mientras elimina 3, y / o las llamadas fusiones "malvadas" pueden queuerse en cambios que no aparecen en ninguno de los padres (las diferencias combinadas de git están diseñadas para encontrar tales cambios).

Además, ¿hay alguna manera de modificar el post de confirmación una vez que se envía al server? Queremos indicar si la ID (# 12345) es una PBI, Tarea o Error

No. Es imposible modificar nada acerca de una confirmación, porque la identificación hash de la confirmación ( 0b4a13e... ) es una sum de comprobación criptográfica del contenido de la confirmación. Cambie cualquier cosa, incluso un solo bit, y la sum de verificación cambia de forma espectacular e impnetworkingecible (bueno, "pnetworkingecible" haciendo la sum de comprobación del nuevo contenido, por supuesto). Esto es precisamente lo que hace que las rebases iniciales sean difíciles para los usuarios intermedios: no cambia las confirmaciones, las copy a las nuevas asignaciones y les dice a todos "por favor, olviden las antiguas y utilicen las nuevas".

Editar : Olvidé mencionar que este tipo de cosas (agregar una nota a una confirmación) es para lo git notes están diseñadas las git notes . Funcionan no modificando realmente el compromiso en sí, sino más bien agregando un tipo especial de bag-on-side que el git log consulta automáticamente. El mecanismo de implementación es bastante complicado, pero se networkinguce al hecho de que los commits se identifican de manera única por sus hashes ( 0b4a13e... , nuevamente), por lo que git log puede consultar la refs/heads/notes para ver si hay más información para 0b4a13e... Si es así, git log agregará esa información al logging, a less que le diga que no ( --no-notes ) o lo apunte a una reference diferente ( --notes=refs/notes/foo , por ejemplo).

¿Cómo puedo iterar a través de todos los files en un commit / push a un repository de Git en TFS? Estoy escribiendo un complemento del lado del server y necesito acceder a la list de files comprometidos durante un empujón. Tengo el complemento funcionando y recibiendo el post de confirmación, pero también necesito la list de files.

Parte de la interfaz ISubscriber es el siguiente método:

 public EventNotificationStatus ProcessEvent(IVssRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) 

Este es el punto de input de tu Plugin. El parámetro notificationEventArgs aquí es uno de los types a los que se suscribió. Si se suscribe al tipo Microsoft.TeamFoundation.Git.Server.PushNotification , puede get los nombres de file usando algo como lo siguiente:

 var repositoryService = requestContext.GetService<ITeamFoundationGitRepositoryService>(); var repository = repositoryService.FindRepositoryById(requestContext, (notificationEventArgs as PushNotification).RepositoryId); var diffEntries = new List<TfsGitDiffEntry>(); var commits = (notificationEventArgs as PushNotification).IncludedCommits; foreach(var item in commits) { var gitCommit = repository?.LookupObject(item)?.ResolveToCommit(); var manifest = gitCommit.GetManifest(true); diffEntries.AddRange(manifest.Where(x.NewObjectType == GitObjectType.Blob)); } var files = diffEntries.Select(d => d.RelativePath).Distinct(); 

Los objects TfsGitDiffEntry también se pueden usar para determinar una variedad de cosas, consulte la reference de class para get más información: https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(Microsoft.TeamFoundation .Git.Server.TfsGitDiffEntry); k (TargetFrameworkMoniker-.NETFramework, Versión% 3Dv4.6.1); k (DevLang-csharp) & rd = true

Obtener el contenido del file desde un TfsGitDiffEntry es tan simple como:

 var oldFileContentsStream = repository.LookupObject<TfsGitBlob>(diffEntry.OldObjectId.Value).GetContent(); 

o

 var newFileContentsStream = repository.LookupObject<TfsGitBlob>(diffEntry.NewObjectId.Value).GetContent(); 

Además, ¿hay alguna manera de modificar el post de confirmación una vez que se envía al server? Queremos indicar si la ID (# 12345) es una PBI, Tarea o Error

En mi experimentación, no he podido encontrar una manera de hacer esto.