/// <param name="newHead">the object the head points at after the merge</param> /// <param name="base"> /// the common base which was used to produce a content-merge. May /// be <code>null</code> if the merge-result was produced without /// computing a common base /// </param> /// <param name="mergedCommits">all the commits which have been merged together</param> /// <param name="mergeStatus">the status the merge resulted in</param> /// <param name="mergeStrategy"> /// the used /// <see cref="NGit.Merge.MergeStrategy">NGit.Merge.MergeStrategy</see> /// </param> /// <param name="lowLevelResults"> /// merge results as returned by /// <see cref="NGit.Merge.ResolveMerger.GetMergeResults()">NGit.Merge.ResolveMerger.GetMergeResults() /// </see> /// </param> /// <param name="description">a user friendly description of the merge result</param> public MergeCommandResult(ObjectId newHead, ObjectId @base, ObjectId[] mergedCommits , MergeStatus mergeStatus, MergeStrategy mergeStrategy, IDictionary <string, NGit.Merge.MergeResult <Sequence> > lowLevelResults, string description) { this.newHead = newHead; this.mergedCommits = mergedCommits; this.@base = @base; this.mergeStatus = mergeStatus; this.mergeStrategy = mergeStrategy; this.description = description; if (lowLevelResults != null) { foreach (KeyValuePair <string, NGit.Merge.MergeResult <Sequence> > result in lowLevelResults .EntrySet()) { AddConflict(result.Key, result.Value); } } }
/// <summary> /// Executes the /// <code>Merge</code> /// command with all the options and parameters /// collected by the setter methods (e.g. /// <see cref="Include(NGit.Ref)">Include(NGit.Ref)</see> /// ) of this /// class. Each instance of this class should only be used for one invocation /// of the command. Don't call this method twice on an instance. /// </summary> /// <returns>the result of the merge</returns> /// <exception cref="NGit.Api.Errors.GitAPIException"></exception> /// <exception cref="NGit.Api.Errors.NoHeadException"></exception> /// <exception cref="NGit.Api.Errors.ConcurrentRefUpdateException"></exception> /// <exception cref="NGit.Api.Errors.CheckoutConflictException"></exception> /// <exception cref="NGit.Api.Errors.InvalidMergeHeadsException"></exception> /// <exception cref="NGit.Api.Errors.WrongRepositoryStateException"></exception> /// <exception cref="NGit.Api.Errors.NoMessageException"></exception> public override MergeCommandResult Call() { CheckCallable(); if (commits.Count != 1) { throw new InvalidMergeHeadsException(commits.IsEmpty() ? JGitText.Get().noMergeHeadSpecified : MessageFormat.Format(JGitText.Get().mergeStrategyDoesNotSupportHeads, mergeStrategy .GetName(), Sharpen.Extensions.ValueOf(commits.Count))); } RevWalk revWalk = null; DirCacheCheckout dco = null; try { Ref head = repo.GetRef(Constants.HEAD); if (head == null) { throw new NoHeadException(JGitText.Get().commitOnRepoWithoutHEADCurrentlyNotSupported ); } StringBuilder refLogMessage = new StringBuilder("merge "); // Check for FAST_FORWARD, ALREADY_UP_TO_DATE revWalk = new RevWalk(repo); // we know for now there is only one commit Ref @ref = commits[0]; refLogMessage.Append(@ref.GetName()); // handle annotated tags ObjectId objectId = @ref.GetPeeledObjectId(); if (objectId == null) { objectId = @ref.GetObjectId(); } RevCommit srcCommit = revWalk.LookupCommit(objectId); ObjectId headId = head.GetObjectId(); if (headId == null) { revWalk.ParseHeaders(srcCommit); dco = new DirCacheCheckout(repo, repo.LockDirCache(), srcCommit.Tree); dco.SetFailOnConflict(true); dco.Checkout(); RefUpdate refUpdate = repo.UpdateRef(head.GetTarget().GetName()); refUpdate.SetNewObjectId(objectId); refUpdate.SetExpectedOldObjectId(null); refUpdate.SetRefLogMessage("initial pull", false); if (refUpdate.Update() != RefUpdate.Result.NEW) { throw new NoHeadException(JGitText.Get().commitOnRepoWithoutHEADCurrentlyNotSupported ); } SetCallable(false); return(new MergeCommandResult(srcCommit, srcCommit, new ObjectId[] { null, srcCommit }, MergeStatus.FAST_FORWARD, mergeStrategy, null, null)); } RevCommit headCommit = revWalk.LookupCommit(headId); if (revWalk.IsMergedInto(srcCommit, headCommit)) { SetCallable(false); return(new MergeCommandResult(headCommit, srcCommit, new ObjectId[] { headCommit, srcCommit }, MergeStatus.ALREADY_UP_TO_DATE, mergeStrategy, null, null)); } else { if (revWalk.IsMergedInto(headCommit, srcCommit)) { // FAST_FORWARD detected: skip doing a real merge but only // update HEAD refLogMessage.Append(": " + MergeStatus.FAST_FORWARD); dco = new DirCacheCheckout(repo, headCommit.Tree, repo.LockDirCache(), srcCommit. Tree); dco.SetFailOnConflict(true); dco.Checkout(); string msg = null; ObjectId newHead; ObjectId @base = null; MergeStatus mergeStatus = null; if (!squash) { UpdateHead(refLogMessage, srcCommit, headId); newHead = @base = srcCommit; mergeStatus = MergeStatus.FAST_FORWARD; } else { msg = JGitText.Get().squashCommitNotUpdatingHEAD; newHead = @base = headId; mergeStatus = MergeStatus.FAST_FORWARD_SQUASHED; IList <RevCommit> squashedCommits = RevWalkUtils.Find(revWalk, srcCommit, headCommit ); string squashMessage = new SquashMessageFormatter().Format(squashedCommits, head); repo.WriteSquashCommitMsg(squashMessage); } SetCallable(false); return(new MergeCommandResult(newHead, @base, new ObjectId[] { headCommit, srcCommit }, mergeStatus, mergeStrategy, null, msg)); } else { string mergeMessage = string.Empty; if (!squash) { mergeMessage = new MergeMessageFormatter().Format(commits, head); repo.WriteMergeCommitMsg(mergeMessage); repo.WriteMergeHeads(Arrays.AsList(@ref.GetObjectId())); } else { IList <RevCommit> squashedCommits = RevWalkUtils.Find(revWalk, srcCommit, headCommit ); string squashMessage = new SquashMessageFormatter().Format(squashedCommits, head); repo.WriteSquashCommitMsg(squashMessage); } Merger merger = mergeStrategy.NewMerger(repo); bool noProblems; IDictionary <string, MergeResult <NGit.Diff.Sequence> > lowLevelResults = null; IDictionary <string, ResolveMerger.MergeFailureReason> failingPaths = null; IList <string> unmergedPaths = null; if (merger is ResolveMerger) { ResolveMerger resolveMerger = (ResolveMerger)merger; resolveMerger.SetCommitNames(new string[] { "BASE", "HEAD", @ref.GetName() }); resolveMerger.SetWorkingTreeIterator(new FileTreeIterator(repo)); noProblems = merger.Merge(headCommit, srcCommit); lowLevelResults = resolveMerger.GetMergeResults(); failingPaths = resolveMerger.GetFailingPaths(); unmergedPaths = resolveMerger.GetUnmergedPaths(); } else { noProblems = merger.Merge(headCommit, srcCommit); } refLogMessage.Append(": Merge made by "); refLogMessage.Append(mergeStrategy.GetName()); refLogMessage.Append('.'); if (noProblems) { dco = new DirCacheCheckout(repo, headCommit.Tree, repo.LockDirCache(), merger.GetResultTreeId ()); dco.SetFailOnConflict(true); dco.Checkout(); string msg = null; RevCommit newHead = null; MergeStatus mergeStatus = null; if (!squash) { newHead = new Git(GetRepository()).Commit().SetReflogComment(refLogMessage.ToString ()).Call(); mergeStatus = MergeStatus.MERGED; } else { msg = JGitText.Get().squashCommitNotUpdatingHEAD; newHead = headCommit; mergeStatus = MergeStatus.MERGED_SQUASHED; } return(new MergeCommandResult(newHead.Id, null, new ObjectId[] { headCommit.Id, srcCommit .Id }, mergeStatus, mergeStrategy, null, msg)); } else { if (failingPaths != null) { repo.WriteMergeCommitMsg(null); repo.WriteMergeHeads(null); return(new MergeCommandResult(null, merger.GetBaseCommit(0, 1), new ObjectId[] { headCommit.Id, srcCommit.Id }, MergeStatus.FAILED, mergeStrategy, lowLevelResults , failingPaths, null)); } else { string mergeMessageWithConflicts = new MergeMessageFormatter().FormatWithConflicts (mergeMessage, unmergedPaths); repo.WriteMergeCommitMsg(mergeMessageWithConflicts); return(new MergeCommandResult(null, merger.GetBaseCommit(0, 1), new ObjectId[] { headCommit.Id, srcCommit.Id }, MergeStatus.CONFLICTING, mergeStrategy, lowLevelResults , null)); } } } } } catch (NGit.Errors.CheckoutConflictException e) { IList <string> conflicts = (dco == null) ? Sharpen.Collections.EmptyList <string>() : dco.GetConflicts(); throw new NGit.Api.Errors.CheckoutConflictException(conflicts, e); } catch (IOException e) { throw new JGitInternalException(MessageFormat.Format(JGitText.Get().exceptionCaughtDuringExecutionOfMergeCommand , e), e); } finally { if (revWalk != null) { revWalk.Release(); } } }
/// <param name="newHead">the object the head points at after the merge</param> /// <param name="base"> /// the common base which was used to produce a content-merge. May /// be <code>null</code> if the merge-result was produced without /// computing a common base /// </param> /// <param name="mergedCommits">all the commits which have been merged together</param> /// <param name="mergeStatus">the status the merge resulted in</param> /// <param name="mergeStrategy"> /// the used /// <see cref="NGit.Merge.MergeStrategy">NGit.Merge.MergeStrategy</see> /// </param> /// <param name="lowLevelResults"> /// merge results as returned by /// <see cref="NGit.Merge.ResolveMerger.GetMergeResults()">NGit.Merge.ResolveMerger.GetMergeResults() /// </see> /// </param> /// <since>2.0</since> public MergeCommandResult(ObjectId newHead, ObjectId @base, ObjectId[] mergedCommits , MergeStatus mergeStatus, MergeStrategy mergeStrategy, IDictionary <string, MergeResult <Sequence> > lowLevelResults) : this(newHead, @base, mergedCommits, mergeStatus, mergeStrategy , lowLevelResults, null) { }