/// <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. The returned
        /// index must be disposed.
        /// </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="Index"/> 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");

            options = options ?? new MergeTreeOptions();

            var mergeOptions = new GitMergeOpts
            {
                Version             = 1,
                MergeFileFavorFlags = options.MergeFileFavor,
                MergeTreeFlags      = options.FindRenames ? GitMergeTreeFlags.GIT_MERGE_TREE_FIND_RENAMES
                                                     : GitMergeTreeFlags.GIT_MERGE_TREE_NORMAL,
                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))
                    using (var indexHandle = Proxy.git_merge_commits(repo.Handle, oneHandle, twoHandle, mergeOptions))
                    {
                        MergeTreeResult mergeResult;

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

                            using (ConflictIteratorSafeHandle 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);
                    }
        }
Beispiel #2
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. The returned
        /// index must be disposed.
        /// </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="Index"/> 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");

            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 mergeOptions = new GitMergeOpts
            {
                Version             = 1,
                MergeFileFavorFlags = options.MergeFileFavor,
                MergeTreeFlags      = mergeFlags,
                RenameThreshold     = (uint)options.RenameThreshold,
                TargetLimit         = (uint)options.TargetLimit,
            };

            bool earlyStop;

            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))
                    using (var indexHandle = Proxy.git_merge_commits(repo.Handle, oneHandle, twoHandle, mergeOptions, 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 (ConflictIteratorSafeHandle 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);
                    }
        }