예제 #1
0
        /// <summary>
        /// Perform a three-way merge of two commits, looking up their
        /// commit ancestor. The returned index will contain the results
        /// of the merge and can be examined for conflicts.
        /// </summary>
        /// <param name="ours">The first tree</param>
        /// <param name="theirs">The second tree</param>
        /// <param name="options">The <see cref="MergeTreeOptions"/> controlling the merge</param>
        /// <param name="earlyStop">True if the merge stopped early due to conflicts</param>
        /// <returns>The <see cref="IndexHandle"/> containing the merged trees and any conflicts</returns>
        private IndexHandle MergeCommits(Commit ours, Commit theirs, MergeTreeOptions options, out bool earlyStop)
        {
            GitMergeFlag mergeFlags = GitMergeFlag.GIT_MERGE_NORMAL;

            if (options.SkipReuc)
            {
                mergeFlags |= GitMergeFlag.GIT_MERGE_SKIP_REUC;
            }
            if (options.FindRenames)
            {
                mergeFlags |= GitMergeFlag.GIT_MERGE_FIND_RENAMES;
            }
            if (options.FailOnConflict)
            {
                mergeFlags |= GitMergeFlag.GIT_MERGE_FAIL_ON_CONFLICT;
            }

            var mergeOptions = new GitMergeOpts
            {
                Version             = 1,
                MergeFileFavorFlags = options.MergeFileFavor,
                MergeTreeFlags      = mergeFlags,
                RenameThreshold     = (uint)options.RenameThreshold,
                TargetLimit         = (uint)options.TargetLimit,
            };

            using (var oneHandle = Proxy.git_object_lookup(repo.Handle, ours.Id, GitObjectType.Commit))
                using (var twoHandle = Proxy.git_object_lookup(repo.Handle, theirs.Id, GitObjectType.Commit))
                {
                    var indexHandle = Proxy.git_merge_commits(repo.Handle, oneHandle, twoHandle, mergeOptions, out earlyStop);
                    return(indexHandle);
                }
        }
예제 #2
0
        /// <summary>
        /// Perform a three-way merge of two commits, looking up their
        /// commit ancestor. The returned <see cref="MergeTreeResult"/> will contain the results
        /// of the merge and can be examined for conflicts.
        /// </summary>
        /// <param name="ours">The first commit</param>
        /// <param name="theirs">The second commit</param>
        /// <param name="options">The <see cref="MergeTreeOptions"/> controlling the merge</param>
        /// <returns>The <see cref="MergeTreeResult"/> containing the merged trees and any conflicts</returns>
        public virtual MergeTreeResult MergeCommits(Commit ours, Commit theirs, MergeTreeOptions options)
        {
            Ensure.ArgumentNotNull(ours, "ours");
            Ensure.ArgumentNotNull(theirs, "theirs");

            var modifiedOptions = new MergeTreeOptions();

            // We throw away the index after looking at the conflicts, so we'll never need the REUC
            // entries to be there
            modifiedOptions.SkipReuc = true;

            if (options != null)
            {
                modifiedOptions.FailOnConflict         = options.FailOnConflict;
                modifiedOptions.FindRenames            = options.FindRenames;
                modifiedOptions.IgnoreWhitespaceChange = options.IgnoreWhitespaceChange;
                modifiedOptions.MergeFileFavor         = options.MergeFileFavor;
                modifiedOptions.RenameThreshold        = options.RenameThreshold;
                modifiedOptions.TargetLimit            = options.TargetLimit;
            }

            bool earlyStop;

            using (var indexHandle = MergeCommits(ours, theirs, modifiedOptions, out earlyStop))
            {
                MergeTreeResult mergeResult;

                // Stopped due to FailOnConflict so there's no index or conflict list
                if (earlyStop)
                {
                    return(new MergeTreeResult(new Conflict[] { }));
                }

                if (Proxy.git_index_has_conflicts(indexHandle))
                {
                    List <Conflict> conflicts = new List <Conflict>();
                    Conflict        conflict;

                    using (ConflictIteratorHandle iterator = Proxy.git_index_conflict_iterator_new(indexHandle))
                    {
                        while ((conflict = Proxy.git_index_conflict_next(iterator)) != null)
                        {
                            conflicts.Add(conflict);
                        }
                    }

                    mergeResult = new MergeTreeResult(conflicts);
                }
                else
                {
                    var treeId = Proxy.git_index_write_tree_to(indexHandle, repo.Handle);
                    mergeResult = new MergeTreeResult(this.repo.Lookup <Tree>(treeId));
                }

                return(mergeResult);
            }
        }
예제 #3
0
        /// <summary>
        /// Returns whether merging <paramref name="one"/> into <paramref name="another"/>
        /// would result in merge conflicts.
        /// </summary>
        /// <param name="one">The commit wrapping the base tree to merge into.</param>
        /// <param name="another">The commit wrapping the tree to merge into <paramref name="one"/>.</param>
        /// <returns>True if the merge does not result in a conflict, false otherwise.</returns>
        public virtual bool CanMergeWithoutConflict(Commit one, Commit another)
        {
            Ensure.ArgumentNotNull(one, "one");
            Ensure.ArgumentNotNull(another, "another");

            var opts = new MergeTreeOptions()
            {
                SkipReuc       = true,
                FailOnConflict = true,
            };

            var result = repo.ObjectDatabase.MergeCommits(one, another, opts);

            return(result.Status == MergeTreeStatus.Succeeded);
        }
예제 #4
0
        /// <summary>
        /// Performs a cherry-pick of <paramref name="cherryPickCommit"/> onto <paramref name="cherryPickOnto"/> commit.
        /// </summary>
        /// <param name="cherryPickCommit">The commit to cherry-pick.</param>
        /// <param name="cherryPickOnto">The commit to cherry-pick onto.</param>
        /// <param name="mainline">Which commit to consider the parent for the diff when cherry-picking a merge commit.</param>
        /// <param name="options">The options for the merging in the cherry-pick operation.</param>
        /// <param name="earlyStop">True if the cherry-pick stopped early due to conflicts</param>
        /// <returns>The <see cref="IndexHandle"/> containing the cherry-pick result tree and any conflicts</returns>
        private IndexHandle CherryPickCommit(Commit cherryPickCommit, Commit cherryPickOnto, int mainline, MergeTreeOptions options, out bool earlyStop)
        {
            GitMergeFlag mergeFlags = GitMergeFlag.GIT_MERGE_NORMAL;

            if (options.SkipReuc)
            {
                mergeFlags |= GitMergeFlag.GIT_MERGE_SKIP_REUC;
            }
            if (options.FindRenames)
            {
                mergeFlags |= GitMergeFlag.GIT_MERGE_FIND_RENAMES;
            }
            if (options.FailOnConflict)
            {
                mergeFlags |= GitMergeFlag.GIT_MERGE_FAIL_ON_CONFLICT;
            }

            var mergeOptions = new GitMergeOpts
            {
                Version             = 1,
                MergeFileFavorFlags = options.MergeFileFavor,
                MergeTreeFlags      = mergeFlags,
                RenameThreshold     = (uint)options.RenameThreshold,
                TargetLimit         = (uint)options.TargetLimit,
            };

            using (var cherryPickOntoHandle = Proxy.git_object_lookup(repo.Handle, cherryPickOnto.Id, GitObjectType.Commit))
                using (var cherryPickCommitHandle = Proxy.git_object_lookup(repo.Handle, cherryPickCommit.Id, GitObjectType.Commit))
                {
                    var indexHandle = Proxy.git_cherrypick_commit(repo.Handle, cherryPickCommitHandle, cherryPickOntoHandle, (uint)mainline, mergeOptions, out earlyStop);
                    return(indexHandle);
                }
        }
예제 #5
0
        /// <summary>
        /// Performs a cherry-pick of <paramref name="cherryPickCommit"/> onto <paramref name="cherryPickOnto"/> commit.
        /// </summary>
        /// <param name="cherryPickCommit">The commit to cherry-pick.</param>
        /// <param name="cherryPickOnto">The commit to cherry-pick onto.</param>
        /// <param name="mainline">Which commit to consider the parent for the diff when cherry-picking a merge commit.</param>
        /// <param name="options">The options for the merging in the cherry-pick operation.</param>
        /// <returns>The <see cref="TransientIndex"/> containing the cherry-pick result tree and any conflicts, or null if the merge stopped early due to conflicts.
        /// The index must be disposed by the caller. </returns>
        public virtual TransientIndex CherryPickCommitIntoIndex(Commit cherryPickCommit, Commit cherryPickOnto, int mainline, MergeTreeOptions options)
        {
            Ensure.ArgumentNotNull(cherryPickCommit, "cherryPickCommit");
            Ensure.ArgumentNotNull(cherryPickOnto, "cherryPickOnto");

            options = options ?? new MergeTreeOptions();

            bool earlyStop;
            var  indexHandle = CherryPickCommit(cherryPickCommit, cherryPickOnto, mainline, options, out earlyStop);

            if (earlyStop)
            {
                if (indexHandle != null)
                {
                    indexHandle.Dispose();
                }
                return(null);
            }
            var result = new TransientIndex(indexHandle, repo);

            return(result);
        }
예제 #6
0
        /// <summary>
        /// Perform a three-way merge of two commits, looking up their
        /// commit ancestor. The returned index will contain the results
        /// of the merge and can be examined for conflicts.
        /// </summary>
        /// <param name="ours">The first tree</param>
        /// <param name="theirs">The second tree</param>
        /// <param name="options">The <see cref="MergeTreeOptions"/> controlling the merge</param>
        /// <returns>The <see cref="TransientIndex"/> containing the merged trees and any conflicts, or null if the merge stopped early due to conflicts.
        /// The index must be disposed by the caller.</returns>
        public virtual TransientIndex MergeCommitsIntoIndex(Commit ours, Commit theirs, MergeTreeOptions options)
        {
            Ensure.ArgumentNotNull(ours, "ours");
            Ensure.ArgumentNotNull(theirs, "theirs");

            options = options ?? new MergeTreeOptions();

            bool earlyStop;
            var  indexHandle = MergeCommits(ours, theirs, options, out earlyStop);

            if (earlyStop)
            {
                if (indexHandle != null)
                {
                    indexHandle.Dispose();
                }
                return(null);
            }
            var result = new TransientIndex(indexHandle, repo);

            return(result);
        }
예제 #7
0
        /// <summary>
        /// Performs a revert of <paramref name="revertCommit"/> onto <paramref name="revertOnto"/> commit.
        /// </summary>
        /// <param name="revertCommit">The commit to revert.</param>
        /// <param name="revertOnto">The commit to revert onto.</param>
        /// <param name="mainline">Which commit to consider the parent for the diff when reverting a merge commit.</param>
        /// <param name="options">The options for the merging in the revert operation.</param>
        /// <returns>A result containing a <see cref="Tree"/> if the revert was successful and a list of <see cref="Conflict"/>s if it is not.</returns>
        public virtual MergeTreeResult RevertCommit(Commit revertCommit, Commit revertOnto, int mainline, MergeTreeOptions options)
        {
            Ensure.ArgumentNotNull(revertCommit, "revertCommit");
            Ensure.ArgumentNotNull(revertOnto, "revertOnto");

            options = options ?? new MergeTreeOptions();

            // We throw away the index after looking at the conflicts, so we'll never need the REUC
            // entries to be there
            GitMergeFlag mergeFlags = GitMergeFlag.GIT_MERGE_NORMAL | GitMergeFlag.GIT_MERGE_SKIP_REUC;

            if (options.FindRenames)
            {
                mergeFlags |= GitMergeFlag.GIT_MERGE_FIND_RENAMES;
            }
            if (options.FailOnConflict)
            {
                mergeFlags |= GitMergeFlag.GIT_MERGE_FAIL_ON_CONFLICT;
            }


            var opts = new GitMergeOpts
            {
                Version             = 1,
                MergeFileFavorFlags = options.MergeFileFavor,
                MergeTreeFlags      = mergeFlags,
                RenameThreshold     = (uint)options.RenameThreshold,
                TargetLimit         = (uint)options.TargetLimit
            };

            bool earlyStop;

            using (var revertOntoHandle = Proxy.git_object_lookup(repo.Handle, revertOnto.Id, GitObjectType.Commit))
                using (var revertCommitHandle = Proxy.git_object_lookup(repo.Handle, revertCommit.Id, GitObjectType.Commit))
                    using (var indexHandle = Proxy.git_revert_commit(repo.Handle, revertCommitHandle, revertOntoHandle, (uint)mainline, opts, out earlyStop))
                    {
                        MergeTreeResult revertTreeResult;

                        // Stopped due to FailOnConflict so there's no index or conflict list
                        if (earlyStop)
                        {
                            return(new MergeTreeResult(new Conflict[] { }));
                        }

                        if (Proxy.git_index_has_conflicts(indexHandle))
                        {
                            List <Conflict> conflicts = new List <Conflict>();
                            Conflict        conflict;
                            using (ConflictIteratorHandle iterator = Proxy.git_index_conflict_iterator_new(indexHandle))
                            {
                                while ((conflict = Proxy.git_index_conflict_next(iterator)) != null)
                                {
                                    conflicts.Add(conflict);
                                }
                            }
                            revertTreeResult = new MergeTreeResult(conflicts);
                        }
                        else
                        {
                            var treeId = Proxy.git_index_write_tree_to(indexHandle, repo.Handle);
                            revertTreeResult = new MergeTreeResult(this.repo.Lookup <Tree>(treeId));
                        }

                        return(revertTreeResult);
                    }
        }