diff --git a/GitTfs.Vs2010/GitTfs.Vs2010.csproj b/GitTfs.Vs2010/GitTfs.Vs2010.csproj index 7ea88d51..7250ae0b 100644 --- a/GitTfs.Vs2010/GitTfs.Vs2010.csproj +++ b/GitTfs.Vs2010/GitTfs.Vs2010.csproj @@ -1,4 +1,4 @@ - + Debug @@ -72,6 +72,7 @@ + False @@ -154,4 +155,4 @@ xcopy /y "$(TargetDir)*.dll" "$(SolutionDir)GitTfs\$(OutDir)" - \ No newline at end of file + diff --git a/GitTfs.VsCommon/Wrappers.cs b/GitTfs.VsCommon/Wrappers.cs index 50c1455e..1f56d0a0 100644 --- a/GitTfs.VsCommon/Wrappers.cs +++ b/GitTfs.VsCommon/Wrappers.cs @@ -479,5 +479,19 @@ namespace Sep.Git.Tfs.VsCommon { get { return _workspace.OwnerName; } } + + public void Merge(string sourceTfsPath, string targetTfsPath) + { + var status = _workspace.Merge(sourceTfsPath, targetTfsPath, null, null, LockLevel.None, RecursionType.Full, + MergeOptions.AlwaysAcceptMine); + Trace.WriteLine(status.NumOperations); + var conflicts = _workspace.QueryConflicts(null, true); + foreach (var conflict in conflicts) + { + conflict.Resolution = Resolution.AcceptYours; + _workspace.ResolveConflict(conflict); + } + //_stdout.WriteLine("merge status:" + status.NumOperations); + } } } \ No newline at end of file diff --git a/GitTfs.VsFake/TfsHelper.VsFake.cs b/GitTfs.VsFake/TfsHelper.VsFake.cs index 6d011ef6..7f9a10e5 100644 --- a/GitTfs.VsFake/TfsHelper.VsFake.cs +++ b/GitTfs.VsFake/TfsHelper.VsFake.cs @@ -233,6 +233,11 @@ namespace Sep.Git.Tfs.VsFake #region unimplemented + public void Merge(string sourceTfsPath, string tfsRepositoryPath) + { + throw new NotImplementedException(); + } + public IPendingChange[] GetPendingChanges() { throw new NotImplementedException(); diff --git a/GitTfs/Commands/Rcheckin.cs b/GitTfs/Commands/Rcheckin.cs index 4ba4fc52..834c2a46 100644 --- a/GitTfs/Commands/Rcheckin.cs +++ b/GitTfs/Commands/Rcheckin.cs @@ -106,13 +106,14 @@ namespace Sep.Git.Tfs.Commands rc.ExtractCommit(commitWithParents, currentParent); rc.BuildCommitMessage(!_checkinOptions.NoGenerateCheckinComment, currentParent); string target = rc.Sha; + string tfsRepositoryPathOfMergedBranch = FindTfsRepositoryPathOfMergedBranch(repo, rc.Parents); var commitSpecificCheckinOptions = _checkinOptionsFactory.BuildCommitSpecificCheckinOptions(_checkinOptions, rc.Message, rc.Commit); _stdout.WriteLine("Starting checkin of {0} '{1}'", target.Substring(0, 8), commitSpecificCheckinOptions.CheckinComment); try { - newChangesetId = tfsRemote.Checkin(target, currentParent, parentChangeset, commitSpecificCheckinOptions); + newChangesetId = tfsRemote.Checkin(target, currentParent, parentChangeset, commitSpecificCheckinOptions, tfsRepositoryPathOfMergedBranch); tfsRemote.FetchWithMerge(newChangesetId, rc.Parents); if (tfsRemote.MaxChangesetId != newChangesetId) { @@ -177,11 +178,12 @@ namespace Sep.Git.Tfs.Commands rc.ExtractCommit(revList, tfsLatest); rc.BuildCommitMessage(!_checkinOptions.NoGenerateCheckinComment, tfsLatest); string target = rc.Sha; + string tfsRepositoryPathOfMergedBranch = FindTfsRepositoryPathOfMergedBranch(repo, rc.Parents); var commitSpecificCheckinOptions = _checkinOptionsFactory.BuildCommitSpecificCheckinOptions(_checkinOptions, rc.Message, rc.Commit); _stdout.WriteLine("Starting checkin of {0} '{1}'", target.Substring(0, 8), commitSpecificCheckinOptions.CheckinComment); - long newChangesetId = tfsRemote.Checkin(rc.Sha, parentChangeset, commitSpecificCheckinOptions); + long newChangesetId = tfsRemote.Checkin(rc.Sha, parentChangeset, commitSpecificCheckinOptions, tfsRepositoryPathOfMergedBranch); tfsRemote.FetchWithMerge(newChangesetId, rc.Parents); if (tfsRemote.MaxChangesetId != newChangesetId) throw new GitTfsException("error: New TFS changesets were found. Rcheckin was not finished."); @@ -230,6 +232,26 @@ namespace Sep.Git.Tfs.Commands } } + private string FindTfsRepositoryPathOfMergedBranch(IGitRepository repo, string[] gitParents) + { + if (gitParents.Length != 0) + { + if (gitParents.Length > 1) + _stdout.WriteLine("warning: only 1 parent is supported by TFS for a merge changeset. The other parents won't be materialized on the TFS merge!"); + foreach (var gitParent in gitParents) + { + var tfsCommit = repo.GetTfsCommit(gitParent); + if (tfsCommit != null) + return tfsCommit.Remote.TfsRepositoryPath; + _stdout.WriteLine("warning: the parent " + gitParent + " of the merge commit was not checked in TFS and will be ignored!"); + } + //Local merge where didn't found a checked in commit (strange!) + //TODO (IMO) Find if that's TFS branches that are not completely checked in + //If that's the case, we should fail and ask for rcheckin the merged branch before + } + return null; + } + public void RebaseOnto(IGitRepository repository, string tfsLatest, string target) { repository.CommandNoisy("rebase", "--preserve-merges", "--onto", tfsLatest, target); diff --git a/GitTfs/Core/DerivedGitTfsRemote.cs b/GitTfs/Core/DerivedGitTfsRemote.cs index ef5b9df8..821fee15 100644 --- a/GitTfs/Core/DerivedGitTfsRemote.cs +++ b/GitTfs/Core/DerivedGitTfsRemote.cs @@ -1,4 +1,4 @@ -using System; +using System; using Sep.Git.Tfs.Core.TfsInterop; using Sep.Git.Tfs.Commands; @@ -192,12 +192,12 @@ namespace Sep.Git.Tfs.Core throw new NotImplementedException(); } - public long Checkin(string treeish, TfsChangesetInfo parentChangeset, CheckinOptions options) + public long Checkin(string treeish, TfsChangesetInfo parentChangeset, CheckinOptions options, string sourceTfsPath = null) { throw new NotImplementedException(); } - public long Checkin(string head, string parent, TfsChangesetInfo parentChangeset, CheckinOptions options) + public long Checkin(string head, string parent, TfsChangesetInfo parentChangeset, CheckinOptions options, string sourceTfsPath = null) { throw new NotImplementedException(); } @@ -232,12 +232,16 @@ namespace Sep.Git.Tfs.Core throw new NotImplementedException(); } - #endregion - public RemoteInfo RemoteInfo { get { throw new NotImplementedException(); } } + + public void Merge(string sourceTfsPath, string targetTfsPath) + { + throw new NotImplementedException(); + } + #endregion } } diff --git a/GitTfs/Core/GitRepository.cs b/GitTfs/Core/GitRepository.cs index 96ea8cff..662ba025 100644 --- a/GitTfs/Core/GitRepository.cs +++ b/GitTfs/Core/GitRepository.cs @@ -270,6 +270,11 @@ namespace Sep.Git.Tfs.Core return TryParseChangesetInfo(currentCommit.Message, currentCommit.Sha, false); } + public TfsChangesetInfo GetTfsCommit(string sha) + { + return TryParseChangesetInfo(GetCommitMessage(sha), sha, false); + } + private void FindTfsCommits(TextReader stdout, ICollection tfsCommits, bool includeStubRemotes) { string currentCommit = null; diff --git a/GitTfs/Core/GitTfsRemote.cs b/GitTfs/Core/GitTfsRemote.cs index d75ac5fc..596a2327 100644 --- a/GitTfs/Core/GitTfsRemote.cs +++ b/GitTfs/Core/GitTfsRemote.cs @@ -533,17 +533,17 @@ namespace Sep.Git.Tfs.Core } } - public long Checkin(string head, TfsChangesetInfo parentChangeset, CheckinOptions options) + public long Checkin(string head, TfsChangesetInfo parentChangeset, CheckinOptions options, string sourceTfsPath = null) { var changeset = 0L; - WithWorkspace(parentChangeset, workspace => changeset = Checkin(head, parentChangeset.GitCommit, workspace, options)); + WithWorkspace(parentChangeset, workspace => changeset = Checkin(head, parentChangeset.GitCommit, workspace, options, sourceTfsPath)); return changeset; } - public long Checkin(string head, string parent, TfsChangesetInfo parentChangeset, CheckinOptions options) + public long Checkin(string head, string parent, TfsChangesetInfo parentChangeset, CheckinOptions options, string sourceTfsPath = null) { var changeset = 0L; - WithWorkspace(parentChangeset, workspace => changeset = Checkin(head, parent, workspace, options)); + WithWorkspace(parentChangeset, workspace => changeset = Checkin(head, parent, workspace, options, sourceTfsPath)); return changeset; } @@ -558,9 +558,11 @@ namespace Sep.Git.Tfs.Core Tfs.WithWorkspace(WorkingDirectory, this, parentChangeset, action); } - private long Checkin(string head, string parent, ITfsWorkspace workspace, CheckinOptions options) + private long Checkin(string head, string parent, ITfsWorkspace workspace, CheckinOptions options, string sourceTfsPath) { PendChangesToWorkspace(head, parent, workspace); + if (!string.IsNullOrWhiteSpace(sourceTfsPath)) + workspace.Merge(sourceTfsPath, TfsRepositoryPath); return workspace.Checkin(options); } diff --git a/GitTfs/Core/IGitRepository.cs b/GitTfs/Core/IGitRepository.cs index 35e8e962..66655cad 100644 --- a/GitTfs/Core/IGitRepository.cs +++ b/GitTfs/Core/IGitRepository.cs @@ -21,6 +21,7 @@ namespace Sep.Git.Tfs.Core void MoveTfsRefForwardIfNeeded(IGitTfsRemote remote); IEnumerable GetLastParentTfsCommits(string head); IEnumerable GetLastParentTfsCommits(string head, bool includeStubRemotes); + TfsChangesetInfo GetTfsCommit(string sha); TfsChangesetInfo GetCurrentTfsCommit(); IDictionary GetObjects(string commit); string HashAndInsertObject(string filename); diff --git a/GitTfs/Core/IGitTfsRemote.cs b/GitTfs/Core/IGitTfsRemote.cs index 942c6cea..37a98d88 100644 --- a/GitTfs/Core/IGitTfsRemote.cs +++ b/GitTfs/Core/IGitTfsRemote.cs @@ -32,12 +32,12 @@ namespace Sep.Git.Tfs.Core void Shelve(string shelvesetName, string treeish, TfsChangesetInfo parentChangeset, bool evaluateCheckinPolicies); bool HasShelveset(string shelvesetName); long CheckinTool(string head, TfsChangesetInfo parentChangeset); - long Checkin(string treeish, TfsChangesetInfo parentChangeset, CheckinOptions options); + long Checkin(string treeish, TfsChangesetInfo parentChangeset, CheckinOptions options, string sourceTfsPath = null); /// /// Checks in to TFS set of changes from git repository between given commits (parent..head) onto given TFS changeset. Returns ID of the new changeset. /// - long Checkin(string head, string parent, TfsChangesetInfo parentChangeset, CheckinOptions options); + long Checkin(string head, string parent, TfsChangesetInfo parentChangeset, CheckinOptions options, string sourceTfsPath = null); void CleanupWorkspace(); void CleanupWorkspaceDirectory(); ITfsChangeset GetChangeset(long changesetId); diff --git a/GitTfs/Core/ITfsWorkspace.cs b/GitTfs/Core/ITfsWorkspace.cs index 749f093b..bc318fc3 100644 --- a/GitTfs/Core/ITfsWorkspace.cs +++ b/GitTfs/Core/ITfsWorkspace.cs @@ -39,5 +39,6 @@ namespace Sep.Git.Tfs.Core void Get(IChangeset changeset); long CheckinTool(Func generateCheckinComment); + void Merge(string sourceTfsPath, string tfsRepositoryPath); } } \ No newline at end of file diff --git a/GitTfs/Core/TfsInterop/IWorkspace.cs b/GitTfs/Core/TfsInterop/IWorkspace.cs index 87580c8d..92f8a059 100644 --- a/GitTfs/Core/TfsInterop/IWorkspace.cs +++ b/GitTfs/Core/TfsInterop/IWorkspace.cs @@ -17,5 +17,6 @@ namespace Sep.Git.Tfs.Core.TfsInterop void GetSpecificVersion(IChangeset changeset); string GetLocalItemForServerItem(string serverItem); string OwnerName { get; } + void Merge(string sourceTfsPath, string tfsRepositoryPath); } } \ No newline at end of file diff --git a/GitTfs/Core/TfsWorkspace.cs b/GitTfs/Core/TfsWorkspace.cs index b199eae7..54c7f094 100644 --- a/GitTfs/Core/TfsWorkspace.cs +++ b/GitTfs/Core/TfsWorkspace.cs @@ -67,6 +67,11 @@ namespace Sep.Git.Tfs.Core return newChangesetId; } + public void Merge(string sourceTfsPath, string tfsRepositoryPath) + { + _workspace.Merge(sourceTfsPath, tfsRepositoryPath); + } + public long Checkin(CheckinOptions options) { if (options == null) options = _checkinOptions;