TFS2010: извлечение всех наборов изменений, связанных с ветвью (полная рекурсия)
Это означает мой предыдущий вопрос о TFS 2010 и возможность создания журнала изменений.
Я раньше использовал метки для идентификации версии программы, но поскольку метки не являются фиксированными точками во времени, теперь я использую ветки.
Вот как выглядит иерархия ветвей:
![branch hierarchy]()
Как вы можете видеть, существуют два разных приложения, которые являются ветвями соединительной линии: APP_A
(приложение A) и APP_B
(приложение B). Оба они почти идентичны, но есть некоторые функциональные различия.
Вот процесс создания новой версии приложения (скажем, версия 1.3):
- Изменен
Main trunk
(добавлены новые функциональные возможности, исправлены ошибки...)
- Из измененного
Main trunk
создается новая ветвь: Main trunk 1.3
-
APP_A
ветвь может быть изменена, поэтому уникальные функции APP_A
будут работать с модификацией версии 1.3
ветвь -
APP_B
может быть изменена, поэтому уникальные функции APP_B
будут работать с модификацией v1.3
-
Main trunk 1.3
объединяется в APP_A
и APP_B
, поэтому приложения APP_A
и APP_B
получают модификации Main trunk
- От измененной ветки
APP_A
создается новая ветвь: APP_A_1.3
- От измененной ветки
APP_B
создается новая ветка: APP_B_1.3
Моя цель - создать журнал изменений между APP_A_1.3
и APP_A_1.2
.
С помощью списка изменений я имею в виду список WorkItems. Каждый набор изменений, который зарегистрирован, связан с одним или несколькими WorkItem (например, элементом Bug). Я хотел бы получить список всех рабочих элементов, связанных с набором изменений, который повлиял на APP_A_1.3
: эти изменения могут появиться из Main trunk
(шаг 1 выше), APP_A branch
(шаг 3 выше) или даже сама ветвь APP_A_1.3
(если исправления включены после создания ветки).
Чтобы получить этот список рабочих элементов, я попытался получить список всех наборов изменений, привязанных к APP_A_1.2
("связанный" = код, который был отмечен в наборе изменений теперь находится в ветке APP_A_1.2
) и список всех наборов изменений, которые "связаны" с APP_A_1.3
.
Затем я смогу узнать, какие набор изменений "привязан" к APP_A_1.3
, а не "привязан" к APP_A_1.2
. Из этого подмножества наборов изменений я получу все связанные с ним WorkItems и, следовательно, свой журнал изменений.
Здесь моя проблема: как я могу получить список ВСЕ наборов изменений, которые "связаны" с указанной ветвью? Я использую API TFS 2010 для кода С#.
Ввод моей программы (которая будет извлекать все команды изменений для указанной ветки) будет именем ветки (скажем APP_A_1.2
), а результатом будет список следующих наборов изменений:
- набор изменений, примененный к
APP_A_1.2
самой ветке
- добавлены изменения, примененные к ветке
APP_A
до APP_A_1.2
- набор изменений, примененный к ветке
Main trunk 1.2
, прежде чем он будет объединен с APP_A
- добавлены изменения, примененные к ветке
Main trunk
до Main trunk 1.2
Я написал следующие фрагменты кода для получения всех этих наборов изменений:
// 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();
Даже если указан RecursionType.Full
, указанный выше код только возвращает внесенные изменения в ветвь APP_A_1.2
. Это идентично команде "История" в представлении "Проводник исходного кода" в Visual Studio.
Затем я попробовал следующий фрагмент кода:
// 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();
Это возвращает изменения, которые были отмечены на ветке APP_A_1.2
, и те, которые были помечены в ветке APP_A
до APP_A_1.2
. Гораздо лучше, но недостаточно. Я не могу найти способ сделать рекурсию работой с ветвями, которые "выше" APP_A
(Main trunk
в моем случае)...
У кого-нибудь есть идея?
Кроме того, приветствуются любые лучшие идеи для получения изменений между двумя ветками...
спасибо.
Ответы
Ответ 1
Наконец я придумал простое решение. Я не совсем этому доволен, поскольку он на самом деле выглядит как алгоритм грубой силы, но по крайней мере он работает.
Что я делаю:
1) Получите список каждого набора изменений, который применяется к самому корню моих ветвей TFS (т.е. "родительский путь" Main Trunk
):
var allChangesets = vcs.QueryHistory(
"MySourcePath",
VersionSpec.Latest,
0,
RecursionType.Full,
null,
firstPossibleChangeset,
VersionSpec.Latest,
int.MaxValue,
true,
false).OfType<Changeset>().ToList();
2) Для каждого загруженного набора изменений я вызываю TrackMerges
, чтобы увидеть, влияет ли набор изменений каким-то образом моими ветвями. TrackMerges
может сказать мне, если указанный набор изменений применяется к ветвям, которые я указываю как параметр функции (он вернет идентификатор целевого набора изменений в этих ветвях). Если набор изменений применяется к ветки назначения (в моем случае APP_A_1.3
), а не в ветки источника (APP_A_1.2
), значит, это означает что-то новое в моей ветке 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) Теперь очень просто получить мой журнал изменений (список рабочих элементов) из списка "новых наборов изменений":
// 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));
}
}
}
Я не думаю, что это лучший подход, но он отлично работает и остается простым. Кроме того, мне не нужно было делать что-либо (имя/иерархия), так что это не так уж плохо IMO. Надеюсь, это поможет кому-то.
Ответ 2
сначала позвольте мне сначала задать один вопрос. В верхней части сообщения вы пишете:
"Моя цель - создать журнал изменений между APP_A_1.3 и APP_A_1.2."
но затем, когда вы пишете, какие изменения конкретно вы ищете, вы перечислите:
изменения, применяемые к самой ветке APP_A_1.2
набор изменений, примененный к ветки APP_A, до создания APP_A_1.2
изменений, примененных к ветке Main trunk 1.2, прежде чем он будет объединен с APP_A
изменений, внесенных в главную ветвь магистрали, до того, как была создана основная магистраль 1.2.
Это недействительный список, потому что он предоставит вам все изменения, внесенные в APP_A_1.3, APP_A_1.2, 1.1 и т.д. в начало репозитория.
Я не могу проверить свой подход прямо сейчас, но это то, что я сделал бы:
- QueryHistory, чтобы все изменения были проверены непосредственно в ветке 1.3
- используйте QueryMergesExtended, чтобы следовать за слияниями в эту ветку. QueryMergesExtended (http://msdn.microsoft.com/en-us/library/ff736485.aspx) был добавлен в TFS 2010 специально для того, чтобы быть намного более производительным и надежным, чем QueryMerges и QueryMergesWithDetails, чтобы поддерживать инструменты визуализации отрасли
- afaik вам не нужно указывать опцию FollowRenames в QueryMergesExtended, потому что вы запрашиваете слияние с корнем ветки
- когда вы получаете список изменений источника (из APP_A), вам нужно проверить каждый набор изменений, чтобы увидеть, что он содержит изменения слияния. Если это так, вам нужно запросить слияния в app_a для этих наборов изменений. Сделайте это рекурсивно, пока не пройдете целую иерархию ветвей.
В боковой теме вы можете посмотреть позже в QueryMergeRelationships (http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.versioncontrolserver.querymergerelationships.aspx), который дает вам список объектов ветвей, введенный в tfs 2010 ( это происходит, когда в Source Control Explorer вы выбираете папку и нажимаете "Преобразовать в ветвь" ). Однако, если вы можете обнаружить свою ветку по-разному (с жестким кодом), чем она не нужна.
Надеюсь, это поможет!
Ответ 3
Да, сам работаю над этой проблемой. Я нашел проект codeplex, который решает его, когда вы все равно различаете ярлыки.
Посмотрите, поможет ли это: http://tfslabeldiff.codeplex.com/SourceControl/changeset/view/7075#158224
Я был очень удивлен, как трудно это было найти, но документации для TFS в лучшем случае недостаточно. Казалось, что это должно быть очевидно!