private static bool AcceptHeads(ClientStateInfo clientInfo, Area ws, out string errorData) { SharedNetwork.ImportBranches(clientInfo.SharedInfo); Dictionary<Guid, Head> temporaryHeads = new Dictionary<Guid, Head>(); Dictionary<Guid, Guid> pendingMerges = new Dictionary<Guid, Guid>(); Dictionary<Guid, HashSet<Guid>> headAncestry = new Dictionary<Guid, HashSet<Guid>>(); foreach (var x in clientInfo.SharedInfo.PushedVersions) { Branch branch = ws.GetBranch(x.Version.Branch); Head head; if (!temporaryHeads.TryGetValue(branch.ID, out head)) { var heads = ws.GetBranchHeads(branch); if (heads.Count == 0) head = new Head() { Branch = branch.ID, Version = x.Version.ID }; else if (heads.Count == 1) head = heads[0]; else { // ??? Printer.PrintError("OMG 1"); errorData = string.Format("Multiple ({0}) heads for branch {1}", heads.Count, branch.ID); return false; } temporaryHeads[branch.ID] = head; } if (head.Version != x.Version.ID) { HashSet<Guid> headAncestors = null; if (!headAncestry.TryGetValue(head.Version, out headAncestors)) { headAncestors = SharedNetwork.GetAncestry(head.Version, clientInfo.SharedInfo); headAncestry[head.Version] = headAncestors; } if (headAncestors.Contains(x.Version.ID)) { // all best } else if (SharedNetwork.IsAncestor(head.Version, x.Version.ID, clientInfo.SharedInfo)) { headAncestry.Remove(head.Version); pendingMerges[branch.ID] = Guid.Empty; head.Version = x.Version.ID; } else if (!SharedNetwork.IsAncestor(x.Version.ID, head.Version, clientInfo.SharedInfo)) { headAncestry.Remove(head.Version); pendingMerges[branch.ID] = head.Version; head.Version = x.Version.ID; } } } foreach (var x in pendingMerges) { if (x.Value == Guid.Empty) { Printer.PrintDiagnostics("Uncontested head update for branch \"{0}\".", ws.GetBranch(x.Key).Name); Printer.PrintDiagnostics(" - Head updated to {0}", temporaryHeads[x.Key].Version); continue; } Branch branch = ws.GetBranch(x.Key); VersionInfo result; string error; result = ws.MergeRemote(ws.GetLocalOrRemoteVersion(x.Value, clientInfo.SharedInfo), temporaryHeads[x.Key].Version, clientInfo.SharedInfo, out error); if (result == null) { // safe merge? Printer.PrintError("OMG 2"); errorData = string.Format("Can't automatically merge data - multiple heads in branch \'{0}\'.\nAttempted merge result: {1}", branch.Name, error); return false; } else { clientInfo.MergeVersions.Add(result); Printer.PrintMessage("Resolved incoming merge for branch \"{0}\".", branch.Name); Printer.PrintDiagnostics(" - Merge local input {0}", x.Value); Printer.PrintDiagnostics(" - Merge remote input {0}", temporaryHeads[x.Key].Version); Printer.PrintDiagnostics(" - Head updated to {0}", result.Version.ID); temporaryHeads[x.Key].Version = result.Version.ID; } } // theoretically best clientInfo.UpdatedHeads = temporaryHeads; errorData = string.Empty; return true; }