/// <summary> /// Apply the changes between the two commits to the TFS workspace. This will make the /// changes as granular as possible. /// </summary> private bool ApplyCommitToWorkspace(CommitRange commitRange) { var toApply = new Stack <CommitRange>(); var current = commitRange.NewCommit; var oldCommit = commitRange.OldCommit; while (current.Sha != oldCommit.Sha && current.Parents.Count() == 1) { var parent = current.Parents.ElementAt(0); toApply.Push(new CommitRange(oldCommit: parent, newCommit: current)); current = parent; } if (current.Sha != oldCommit.Sha) { toApply.Push(new CommitRange(oldCommit: oldCommit, newCommit: current)); } while (toApply.Count > 0) { if (!ApplyCommitToWorkspaceCore(toApply.Pop())) { return(false); } } return(true); }
internal void RunCore(Commit baseCommit) { // TODO: Add cancellation, async, etc ... to the loop while (true) { if (!FetchGitLatest()) { return; } var refName = string.Format("refs/remotes/{0}/{1}", _remoteName, _branchName); var commit = _repository.Refs[refName].ResolveAs <Commit>(); if (commit.Sha == baseCommit.Sha) { _host.Verbose("No changes detected, waiting"); Thread.Sleep(TimeSpan.FromMinutes(1)); continue; } if (!UpdateWorkspaceToLatest()) { return; } var commitRange = new CommitRange(oldCommit: baseCommit, newCommit: commit); if (!ApplyCommitToWorkspace(commitRange)) { return; } baseCommit = commit; } }
private string CreateCheckinMessage(CommitRange commitRange, string ownerDisplayName) { var builder = new StringBuilder(); var message = commitRange.NewCommit.Message; var shortMessage = commitRange.NewCommit.MessageShort; if (!string.IsNullOrEmpty(shortMessage) && shortMessage.StartsWith(@"Merge pull request") && message.StartsWith(shortMessage)) { // For merged PRs, re-arrange the checkin message to output the core commit message first. var strippedMessage = message.Substring(shortMessage.Length).TrimStart('\n', '\r', ' '); builder.AppendLine(strippedMessage); builder.AppendLine(); builder.AppendLine(shortMessage); } else { builder.AppendLine(message); builder.AppendLine(); } builder.AppendFormatLine("Ported from Git -> TFS on behalf of: '{0}'", ownerDisplayName); builder.AppendLine(); builder.AppendFormatLine("From: {0}", commitRange.OldCommit.Sha); builder.AppendFormatLine("To: {0}", commitRange.NewCommit.Sha); builder.AppendLine(); builder.AppendFormatLine("[git-commit-sha: {0}]", commitRange.NewCommit.Sha); var commitUri = _repositoryUrl + string.Format("/commit/{0}", commitRange.NewCommit.Sha); builder.AppendFormatLine("[git-commit-url: {0}", commitUri); builder.AppendLine(); builder.AppendLine("*** This commit was generated automatically by a tool. Contact [email protected] for help. ***"); return(builder.ToString()); }
/// <summary> /// Apply the specific commit to the Workspace. This method assumes the Workspace is in a good /// state at the time the application of the commit occurs. /// <return>True if the operation was completed successfully (or there was simply no work to do)</return> /// </summary> private bool ApplyCommitToWorkspaceCore(CommitRange commitRange) { Debug.Assert(!HasPendingChangesBesidesLock()); var newCommit = commitRange.NewCommit; _host.Status("Applying {0}", newCommit); // Note: This is a suboptimal way of building the tree. The file system can be changed by // local builds and such. Much better to build directly from the Workspace object. var workspaceTree = GitUtils.CreateTreeFromWorkspace(_workspace, _workspacePath, _repository.ObjectDatabase); var treeChanges = _repository.Diff.Compare <TreeChanges>(workspaceTree, newCommit.Tree, compareOptions: new LibGit2Sharp.CompareOptions() { Similarity = SimilarityOptions.Renames }); if (!treeChanges.Any()) { _host.Status("No changes to apply"); return(true); } if (!ApplyGitChangeToWorkspace(treeChanges)) { return(false); } var ownerInfo = GetCommitOwnerInfo(commitRange.NewCommit); var checkinMessage = CreateCheckinMessage(commitRange, ownerInfo.UserDisplayName); if (_confirmBeforeCheckin && !ConfirmCheckin(newCommit, checkinMessage)) { return(false); } try { _workspace.CheckIn( _workspace.GetPendingChanges(), author: ownerInfo.MappedTfsAuthorName, comment: checkinMessage, checkinNote: null, workItemChanges: null, policyOverride: null); _cachedWorkspaceTree = newCommit.Tree; } catch (Exception ex) { _host.Error("Unable to complete checkin: {0}", ex.Message); _cachedWorkspaceTree = null; return(false); } _host.Status("Checkin complete for {0}", commitRange.NewCommit.Sha); // The check in will undo the lock so re-lock now if (_lockWorkspacePath) { LockWorkspacePath(); } return(true); }