TFS2010: получить все наборы изменений, связанные с веткой (полная рекурсия)
таким образом мой предыдущий вопрос о TFS 2010 и возможности создания журнала изменений.
ранее я использовал метки для идентификации версии программы, но поскольку метки не являются фиксированными точками во времени, теперь я использую ветви.
вот как выглядит иерархия ветвей:
как вы можете видеть, есть два разных приложения, которые являются ветвями ствола: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
.
под changelog я имею в виду список WorkItems. каждый набор изменений, который регистрируется, связан с одним или несколькими WorkItem (например, элемент ошибки). я хотел бы иметь возможность получить список всех workitems, которые были связаны с набором изменений, который повлиял APP_A_1.3
: эти наборы изменений могут исходить от Main trunk
(Шаг 1 выше), APP_A branch
(Шаг 3 выше) или даже APP_A_1.3
сама ветвь (если исправления регистрируются после создания ветви).
чтобы получить этот список workitems, я попытался получить список всех наборов изменений, которые "связаны" с APP_A_1.2
( "linked" = код, который был зарегистрирован в наборе изменений, теперь находится в ветке APP_A_1.2
) и список всех изменений, которые "привязаны" к APP_A_1.3
.
тогда я смогу узнать, какой наборы изменений "связаны" с APP_A_1.3
и не "привязана" к APP_A_1.2
. Из этого подмножества наборов изменений я получу все связанные WorkItems и, следовательно, мой журнал изменений.
вот моя проблема: как я мог получить список все наборы изменений, которые "связаны" с указанной веткой? Я использую API TFS 2010 для кода C#.
вход моей программы (которая будет извлекать все наборы изменений для указанной ветви) будет именем ветви (скажем 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
ветка + те, которые были checked - in на APP_A
филиала перед APP_A_1.2
был создан. Намного лучше, но недостаточно. Я не могу найти способ заставить рекурсию работать с ветвями, которые находятся "выше"APP_A
(Main trunk
в моем случае)...
у кого-нибудь есть идея?
кроме того, любые лучшие идеи для получения журнала изменений между двумя ветвями приветствуются... Тнх.
3 ответов
сначала позвольте мне сначала задать один вопрос. В верхней части сообщения Вы пишете: "Моя цель-создать журнал изменений между APP_A_1.3 и APP_A_1.2."
но тогда, когда вы пишете, какие изменения конкретно вы ищете для вас список: наборы изменений, применяемые в APP_A_1.2 сама ветвь наборы изменений, применяемые в ветви APP_A перед APP_A_1.Создано 2 наборы изменений, примененные к основной ветви магистрали 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 (это то, что происходит, когда в Проводнике управления версиями вы выбираете папку и нажимаете преобразовать в ветвь). Однако, если вы можете открыть свою ветвь по-другому (жестко), чем это не нужно.
надеюсь, что это помогает!
я, наконец, придумал простое решение. Я не совсем доволен этим, поскольку на самом деле это выглядит как алгоритм грубой силы, но, по крайней мере, он работает.
что я делаю:
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) Теперь очень просто получить мой журнал изменений (список workitems) из списка " new 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));
}
}
}
Я не думаю, что это лучший подход, но он работает отлично и остается простой. Кроме того, мне не нужно было ничего жестко кодировать (имена ветвей/иерархия), поэтому это не так уж плохо IMO. Надеюсь, это кому-то поможет.
Да, я тоже работаю над этой проблемой. Я нашел проект codeplex, который решает его, когда вы различаете ярлыки, во всяком случае.
посмотрите, поможет ли это:http://tfslabeldiff.codeplex.com/SourceControl/changeset/view/7075#158224
Я был очень удивлен, насколько сложно это было найти, но документация для TFS в лучшем случае отсутствует. Казалось, это должно быть очевидно!