/// <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)); } }
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)); } }
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); }
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)); }
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); } } }
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); }
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)); } }
/// <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)); } }
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); }
internal TreeChanges(DiffSafeHandle diff) { Proxy.git_diff_foreach(diff, FileCallback, null, null); }