Esempio n. 1
0
        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;
                }
            }

            DiffHandle diff = BuildDiffList(null, null, comparer, diffOptions, paths, explicitPathsOptions, compareOptions);

            try
            {
                return(BuildDiffResult <T>(diff));
            }
            catch
            {
                diff.SafeDispose();
                throw;
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Removes from the staging area all the modifications of a file since the latest commit (addition, updation or removal).
        /// </summary>
        /// <param name="repository">The repository in which to act</param>
        /// <param name="path">The path of the file within the working directory.</param>
        /// <param name="explicitPathsOptions">
        /// The passed <paramref name="path"/> will be treated as explicit paths.
        /// Use these options to determine how unmatched explicit paths should be handled.
        /// </param>
        public static void Unstage(IRepository repository, string path, ExplicitPathsOptions explicitPathsOptions)
        {
            Ensure.ArgumentNotNull(repository, "repository");
            Ensure.ArgumentNotNull(path, "path");

            Unstage(repository, new[] { path }, explicitPathsOptions);
        }
Esempio n. 3
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,
                                     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;
                }
            }

            DiffHandle diff = BuildDiffList(oldTreeId, null, comparer, diffOptions, paths, explicitPathsOptions, compareOptions);

            try
            {
                return(BuildDiffResult <T>(diff));
            }
            catch
            {
                diff.SafeDispose();
                throw;
            }
        }
Esempio n. 4
0
 /// <summary>
 /// Show changes between the working directory and the index.
 /// <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="paths">The list of paths (either files or directories) that should be compared.</param>
 /// <param name="includeUntracked">If true, include untracked files from the working dir as additions. Otherwise ignore them.</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 working directory and the index.</returns>
 public virtual T Compare <T>(
     IEnumerable <string> paths,
     bool includeUntracked,
     ExplicitPathsOptions explicitPathsOptions,
     CompareOptions compareOptions) where T : class, IDiffResult
 {
     return(Compare <T>(includeUntracked ? DiffModifiers.IncludeUntracked : DiffModifiers.None, paths, explicitPathsOptions, compareOptions));
 }
Esempio n. 5
0
        /// <summary>
        /// Replaces entries in the <see cref="Index"/> with entries from the specified <see cref="Commit"/>.
        /// </summary>
        /// <param name="commit">The target <see cref="Commit"/> object.</param>
        /// <param name="paths">The list of paths (either files or directories) that should be considered.</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>
        public virtual void Replace(Commit commit, IEnumerable <string> paths, ExplicitPathsOptions explicitPathsOptions)
        {
            Ensure.ArgumentNotNull(commit, "commit");

            using (var changes = repo.Diff.Compare <TreeChanges>(commit.Tree, DiffTargets.Index, paths, explicitPathsOptions, new CompareOptions {
                Similarity = SimilarityOptions.None
            }))
            {
                Replace(changes);
            }
        }
Esempio n. 6
0
        private DiffHandle BuildDiffList(
            ObjectId oldTreeId,
            ObjectId newTreeId,
            TreeComparisonHandleRetriever comparisonHandleRetriever,
            DiffModifiers diffOptions,
            IEnumerable <string> paths,
            ExplicitPathsOptions explicitPathsOptions,
            CompareOptions compareOptions)
        {
            var filePaths = repo.ToFilePaths(paths);

            MatchedPathsAggregator matchedPaths = null;

            // We can't match paths unless we've got something to match
            // against and we're told to do so.
            if (filePaths != null && explicitPathsOptions != null)
            {
                if (explicitPathsOptions.OnUnmatchedPath != null || explicitPathsOptions.ShouldFailOnUnmatchedPath)
                {
                    matchedPaths = new MatchedPathsAggregator();
                }
            }

            using (GitDiffOptions options = BuildOptions(diffOptions, filePaths, matchedPaths, compareOptions))
            {
                var diffList = comparisonHandleRetriever(oldTreeId, newTreeId, options);

                if (matchedPaths != null)
                {
                    try
                    {
                        DispatchUnmatchedPaths(explicitPathsOptions, filePaths, matchedPaths);
                    }
                    catch
                    {
                        diffList.Dispose();
                        throw;
                    }
                }

                DetectRenames(diffList, compareOptions);

                return(diffList);
            }
        }
Esempio n. 7
0
        private static void DispatchUnmatchedPaths(
            ExplicitPathsOptions explicitPathsOptions,
            IEnumerable <FilePath> filePaths,
            IEnumerable <FilePath> matchedPaths)
        {
            List <FilePath> unmatchedPaths = (filePaths != null ?
                                              filePaths.Except(matchedPaths) : Enumerable.Empty <FilePath>()).ToList();

            if (!unmatchedPaths.Any())
            {
                return;
            }

            if (explicitPathsOptions.OnUnmatchedPath != null)
            {
                unmatchedPaths.ForEach(filePath => explicitPathsOptions.OnUnmatchedPath(filePath.Native));
            }

            if (explicitPathsOptions.ShouldFailOnUnmatchedPath)
            {
                throw new UnmatchedPathException(BuildUnmatchedPathsMessage(unmatchedPaths));
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Promotes to the staging area the latest modifications of a collection of files in the working directory (addition, updation or removal).
        ///
        /// Any paths (even those listed explicitly) that are ignored by configuration will not be staged unless <see cref="StageOptions.IncludeIgnored"/> is unset.
        /// </summary>
        /// <param name="repository">The repository in which to act</param>
        /// <param name="paths">The collection of paths of the files within the working directory.</param>
        /// <param name="stageOptions">Determines how paths will be staged.</param>
        public static void Stage(IRepository repository, IEnumerable <string> paths, StageOptions stageOptions)
        {
            Ensure.ArgumentNotNull(repository, "repository");
            Ensure.ArgumentNotNull(paths, "paths");

            DiffModifiers        diffModifiers        = DiffModifiers.IncludeUntracked;
            ExplicitPathsOptions explicitPathsOptions = stageOptions != null ? stageOptions.ExplicitPathsOptions : null;

            if (stageOptions != null && stageOptions.IncludeIgnored)
            {
                diffModifiers |= DiffModifiers.IncludeIgnored;
            }

            using (var changes = repository.Diff.Compare <TreeChanges>(diffModifiers, paths, explicitPathsOptions,
                                                                       new CompareOptions {
                Similarity = SimilarityOptions.None
            }))
            {
                var unexpectedTypesOfChanges = changes
                                               .Where(
                    tec => tec.Status != ChangeKind.Added &&
                    tec.Status != ChangeKind.Modified &&
                    tec.Status != ChangeKind.Conflicted &&
                    tec.Status != ChangeKind.Unmodified &&
                    tec.Status != ChangeKind.Deleted).ToList();

                if (unexpectedTypesOfChanges.Count > 0)
                {
                    throw new InvalidOperationException(
                              string.Format(CultureInfo.InvariantCulture,
                                            "Entry '{0}' bears an unexpected ChangeKind '{1}'",
                                            unexpectedTypesOfChanges[0].Path, unexpectedTypesOfChanges[0].Status));
                }

                /* Remove files from the index that don't exist on disk */
                foreach (TreeEntryChanges treeEntryChanges in changes)
                {
                    switch (treeEntryChanges.Status)
                    {
                    case ChangeKind.Conflicted:
                        if (!treeEntryChanges.Exists)
                        {
                            repository.Index.Remove(treeEntryChanges.Path);
                        }
                        break;

                    case ChangeKind.Deleted:
                        repository.Index.Remove(treeEntryChanges.Path);
                        break;

                    default:
                        continue;
                    }
                }

                foreach (TreeEntryChanges treeEntryChanges in changes)
                {
                    switch (treeEntryChanges.Status)
                    {
                    case ChangeKind.Added:
                    case ChangeKind.Modified:
                        repository.Index.Add(treeEntryChanges.Path);
                        break;

                    case ChangeKind.Conflicted:
                        if (treeEntryChanges.Exists)
                        {
                            repository.Index.Add(treeEntryChanges.Path);
                        }
                        break;

                    default:
                        continue;
                    }
                }

                repository.Index.Write();
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Removes from the staging area all the modifications of a collection of file since the latest commit (addition, updation or removal).
        /// </summary>
        /// <param name="repository">The repository in which to act</param>
        /// <param name="paths">The collection of paths of the files within the working directory.</param>
        /// <param name="explicitPathsOptions">
        /// The passed <paramref name="paths"/> will be treated as explicit paths.
        /// Use these options to determine how unmatched explicit paths should be handled.
        /// </param>
        public static void Unstage(IRepository repository, IEnumerable <string> paths, ExplicitPathsOptions explicitPathsOptions)
        {
            Ensure.ArgumentNotNull(repository, "repository");
            Ensure.ArgumentNotNull(paths, "paths");

            if (repository.Info.IsHeadUnborn)
            {
                using (var changes = repository.Diff.Compare <TreeChanges>(null, DiffTargets.Index, paths, explicitPathsOptions, new CompareOptions {
                    Similarity = SimilarityOptions.None
                }))
                    repository.Index.Replace(changes);
            }
            else
            {
                repository.Index.Replace(repository.Head.Tip, paths, explicitPathsOptions);
            }

            repository.Index.Write();
        }
Esempio n. 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>
 /// <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) where T : class, IDiffResult
 {
     return(Compare <T>(oldTree, diffTargets, paths, explicitPathsOptions, null));
 }
Esempio n. 11
0
        /// <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;
                }
            }

            DiffHandle diff = BuildDiffList(oldTreeId, newTreeId, comparer, diffOptions, paths, explicitPathsOptions, compareOptions);

            try
            {
                return(BuildDiffResult <T>(diff));
            }
            catch
            {
                diff.SafeDispose();
                throw;
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Removes a file from the staging area, and optionally removes it from the working directory as well.
        /// <para>
        ///   If the file has already been deleted from the working directory, this method will only deal
        ///   with promoting the removal to the staging area.
        /// </para>
        /// <para>
        ///   The default behavior is to remove the file from the working directory as well.
        /// </para>
        /// <para>
        ///   When not passing a <paramref name="explicitPathsOptions"/>, the passed path will be treated as
        ///   a pathspec. You can for example use it to pass the relative path to a folder inside the working directory,
        ///   so that all files beneath this folders, and the folder itself, will be removed.
        /// </para>
        /// </summary>
        /// <param name="repository">The repository in which to operate</param>
        /// <param name="path">The path of the file within the working directory.</param>
        /// <param name="removeFromWorkingDirectory">True to remove the file from the working directory, False otherwise.</param>
        /// <param name="explicitPathsOptions">
        /// The passed <paramref name="path"/> will be treated as an explicit path.
        /// Use these options to determine how unmatched explicit paths should be handled.
        /// </param>
        public static void Remove(IRepository repository, string path, bool removeFromWorkingDirectory, ExplicitPathsOptions explicitPathsOptions)
        {
            Ensure.ArgumentNotNull(repository, "repository");
            Ensure.ArgumentNotNull(path, "path");

            Remove(repository, new[] { path }, removeFromWorkingDirectory, explicitPathsOptions);
        }
Esempio n. 13
0
        private static IEnumerable <string> RemoveStagedItems(IRepository repository, IEnumerable <string> paths, bool removeFromWorkingDirectory = true, ExplicitPathsOptions explicitPathsOptions = null)
        {
            var removed = new List <string>();

            using (var changes = repository.Diff.Compare <TreeChanges>(DiffModifiers.IncludeUnmodified | DiffModifiers.IncludeUntracked, paths, explicitPathsOptions))
            {
                var index = repository.Index;

                foreach (var treeEntryChanges in changes)
                {
                    var status = repository.RetrieveStatus(treeEntryChanges.Path);

                    switch (treeEntryChanges.Status)
                    {
                    case ChangeKind.Added:
                    case ChangeKind.Deleted:
                        removed.Add(treeEntryChanges.Path);
                        index.Remove(treeEntryChanges.Path);
                        break;

                    case ChangeKind.Unmodified:
                        if (removeFromWorkingDirectory && (
                                status.HasFlag(FileStatus.ModifiedInIndex) ||
                                status.HasFlag(FileStatus.NewInIndex)))
                        {
                            throw new RemoveFromIndexException("Unable to remove file '{0}', as it has changes staged in the index. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.",
                                                               treeEntryChanges.Path);
                        }
                        removed.Add(treeEntryChanges.Path);
                        index.Remove(treeEntryChanges.Path);
                        continue;

                    case ChangeKind.Modified:
                        if (status.HasFlag(FileStatus.ModifiedInWorkdir) && status.HasFlag(FileStatus.ModifiedInIndex))
                        {
                            throw new RemoveFromIndexException("Unable to remove file '{0}', as it has staged content different from both the working directory and the HEAD.",
                                                               treeEntryChanges.Path);
                        }
                        if (removeFromWorkingDirectory)
                        {
                            throw new RemoveFromIndexException("Unable to remove file '{0}', as it has local modifications. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.",
                                                               treeEntryChanges.Path);
                        }
                        removed.Add(treeEntryChanges.Path);
                        index.Remove(treeEntryChanges.Path);
                        continue;

                    default:
                        throw new RemoveFromIndexException("Unable to remove file '{0}'. Its current status is '{1}'.",
                                                           treeEntryChanges.Path,
                                                           treeEntryChanges.Status);
                    }
                }

                index.Write();

                return(removed);
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Removes a collection of fileS from the staging, and optionally removes them from the working directory as well.
        /// <para>
        ///   If a file has already been deleted from the working directory, this method will only deal
        ///   with promoting the removal to the staging area.
        /// </para>
        /// <para>
        ///   The default behavior is to remove the files from the working directory as well.
        /// </para>
        /// <para>
        ///   When not passing a <paramref name="explicitPathsOptions"/>, the passed paths will be treated as
        ///   a pathspec. You can for example use it to pass the relative paths to folders inside the working directory,
        ///   so that all files beneath these folders, and the folders themselves, will be removed.
        /// </para>
        /// </summary>
        /// <param name="repository">The repository in which to operate</param>
        /// <param name="paths">The collection of paths of the files within the working directory.</param>
        /// <param name="removeFromWorkingDirectory">True to remove the files from the working directory, False otherwise.</param>
        /// <param name="explicitPathsOptions">
        /// The passed <paramref name="paths"/> will be treated as explicit paths.
        /// Use these options to determine how unmatched explicit paths should be handled.
        /// </param>
        public static void Remove(IRepository repository, IEnumerable <string> paths, bool removeFromWorkingDirectory, ExplicitPathsOptions explicitPathsOptions)
        {
            Ensure.ArgumentNotNull(repository, "repository");
            Ensure.ArgumentNotNullOrEmptyEnumerable <string>(paths, "paths");

            var pathsToDelete      = paths.Where(p => Directory.Exists(Path.Combine(repository.Info.WorkingDirectory, p))).ToList();
            var notConflictedPaths = new List <string>();
            var index = repository.Index;

            foreach (var path in paths)
            {
                Ensure.ArgumentNotNullOrEmptyString(path, "path");

                var conflict = index.Conflicts[path];

                if (conflict != null)
                {
                    index.Remove(path);
                    pathsToDelete.Add(path);
                }
                else
                {
                    notConflictedPaths.Add(path);
                }
            }

            // Make sure status will see the changes from before this
            index.Write();

            if (notConflictedPaths.Count > 0)
            {
                pathsToDelete.AddRange(RemoveStagedItems(repository, notConflictedPaths, removeFromWorkingDirectory, explicitPathsOptions));
            }

            if (removeFromWorkingDirectory)
            {
                RemoveFilesAndFolders(repository, pathsToDelete);
            }

            index.Write();
        }