2012-02-14 1 views
17

Ceci suit my previous question à propos de TFS 2010 et la possibilité de créer un journal des modifications. J'ai précédemment utilisé des étiquettes pour identifier une version du programme, mais comme les étiquettes ne sont pas des points fixes dans le temps, maintenant j'utilise des branches.TFS2010: Récupérer tous les changesets associés à une branche (récursivité complète)

Voilà comment la hiérarchie de la branche ressemble à:

branch hierarchy

Comme vous pouvez le voir, il y a deux applications différentes qui sont des branches du tronc: APP_A (application A) et APP_B (application B). Les deux sont presque identiques, mais il y a quelques différences fonctionnelles.

Voici le processus de création d'une nouvelle version de l'application (par exemple la version 1.3):

  1. Le Main trunk est modifié (de nouvelles fonctionnalités sont ajoutées, des corrections de bugs ...)
  2. De modifié Main trunk, une nouvelle branche est créée: Main trunk 1.3
  3. branche APP_A peut être modifié, des fonctionnalités uniques afin de APP_A travaillera avec la modification de v1.3
  4. APP_B branche peut être modifiée, de sorte que des fonctionnalités uniques de APP_B travailleront avec la modification de v1.3
  5. Main trunk 1.3 est fusionné à APP_A et APP_B, afin que les deux APP_A et APP_B applications reçoivent les modifications du Main trunk
  6. De la modification APP_A branche , une nouvelle branche est créée: APP_A_1.3
  7. de la branche APP_B modifiée, une nouvelle branche est créée: APP_B_1.3

Mon but est de pouvoir produire un changelog entre APP_A_1.3 et APP_A_1.2.

Par changelog, je veux dire une liste de WorkItems. Chaque ensemble de modifications qui est archivé est associé à un ou plusieurs éléments de travail (par exemple, un élément de bogue). Je voudrais pouvoir obtenir la liste de tous les workitems qui ont été liés à un changeset qui a affecté : ces changesets pourraient provenir du Main trunk (étape 1 ci-dessus), du APP_A branch (étape 3 ci-dessus) ou même du APP_A_1.3 branche lui-même (si les correctifs sont archivés après la création de la branche).

Pour obtenir cette liste des éléments de travail, j'ai essayé de la liste de tous les changesets qui sont « liés » à APP_A_1.2 (« lié » = le code qui a été vérifié dans la changeset est maintenant sur la branche APP_A_1.2) et la liste de tous les changesets qui sont "liés" à APP_A_1.3. Puis, je serai en mesure de savoir quels changesets sont "liés" à APP_A_1.3 et non "liés" à APP_A_1.2.A partir de ce sous-ensemble de changesets, j'obtiendra tous les WorkItems associés et ainsi mon changelog.

Voici mon problème: comment puis-je obtenir la liste des TOUS les changements qui sont "liés" à une branche spécifiée? J'utilise l'API TFS 2010 pour le code C#.

L'entrée de mon programme (qui récupérerait tous les changesets pour une branche déterminée) serait le nom de la branche (par exemple APP_A_1.2), et la sortie serait la liste des changesets suivants:

  • changesets appliquée sur APP_A_1.2 branche elle-même
  • changesets appliqué sur la branche APP_A avant APP_A_1.2 a été créé
  • changesets appliquée sur la branche Main trunk 1.2 avant qu'il ait été fusionné pour APP_A
  • changesets appliquées sur Main trunk branche avant Main trunk 1.2 a été créé

J'ai écrit les morceaux de code ci-dessous pour obtenir tous les changesets:

// Gets the list of all changesets ID from APP_A_1.2 branch 
var branch1ChangeSets = myVersionControlServer.QueryHistory(
    "$/PATH/APP_A_1.2/", 
    VersionSpec.Latest, 
    0, 
    RecursionType.Full, 
    null, 
    null, 
    null, 
    int.MaxValue, 
    false, 
    false).OfType<Changeset>().Select(z => z.ChangesetId).ToList(); 

Même si RecursionType.Full est spécifié, le code ci-dessus seulement renvoie les changesets qui ont été archivés sur la branche APP_A_1.2 elle-même. Ceci est identique à la commande "Historique" dans la vue Explorateur de code source dans Visual Studio.

Alors j'ai essayé le morceau de code suivant:

// Gets the list of all changesets ID from APP_A_1.2 branch 
var branch1MergedChangeSets = myVersionControlServer.QueryMerges(
    null, 
    null, 
    "$/PATH/APP_A_1.2/", 
    VersionSpec.Latest, 
    null, 
    null, 
    RecursionType.Full).Select(z => z.SourceVersion).ToList(); 

Ce retour changesets qui ont été vérifiés dans le APP_A_1.2 branche + ceux qui ont été cheked-est dans la branche APP_A avant APP_A_1.2 a été créé. Beaucoup mieux, mais pas suffisant. Je ne peux pas trouver un moyen de faire fonctionner la récursivité avec des branches qui sont "au-dessus" APP_A (Main trunk dans mon cas) ...

Quelqu'un a une idée?

De plus, toutes les meilleures idées pour obtenir le changelog entre deux branches sont les bienvenues ... Thx.

+1

Bonne question! ATM vous êtes bloqué avec comment récupérer avec précision les Changesets. Une fois que vous les aurez, considérez cet article fantastique par B.Hodges, qui vous aidera à corréler une liste de Changesets avec une liste d'éléments de travail: http://blogs.msdn.com/b/buckh/archive/2012 /02/01/listing-the-work-items-associated-with-changesets-for-a-path.aspx – pantelif

Répondre

2

J'ai finalement trouvé une solution simple. Je ne suis pas totalement content car cela ressemble à un algorithme de force brute, mais au moins cela fonctionne.

Ce que je fais est:

1) Inscrivez-vous la liste des chaque changeset qui est appliqué sur la racine même de mes branches TFS (ie le "chemin parent" de Main Trunk):

var allChangesets = vcs.QueryHistory(
    "MySourcePath", 
    VersionSpec.Latest, 
    0, 
    RecursionType.Full, 
    null, 
    firstPossibleChangeset, 
    VersionSpec.Latest, 
    int.MaxValue, 
    true, 
    false).OfType<Changeset>().ToList(); 

2) Pour chaque ensemble de modifications récupérées, j'appelle le TrackMerges pour voir si le changeset affecte d'une manière ou d'une autre mes branches. TrackMerges est capable de me dire si un changeset spécifié est appliqué sur les branches que je spécifie comme paramètre de la fonction (cela retournera l'ID de changeset cible sur ces branches). Si un ensemble de modifications est appliqué sur la branche de destination (dans mon cas APP_A_1.3) et non dans la branche source (APP_A_1.2), cela signifie que c'est définitivement quelque chose de nouveau sur ma branche APP_A_1.3.

List<int> newChangesets = new List<int>(); 
foreach (var z in allChangesets.Where(y => y.ChangesetId > firstPossibleChangesetId)) 
{ 
    var zz = vcs.TrackMerges(
     new int[] { z.ChangesetId }, 
     new ItemIdentifier("THE TRUNK PATH"), // The root of all branches 
     new ItemIdentifier[] { new ItemIdentifier(fromBranchPath), new ItemIdentifier(toBranchPath) }, 
     null); 

    var targetInFromBranch = zz.Where(t => t.TargetItem.Item == fromBranchPath).FirstOrDefault(); 
    var targetInToBranch = zz.Where(t => t.TargetItem.Item == toBranchPath).FirstOrDefault(); 

    if (targetInToBranch != null && targetInFromBranch == null) 
    { 
     // Then the changeset is only applied on the ToBranch 
     newChangesets.Add(z.ChangesetId); 
    } 
} 

3) Maintenant, il est très simple d'obtenir mon changelog (la liste des éléments de travail) de la liste des « nouveaux changesets »:

// Now, gets associated work items! 
Dictionary<int, WorkItem> dico = new Dictionary<int, WorkItem>(); 
foreach (int changesetId in newChangesets) 
{ 
    foreach (WorkItem zz in vcs.GetChangeset(changesetId).WorkItems) 
    { 
     this.AddWorkItemToDicRecursive(wis, dico, zz); 
    } 
} 

private void AddWorkItemToDicRecursive(WorkItemStore wis, Dictionary<int, WorkItem> dico, WorkItem workItem) 
{ 
    if (!dico.ContainsKey(workItem.Id)) 
    { 
     dico.Add(workItem.Id, workItem); 

     foreach (WorkItemLink associatedItem in workItem.WorkItemLinks) 
     { 
      this.AddWorkItemToDicRecursive(wis, dico, wis.GetWorkItem(associatedItem.TargetId)); 
     } 
    } 
} 

Je ne pense pas que c'est la meilleure approche possible, mais ça marche bien et reste simple. De plus, je n'ai pas eu à coder en dur (noms de branches/hiérarchie) donc ce n'est pas trop mauvais IMO. J'espère que ça va aider quelqu'un.

3

d'abord laissez-moi d'abord poser une question. En haut du message, vous écrivez: "Mon objectif est de pouvoir produire un journal des modifications entre APP_A_1.3 et APP_A_1.2."

mais quand vous écrivez les changements que vous êtes à la recherche spécifiquement pour vous la liste: changesets appliquée sur la branche branche APP_A_1.2 se de changesets appliquée sur la branche APP_A avant APP_A_1.2 a été créé changesets appliqué sur le tronc principal 1.2 avant d' a été fusionné à APP_A changesets appliqués sur la branche de ligne principale avant la création de la ligne principale 1.2

Cette liste n'est pas valide car elle vous donnera toutes les modifications ayant contribué à APP_A_1.3, APP_A_1.2, 1.1, etc. au début du référentiel.

Je ne suis pas en mesure de tester mon approche pour le moment, mais voici ce que je ferais: - QueryHistory pour que toutes les modifications soient enregistrées directement dans la branche 1.3 - utilisez QueryMergesExtended pour suivre les fusions dans cette branche. QueryMergesExtended (http://msdn.microsoft.com/en-us/library/ff736485.aspx) a été ajouté dans TFS 2010 spécifiquement pour être beaucoup plus performant et robuste que QueryMerges et QueryMergesWithDetails, afin de prendre en charge les outils de visualisation de branche - afaik vous n'avez pas besoin de spécifier l'option FollowRenames dans QueryMergesExtended car vous interrogez les fusions à la racine de la branche - lorsque vous obtenez la liste des changements de source (de APP_A), vous devez vérifier chaque modification pour voir qu'elle contient des modifications de fusion. Si c'est le cas, vous devez interroger les fusions sur app_a pour ces changesets. Faites-le de manière récursive jusqu'à ce que vous marchiez toute la hiérarchie des branches. Sur le côté, vous pouvez regarder plus tard le QueryMergeRelationships (http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.versioncontrolserver.querymergerelationships.aspx) qui vous donne la liste des objets de branche introduite dans tfs 2010 (c'est ce qui se passe lorsque dans Source Control Explorer vous sélectionnez le dossier et cliquez sur Convertir en branche). Cependant si vous pouvez découvrir votre branche de manière différente (les coder en dur) que ce n'est pas nécessaire.

Espérons que cela aide!

+0

Salut, Je ne comprends pas pourquoi la liste que j'ai mentionnée me donnerait les changesets appliqués sur 'APP_A_1.3 '. Je suis OK avec "APP_A_1.2" et "APP_A_1".1' (c'est ce que j'attends), mais je ne vois pas comment un ensemble de modifications appliqué uniquement sur 'APP_A_1.3' apparaîtrait dans l'une des listes. En outre, j'ai testé 'QueryMergesExtended' mais il ne retourne pas récursivement tous les changesets (par exemple, appliqué sur' APP_A_1.3', il retourne des changesets de 'APP_A' mais pas de' Main Trunk'). – ken2k

+0

Je peux en effet utiliser 'QueryMergeRelationships' pour découvrir mes branches puis appeler plusieurs fois' QueryMergesExtended', cela devrait fonctionner. J'ai aussi trouvé un moyen avec 'TrackMerges', je l'afficherai bientôt comme une autre réponse. Je remets en cause votre réponse parce que c'est utile, merci. – ken2k

1

Oui, je travaille aussi sur ce problème. J'ai trouvé un projet de codéplex qui le résout, quand vous changez d'étiquettes, de toute façon.

Voir si cela aide: http://tfslabeldiff.codeplex.com/SourceControl/changeset/view/7075#158224

J'ai été assez surpris de voir comment cela était de trouver difficile, mais la documentation de TFS manque au mieux. Il semblait que cela devrait être évident!

+0

Salut Sharon, je pense que ce que vous proposez ne traverse pas l'historique des branches, en d'autres termes, il ne récupérera pas récursivement les changesets entre les différentes branches. – pantelif

Questions connexes