diff options
Diffstat (limited to 'main/src/addins/VersionControl/MonoDevelop.VersionControl.Git')
6 files changed, 103 insertions, 374 deletions
diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/Makefile.am b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/Makefile.am index cb55a46f07..e9b0e461f2 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/Makefile.am +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/Makefile.am @@ -39,6 +39,7 @@ FILES = \ MonoDevelop.VersionControl.Git/CredentialsDialog.cs \ MonoDevelop.VersionControl.Git/EditBranchDialog.cs \ MonoDevelop.VersionControl.Git/EditRemoteDialog.cs \ + MonoDevelop.VersionControl.Git/FilteredStatus.cs \ MonoDevelop.VersionControl.Git/GitClient.cs \ MonoDevelop.VersionControl.Git/GitCommitDialogExtension.cs \ MonoDevelop.VersionControl.Git/GitCommitDialogExtensionWidget.cs \ @@ -55,7 +56,6 @@ FILES = \ MonoDevelop.VersionControl.Git/MergeDialog.cs \ MonoDevelop.VersionControl.Git/NewStashDialog.cs \ MonoDevelop.VersionControl.Git/PushDialog.cs \ - MonoDevelop.VersionControl.Git/RepositoryStatus.cs \ MonoDevelop.VersionControl.Git/Stash.cs \ MonoDevelop.VersionControl.Git/StashManagerDialog.cs \ MonoDevelop.VersionControl.Git/UserInfoConflictDialog.cs diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git.csproj b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git.csproj index efa8752a70..638d825b17 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git.csproj +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git.csproj @@ -61,7 +61,6 @@ <Compile Include="gtk-gui\MonoDevelop.VersionControl.Git.EditRemoteDialog.cs" /> <Compile Include="gtk-gui\MonoDevelop.VersionControl.Git.MergeDialog.cs" /> <Compile Include="MonoDevelop.VersionControl.Git\Change.cs" /> - <Compile Include="MonoDevelop.VersionControl.Git\RepositoryStatus.cs" /> <Compile Include="MonoDevelop.VersionControl.Git\MergeDialog.cs" /> <Compile Include="MonoDevelop.VersionControl.Git\Stash.cs" /> <Compile Include="MonoDevelop.VersionControl.Git\GitUtil.cs" /> @@ -79,6 +78,7 @@ <Compile Include="gtk-gui\MonoDevelop.VersionControl.Git.GitCommitDialogExtensionWidget.cs" /> <Compile Include="MonoDevelop.VersionControl.Git\GitCommitDialogExtension.cs" /> <Compile Include="MonoDevelop.VersionControl.Git\GitSupportFeature.cs" /> + <Compile Include="MonoDevelop.VersionControl.Git\FilteredStatus.cs" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\..\core\MonoDevelop.Core\MonoDevelop.Core.csproj"> diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/FilteredStatus.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/FilteredStatus.cs new file mode 100644 index 0000000000..7099028d12 --- /dev/null +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/FilteredStatus.cs @@ -0,0 +1,80 @@ +// +// SpecificStatus.cs +// +// Author: +// Alan McGovern <alan@xamarin.com> +// +// Copyright (c) 2012 Xamarin Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; + +using NGit; +using NGit.Treewalk; +using NGit.Treewalk.Filter; + +namespace MonoDevelop.VersionControl.Git +{ + class FilteredStatus : NGit.Api.StatusCommand + { + WorkingTreeIterator iter; + + IEnumerable<string> Files { + get; set; + } + + public FilteredStatus (NGit.Repository repository) + : base (repository) + { + + } + + public FilteredStatus (NGit.Repository repository, IEnumerable<string> files) + : base (repository) + { + Files = files; + } + + public override NGit.Api.StatusCommand SetWorkingTreeIt (WorkingTreeIterator workingTreeIt) + { + iter = workingTreeIt; + return this; + } + + public override NGit.Api.Status Call () + { + if (iter == null) + iter = new FileTreeIterator(repo); + + IndexDiff diff = new IndexDiff(repo, Constants.HEAD, iter); + if (Files != null) { + var filters = Files.Where (f => f != ".").ToArray (); + if (filters.Length > 0) + diff.SetFilter (PathFilterGroup.CreateFromStrings (filters)); + } + + diff.Diff (); + return new NGit.Api.Status(diff); + } + } +} + diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs index 2850a1f95c..45ade91b23 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitRepository.cs @@ -266,12 +266,18 @@ namespace MonoDevelop.VersionControl.Git else rev = null; - RepositoryStatus status; - if (localFileNames != null) - status = GitUtil.GetFileStatus (repo, localFileNames); - else - status = GitUtil.GetDirectoryStatus (repo, localDirectory, recursive); - + IEnumerable<string> paths; + if (localFileNames == null) { + if (recursive) + paths = new [] { (string) localDirectory }; + else + paths = Directory.GetFiles (localDirectory); + } else { + paths = localFileNames.Select (f => (string)f); + } + paths = paths.Select (f => ToGitPath (f)); + + var status = new FilteredStatus (repo, paths).Call (); HashSet<string> added = new HashSet<string> (); Action<IEnumerable<string>, VersionStatus> AddFiles = delegate(IEnumerable<string> files, VersionStatus fstatus) { foreach (string file in files) { @@ -284,13 +290,14 @@ namespace MonoDevelop.VersionControl.Git } }; - AddFiles (status.Added, VersionStatus.Versioned | VersionStatus.ScheduledAdd); - AddFiles (status.Modified, VersionStatus.Versioned | VersionStatus.Modified); - AddFiles (status.Removed, VersionStatus.Versioned | VersionStatus.ScheduledDelete); - AddFiles (status.Missing, VersionStatus.Versioned | VersionStatus.ScheduledDelete); - AddFiles (status.MergeConflict, VersionStatus.Versioned | VersionStatus.Conflicted); - AddFiles (status.Untracked, VersionStatus.Unversioned); - + AddFiles (status.GetAdded (), VersionStatus.Versioned | VersionStatus.ScheduledAdd); + AddFiles (status.GetChanged (), VersionStatus.Versioned | VersionStatus.Modified); + AddFiles (status.GetModified (), VersionStatus.Versioned | VersionStatus.Modified); + AddFiles (status.GetRemoved (), VersionStatus.Versioned | VersionStatus.ScheduledDelete); + AddFiles (status.GetMissing (), VersionStatus.Versioned | VersionStatus.ScheduledDelete); + AddFiles (status.GetConflicting (), VersionStatus.Versioned | VersionStatus.Conflicted); + AddFiles (status.GetUntracked (), VersionStatus.Unversioned); + // Existing files for which git did not report an status are supposed to be tracked foreach (FilePath file in existingFiles) { VersionInfo vi = new VersionInfo (file, "", false, VersionStatus.Versioned, rev, VersionStatus.Versioned, null); diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitUtil.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitUtil.cs index 8f9912e4ec..367faeac92 100644 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitUtil.cs +++ b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/GitUtil.cs @@ -164,17 +164,7 @@ namespace MonoDevelop.VersionControl.Git } } } - - public static RepositoryStatus GetDirectoryStatus (NGit.Repository repo, string dir, bool recursive) - { - return new RepositoryStatus (repo, null, repo.ToGitPath (dir), recursive); - } - - public static RepositoryStatus GetFileStatus (NGit.Repository repo, IEnumerable<FilePath> fileNames) - { - return new RepositoryStatus (repo, repo.ToGitPath (fileNames), null, false); - } - + public static ObjectId CreateCommit (NGit.Repository rep, string message, IList<ObjectId> parents, ObjectId indexTreeId, PersonIdent author, PersonIdent committer) { try { diff --git a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/RepositoryStatus.cs b/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/RepositoryStatus.cs deleted file mode 100644 index 43d216dbba..0000000000 --- a/main/src/addins/VersionControl/MonoDevelop.VersionControl.Git/MonoDevelop.VersionControl.Git/RepositoryStatus.cs +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com> - * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2010, Henon <meinrad.recheis@gmail.com> - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * - Neither the name of the Git Development Community nor the - * names of its contributors may be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Linq; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using NGit; -using NGit.Revwalk; -using NGit.Treewalk; -using NGit.Dircache; -using NGit.Treewalk.Filter; - -namespace MonoDevelop.VersionControl.Git -{ - class SpecificStatus : NGit.Api.StatusCommand - { - WorkingTreeIterator iter; - IEnumerable<string> Files { - get; set; - } - - public SpecificStatus (NGit.Repository repository) - : base (repository) - { - } - - public SpecificStatus (NGit.Repository repository, IEnumerable<string> files) - : base (repository) - { - Files = files; - } - - public override NGit.Api.StatusCommand SetWorkingTreeIt (WorkingTreeIterator workingTreeIt) - { - iter = workingTreeIt; - return this; - } - - public override NGit.Api.Status Call () - { - if (iter == null) - iter = new FileTreeIterator(repo); - - IndexDiff diff = new IndexDiff(repo, Constants.HEAD, iter); - if (Files != null) { - var filters = Files.Select (PathFilter.Create).ToArray (); - if (filters.Length > 1) - diff.SetFilter (OrTreeFilter.Create (filters)); - else - diff.SetFilter (filters [0]); - } - - diff.Diff (); - return new NGit.Api.Status(diff); - } - } - - public class RepositoryStatus - { - private string _root_path; - private bool _recursive; - private IEnumerable<string> _file_paths; - private bool changesExist; - - internal RepositoryStatus(NGit.Repository repository, IEnumerable<string> singleFiles, string rootDir, bool recursive) - { - Repository = repository; - _root_path = rootDir; - _recursive = recursive; - _file_paths = singleFiles; - Update(); - } - - public NGit.Repository Repository - { - get; - private set; - } - - public bool ChangesExist { - get { return changesExist; } - } - - /// <summary> - /// List of files added to the index, which are not in the current commit - /// </summary> - public HashSet<string> Added { get; private set; } - - /// <summary> - /// List of files added to the index, which are already in the current commit with different content - /// </summary> - public HashSet<string> Staged { get; private set; } - - /// <summary> - /// List of files removed from the index but are existent in the current commit - /// </summary> - public HashSet<string> Removed { get; private set; } - - /// <summary> - /// List of files existent in the index but are missing in the working directory - /// </summary> - public HashSet<string> Missing { get; private set; } - - /// <summary> - /// List of files with unstaged modifications. A file may be modified and staged at the same time if it has been modified after adding. - /// </summary> - public HashSet<string> Modified { get; private set; } - - /// <summary> - /// List of files existing in the working directory but are neither tracked in the index nor in the current commit. - /// </summary> - public HashSet<string> Untracked { get; private set; } - - /// <summary> - /// List of files with staged modifications that conflict. - /// </summary> - public HashSet<string> MergeConflict { get; private set; } - - ///// <summary> - ///// Returns the number of files checked into the git repository - ///// </summary> - //public int IndexSize { get { return _index.Members.Count; } } - - public bool AnyDifferences { get; private set; } - - /// <summary> - /// Recalculates the status - /// </summary> - public void Update() - { - AnyDifferences = false; - Added = new HashSet<string>(); - Staged = new HashSet<string>(); - Removed = new HashSet<string>(); - Missing = new HashSet<string>(); - Modified = new HashSet<string>(); - Untracked = new HashSet<string>(); - MergeConflict = new HashSet<string>(); - - if (_file_paths != null) - UpdateSingleFiles (_file_paths.ToList ()); - else if (_recursive) - UpdateDirectory (new string[] { _root_path }, true); - else - UpdateDirectory (new string[] { _root_path }, false); - } - - void UpdateSingleFiles (List<string> singleFiles) - { - // NGIT HACK: We verify that all the files listed in the result of - // the GitStatus call are actually in the list of files we're interested - // in. This is because NGit cannot properly filter the git tree and - // incorrectly includes extra directories. See bug # - var status = new SpecificStatus (Repository, singleFiles).Call (); - - foreach (var v in status.GetAdded ()) - if (singleFiles.Contains (v)) - Added.Add (v); - - foreach (var v in status.GetChanged ()) - if (singleFiles.Contains (v)) - Modified.Add (v); - - foreach (var v in status.GetConflicting ()) - if (singleFiles.Contains (v)) - MergeConflict.Add (v); - - foreach (var v in status.GetMissing ()) - if (singleFiles.Contains (v)) - Missing.Add (v); - - foreach (var v in status.GetModified ()) - if (singleFiles.Contains (v)) - Modified.Add (v); - - foreach (var v in status.GetRemoved ()) - if (singleFiles.Contains (v)) - Removed.Add (v); - - foreach (var v in status.GetUntracked ()) - if (singleFiles.Contains (v)) - Untracked.Add (v); - } - - /// <summary> - /// Run the diff operation. Until this is called, all lists will be empty - /// </summary> - /// <returns>true if anything is different between index, tree, and workdir</returns> - private void UpdateDirectory (IEnumerable<string> paths, bool recursive) - { - RevWalk rw = new RevWalk (Repository); - ObjectId id = Repository.Resolve (Constants.HEAD); - var commit = id != null ? rw.ParseCommit (id) : null; - - TreeWalk treeWalk = new TreeWalk (Repository); - treeWalk.Reset (); - treeWalk.Recursive = recursive; - - if (commit != null) - treeWalk.AddTree (commit.Tree); - else - treeWalk.AddTree (new EmptyTreeIterator()); - - DirCache dc = Repository.ReadDirCache (); - treeWalk.AddTree (new DirCacheIterator (dc)); - - FileTreeIterator workTree = new FileTreeIterator (Repository.WorkTree, Repository.FileSystem, WorkingTreeOptions.KEY.Parse(Repository.GetConfig())); - treeWalk.AddTree (workTree); - - List<TreeFilter> filters = new List<TreeFilter> (); - filters.Add (new SkipWorkTreeFilter(1)); - - var pathFilters = paths.Where (p => p != ".").Select (p => PathFilter.Create (p)).ToArray (); - if (pathFilters.Length > 1) { - filters.Add (OrTreeFilter.Create (pathFilters)); // Use an OR to join all path filters - } else if (pathFilters.Length == 1) - filters.Add (pathFilters[0]); - - if (filters.Count > 1) - treeWalk.Filter = AndTreeFilter.Create(filters); - else - treeWalk.Filter = filters[0]; - - while (treeWalk.Next()) - { - AbstractTreeIterator treeIterator = treeWalk.GetTree<AbstractTreeIterator>(0); - DirCacheIterator dirCacheIterator = treeWalk.GetTree<DirCacheIterator>(1); - WorkingTreeIterator workingTreeIterator = treeWalk.GetTree<WorkingTreeIterator>(2); - NGit.FileMode fileModeTree = treeWalk.GetFileMode(0); - - if (treeWalk.IsSubtree) { - treeWalk.EnterSubtree (); - continue; - } - - int stage = dirCacheIterator != null ? dirCacheIterator.GetDirCacheEntry ().Stage : 0; - if (stage > 1) - continue; - else if (stage == 1) { - MergeConflict.Add(dirCacheIterator.EntryPathString); - changesExist = true; - continue; - } - - if (treeIterator != null) - { - if (dirCacheIterator != null) - { - if (!treeIterator.EntryObjectId.Equals(dirCacheIterator.EntryObjectId)) - { - // in repo, in index, content diff => changed - Modified.Add(dirCacheIterator.EntryPathString); - changesExist = true; - } - } - else - { - // in repo, not in index => removed - if (!fileModeTree.Equals(NGit.FileMode.TYPE_TREE)) - { - Removed.Add(treeIterator.EntryPathString); - changesExist = true; - } - } - } - else - { - if (dirCacheIterator != null) - { - // not in repo, in index => added - Added.Add(dirCacheIterator.EntryPathString); - changesExist = true; - } - else - { - // not in repo, not in index => untracked - if (workingTreeIterator != null && !workingTreeIterator.IsEntryIgnored()) - { - Untracked.Add(workingTreeIterator.EntryPathString); - changesExist = true; - } - } - } - if (dirCacheIterator != null) - { - if (workingTreeIterator == null) - { - // in index, not in workdir => missing - Missing.Add(dirCacheIterator.EntryPathString); - changesExist = true; - } - else - { - // Workaround to file time resolution issues - long itime = dirCacheIterator.GetDirCacheEntry ().LastModified; - long ftime = workingTreeIterator.GetEntryLastModified (); - if (itime / 1000 != ftime / 1000) { - if (!dirCacheIterator.IdEqual(workingTreeIterator)) - { - // in index, in workdir, content differs => modified - Modified.Add(dirCacheIterator.EntryPathString); - changesExist = true; - } - } - } - } - } - } - } -} |