/// <summary>
        /// Show changes between a <see cref="Tree"/> and the Index, the Working Directory, or both.
        /// <para>
        /// The level of diff performed can be specified by passing either a <see cref="TreeChanges"/>
        /// or <see cref="Patch"/> type as the generic parameter.
        /// </para>
        /// </summary>
        /// <param name="oldTree">The <see cref="Tree"/> to compare from.</param>
        /// <param name="diffTargets">The targets to compare to.</param>
        /// <param name="paths">The list of paths (either files or directories) that should be compared.</param>
        /// <param name="explicitPathsOptions">
        /// If set, the passed <paramref name="paths"/> will be treated as explicit paths.
        /// Use these options to determine how unmatched explicit paths should be handled.
        /// </param>
        /// <param name="compareOptions">Additional options to define patch generation behavior.</param>
        /// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
        /// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
        /// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
        public virtual T Compare <T>(Tree oldTree, DiffTargets diffTargets, IEnumerable <string> paths,
                                     ExplicitPathsOptions explicitPathsOptions, CompareOptions compareOptions) where T : class, IDiffResult
        {
            var      comparer  = HandleRetrieverDispatcher[diffTargets](repo);
            ObjectId oldTreeId = oldTree != null ? oldTree.Id : null;

            DiffModifiers diffOptions = diffTargets.HasFlag(DiffTargets.WorkingDirectory)
                ? DiffModifiers.IncludeUntracked
                : DiffModifiers.None;

            if (explicitPathsOptions != null)
            {
                diffOptions |= DiffModifiers.DisablePathspecMatch;

                if (explicitPathsOptions.ShouldFailOnUnmatchedPath || explicitPathsOptions.OnUnmatchedPath != null)
                {
                    diffOptions |= DiffModifiers.IncludeUnmodified;
                }
            }

            using (DiffSafeHandle diff = BuildDiffList(oldTreeId, null, comparer, diffOptions, paths, explicitPathsOptions, compareOptions))
            {
                return(BuildDiffResult <T>(diff));
            }
        }
Example #2
0
        internal virtual T Compare <T>(DiffModifiers diffOptions, IEnumerable <string> paths = null,
                                       ExplicitPathsOptions explicitPathsOptions             = null, CompareOptions compareOptions = null) where T : class
        {
            Func <DiffSafeHandle, object> builder;

            if (!ChangesBuilders.TryGetValue(typeof(T), out builder))
            {
                throw new LibGit2SharpException(string.Format(CultureInfo.InvariantCulture,
                                                              "Unexpected type '{0}' passed to Compare. Supported values are either '{1}' or '{2}'.", typeof(T),
                                                              typeof(TreeChanges), typeof(Patch)));
            }

            var comparer = WorkdirToIndex(repo);

            if (explicitPathsOptions != null)
            {
                diffOptions |= DiffModifiers.DisablePathspecMatch;

                if (explicitPathsOptions.ShouldFailOnUnmatchedPath ||
                    explicitPathsOptions.OnUnmatchedPath != null)
                {
                    diffOptions |= DiffModifiers.IncludeUnmodified;
                }
            }

            using (DiffSafeHandle diff = BuildDiffList(null, null, comparer,
                                                       diffOptions, paths, explicitPathsOptions, compareOptions))
            {
                return((T)builder(diff));
            }
        }
Example #3
0
        private static TreeComparisonHandleRetriever WorkdirAndIndexToTree(Repository repo)
        {
            TreeComparisonHandleRetriever comparisonHandleRetriever = (oh, nh, o) =>
            {
                DiffSafeHandle diff = null, diff2 = null;

                try
                {
                    diff  = Proxy.git_diff_tree_to_index(repo.Handle, repo.Index.Handle, oh, o);
                    diff2 = Proxy.git_diff_index_to_workdir(repo.Handle, repo.Index.Handle, o);
                    Proxy.git_diff_merge(diff, diff2);
                }
                catch
                {
                    diff.SafeDispose();
                    throw;
                }
                finally
                {
                    diff2.SafeDispose();
                }

                return(diff);
            };

            return(comparisonHandleRetriever);
        }
Example #4
0
        private static T BuildDiffResult <T>(DiffSafeHandle diff) where T : class, IDiffResult
        {
            Func <DiffSafeHandle, object> builder;

            if (!ChangesBuilders.TryGetValue(typeof(T), out builder))
            {
                throw new LibGit2SharpException("User-defined types passed to Compare are not supported. Supported values are: {0}",
                                                string.Join(", ", ChangesBuilders.Keys.Select(x => x.Name)));
            }

            return((T)builder(diff));
        }
Example #5
0
        internal Patch(DiffSafeHandle diff)
        {
            int count = Proxy.git_diff_num_deltas(diff);

            for (int i = 0; i < count; i++)
            {
                using (var patch = Proxy.git_patch_from_diff(diff, i))
                {
                    var delta = Proxy.git_diff_get_delta(diff, i);
                    AddFileChange(delta);
                    Proxy.git_patch_print(patch, PrintCallBack);
                }
            }
        }
Example #6
0
        private static TreeComparisonHandleRetriever WorkdirAndIndexToTree(Repository repo)
        {
            TreeComparisonHandleRetriever comparisonHandleRetriever = (oh, nh, o) =>
            {
                DiffSafeHandle diff = Proxy.git_diff_tree_to_index(repo.Handle, repo.Index.Handle, oh, o);

                using (DiffSafeHandle diff2 = Proxy.git_diff_index_to_workdir(repo.Handle, repo.Index.Handle, o))
                {
                    Proxy.git_diff_merge(diff, diff2);
                }

                return(diff);
            };

            return(comparisonHandleRetriever);
        }
Example #7
0
        internal PatchStats(DiffSafeHandle diff)
        {
            int count = Proxy.git_diff_num_deltas(diff);

            for (int i = 0; i < count; i++)
            {
                using (var patch = Proxy.git_patch_from_diff(diff, i))
                {
                    var delta       = Proxy.git_diff_get_delta(diff, i);
                    var pathPtr     = delta.NewFile.Path != IntPtr.Zero ? delta.NewFile.Path : delta.OldFile.Path;
                    var newFilePath = LaxFilePathMarshaler.FromNative(pathPtr);

                    var stats   = Proxy.git_patch_line_stats(patch);
                    int added   = stats.Item1;
                    int deleted = stats.Item2;
                    changes.Add(newFilePath, new ContentChangeStats(added, deleted));
                    totalLinesAdded   += added;
                    totalLinesDeleted += deleted;
                }
            }
        }
        internal virtual T Compare <T>(
            DiffModifiers diffOptions,
            IEnumerable <string> paths = null,
            ExplicitPathsOptions explicitPathsOptions = null,
            CompareOptions compareOptions             = null) where T : class, IDiffResult
        {
            var comparer = WorkdirToIndex(repo);

            if (explicitPathsOptions != null)
            {
                diffOptions |= DiffModifiers.DisablePathspecMatch;

                if (explicitPathsOptions.ShouldFailOnUnmatchedPath || explicitPathsOptions.OnUnmatchedPath != null)
                {
                    diffOptions |= DiffModifiers.IncludeUnmodified;
                }
            }

            using (DiffSafeHandle diff = BuildDiffList(null, null, comparer, diffOptions, paths, explicitPathsOptions, compareOptions))
            {
                return(BuildDiffResult <T>(diff));
            }
        }
        /// <summary>
        /// Show changes between two <see cref="Tree"/>s.
        /// </summary>
        /// <param name="oldTree">The <see cref="Tree"/> you want to compare from.</param>
        /// <param name="newTree">The <see cref="Tree"/> you want to compare to.</param>
        /// <param name="paths">The list of paths (either files or directories) that should be compared.</param>
        /// <param name="explicitPathsOptions">
        /// If set, the passed <paramref name="paths"/> will be treated as explicit paths.
        /// Use these options to determine how unmatched explicit paths should be handled.
        /// </param>
        /// <param name="compareOptions">Additional options to define patch generation behavior.</param>
        /// <returns>A <see cref="TreeChanges"/> containing the changes between the <paramref name="oldTree"/> and the <paramref name="newTree"/>.</returns>
        public virtual T Compare <T>(Tree oldTree, Tree newTree, IEnumerable <string> paths, ExplicitPathsOptions explicitPathsOptions,
                                     CompareOptions compareOptions) where T : class, IDiffResult
        {
            var      comparer    = TreeToTree(repo);
            ObjectId oldTreeId   = oldTree != null ? oldTree.Id : null;
            ObjectId newTreeId   = newTree != null ? newTree.Id : null;
            var      diffOptions = DiffModifiers.None;

            if (explicitPathsOptions != null)
            {
                diffOptions |= DiffModifiers.DisablePathspecMatch;

                if (explicitPathsOptions.ShouldFailOnUnmatchedPath || explicitPathsOptions.OnUnmatchedPath != null)
                {
                    diffOptions |= DiffModifiers.IncludeUnmodified;
                }
            }

            using (DiffSafeHandle diff = BuildDiffList(oldTreeId, newTreeId, comparer, diffOptions, paths, explicitPathsOptions, compareOptions))
            {
                return(BuildDiffResult <T>(diff));
            }
        }
Example #10
0
        /// <summary>
        /// Show changes between a <see cref="Tree"/> and the Index, the Working Directory, or both.
        /// <para>
        /// The level of diff performed can be specified by passing either a <see cref="TreeChanges"/>
        /// or <see cref="Patch"/> type as the generic parameter.
        /// </para>
        /// </summary>
        /// <param name="oldTree">The <see cref="Tree"/> to compare from.</param>
        /// <param name="diffTargets">The targets to compare to.</param>
        /// <param name="paths">The list of paths (either files or directories) that should be compared.</param>
        /// <param name="explicitPathsOptions">
        /// If set, the passed <paramref name="paths"/> will be treated as explicit paths.
        /// Use these options to determine how unmatched explicit paths should be handled.
        /// </param>
        /// <param name="compareOptions">Additional options to define patch generation behavior.</param>
        /// <typeparam name="T">Can be either a <see cref="TreeChanges"/> if you are only interested in the list of files modified, added, ..., or
        /// a <see cref="Patch"/> if you want the actual patch content for the whole diff and for individual files.</typeparam>
        /// <returns>A <typeparamref name="T"/> containing the changes between the <see cref="Tree"/> and the selected target.</returns>
        public virtual T Compare <T>(Tree oldTree, DiffTargets diffTargets, IEnumerable <string> paths = null,
                                     ExplicitPathsOptions explicitPathsOptions = null, CompareOptions compareOptions = null) where T : class
        {
            Func <DiffSafeHandle, object> builder;

            if (!ChangesBuilders.TryGetValue(typeof(T), out builder))
            {
                throw new LibGit2SharpException(string.Format(CultureInfo.InvariantCulture,
                                                              "Unexpected type '{0}' passed to Compare. Supported values are either '{1}' or '{2}'.", typeof(T),
                                                              typeof(TreeChanges), typeof(Patch)));
            }

            var      comparer  = HandleRetrieverDispatcher[diffTargets](repo);
            ObjectId oldTreeId = oldTree != null ? oldTree.Id : null;

            DiffModifiers diffOptions = diffTargets.HasFlag(DiffTargets.WorkingDirectory)
                ? DiffModifiers.IncludeUntracked
                : DiffModifiers.None;

            if (explicitPathsOptions != null)
            {
                diffOptions |= DiffModifiers.DisablePathspecMatch;

                if (explicitPathsOptions.ShouldFailOnUnmatchedPath ||
                    explicitPathsOptions.OnUnmatchedPath != null)
                {
                    diffOptions |= DiffModifiers.IncludeUnmodified;
                }
            }

            using (DiffSafeHandle diff = BuildDiffList(oldTreeId, null, comparer,
                                                       diffOptions, paths, explicitPathsOptions, compareOptions))
            {
                return((T)builder(diff));
            }
        }
Example #11
0
        private static void DetectRenames(DiffSafeHandle diffList, CompareOptions compareOptions)
        {
            var similarityOptions = (compareOptions == null) ? null : compareOptions.Similarity;

            if (similarityOptions == null ||
                similarityOptions.RenameDetectionMode == RenameDetectionMode.Default)
            {
                Proxy.git_diff_find_similar(diffList, null);
                return;
            }

            if (similarityOptions.RenameDetectionMode == RenameDetectionMode.None)
            {
                return;
            }

            var opts = new GitDiffFindOptions
            {
                RenameThreshold            = (ushort)similarityOptions.RenameThreshold,
                RenameFromRewriteThreshold = (ushort)similarityOptions.RenameFromRewriteThreshold,
                CopyThreshold         = (ushort)similarityOptions.CopyThreshold,
                BreakRewriteThreshold = (ushort)similarityOptions.BreakRewriteThreshold,
                RenameLimit           = (UIntPtr)similarityOptions.RenameLimit,
            };

            switch (similarityOptions.RenameDetectionMode)
            {
            case RenameDetectionMode.Exact:
                opts.Flags = GitDiffFindFlags.GIT_DIFF_FIND_EXACT_MATCH_ONLY |
                             GitDiffFindFlags.GIT_DIFF_FIND_RENAMES |
                             GitDiffFindFlags.GIT_DIFF_FIND_COPIES |
                             GitDiffFindFlags.GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED;
                break;

            case RenameDetectionMode.Renames:
                opts.Flags = GitDiffFindFlags.GIT_DIFF_FIND_RENAMES;
                break;

            case RenameDetectionMode.Copies:
                opts.Flags = GitDiffFindFlags.GIT_DIFF_FIND_RENAMES |
                             GitDiffFindFlags.GIT_DIFF_FIND_COPIES;
                break;

            case RenameDetectionMode.CopiesHarder:
                opts.Flags = GitDiffFindFlags.GIT_DIFF_FIND_RENAMES |
                             GitDiffFindFlags.GIT_DIFF_FIND_COPIES |
                             GitDiffFindFlags.GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED;
                break;
            }

            if (!compareOptions.IncludeUnmodified)
            {
                opts.Flags |= GitDiffFindFlags.GIT_DIFF_FIND_REMOVE_UNMODIFIED;
            }

            switch (similarityOptions.WhitespaceMode)
            {
            case WhitespaceMode.DontIgnoreWhitespace:
                opts.Flags |= GitDiffFindFlags.GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE;
                break;

            case WhitespaceMode.IgnoreLeadingWhitespace:
                opts.Flags |= GitDiffFindFlags.GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE;
                break;

            case WhitespaceMode.IgnoreAllWhitespace:
                opts.Flags |= GitDiffFindFlags.GIT_DIFF_FIND_IGNORE_WHITESPACE;
                break;
            }

            Proxy.git_diff_find_similar(diffList, opts);
        }
Example #12
0
 internal TreeChanges(DiffSafeHandle diff)
 {
     Proxy.git_diff_foreach(diff, FileCallback, null, null);
 }