TFS 不一定基于分支对象构建合并候选对象,以实现向后兼容性(分支对象是 TFS 2010 中的新对象)并支持无基础合并(一旦您在两个路径之间执行无基础合并,这些将与合并一起存储未来合并的关系。)
我建议在此处使用自定义签入策略,强制合并从 Dev -> Test 或 Test -> Dev 开始,并且不要跳过中间级别。这也允许您将 Dev 保留为分支对象,因此您仍然可以获得分支可视化等所有不错的功能。
我可以提供一个非常粗略、非常伪代码的示例来说明我的想法。 (这很粗糙,因为我很懒,而且因为我把时间花在 Java SDK 而不是 .NET SDK 上,而且我意识到大多数人都想要一个 .NET 签入策略。但主要是因为我很懒。)
/*
* Create a dictionary of merge targets to allowable merge sources.
* For an item in this list, the allowable merge sources are a whitelist.
*/
private readonly Dictionary<String, List<String>> restrictedMergeTargets =
new Dictionary<String, List<String>>();
public static MergeWhitelistPolicy
{
/* Only allowed merges to $/Main from $/Test. */
List<String> mainWhitelist = new List<String>();
mainWhitelist.add("$/Test");
allowedMerges.put("$/Main", mainWhitelist);
/* Only allow merges to $/Test from $/Dev. */
List<String> testWhitelist = new List<String>();
testWhitelist.add("$/Dev");
allowedMerges.put("$/Test", testWhitelist);
}
public PolicyFailure[] evaluate(PolicyContext context)
{
PendingChange[] pendingChanges = GetPendingCheckin().GetCheckedPendingChanges();
foreach(PendingChange change : pendingChanges)
{
if(! change.IsMerge())
{
continue;
}
foreach(KeyValuePair<String, List<String>> restrictedTarget : restrictedMergeTargets)
{
if(VersionControlPath.IsChild(restrictedTarget.GetKey(), change.GetServerItem())
{
/* Whitelisted merge path - investigate. */
foreach(String allowedSource : restrictedTarget.GetValue())
{
foreach(MergeSource mergeSource : change.GetMergeSources())
{
if(! VersionControlPath.IsChild(allowedSource, mergeSource.GetServerItem()))
{
return new PolicyFailure("Merge from " +
mergeSource.GetServerItem() + " to " +
change.GetServerItem() + " is disallowed.");
}
}
}
}
}
}
return null;
}
当然,这有几个问题。您当然不希望将可接受的合并关系列表硬编码到策略中 - 您可以将其外部化到配置文件中,或者您可以在服务器上查询合并关系并缓存它们,如果您有特定的规则,例如只有直接后代可以合并。 (缓存这一点很重要,因为签入策略评估运行频繁并且预计会很快。它甚至可能偶尔在 UI 线程上运行(尽管我对此表示怀疑),因此您的里程可能会有所不同。)
另外,我的路径测试代码非常草率,主要是为了在我的评论中节省一些空间。 (还有,前面提到的我的懒惰。)
我希望这是一个好的开始。