IEnumerable<IChange> GetAllChanges(string fromCommit, GitBasedFileSystemSnapshot toSnapshot, string[] paths) { var currentCommit = toSnapshot.Commit; var currentSnapshot = toSnapshot; // empty path filter => result is empty if (paths != null && !paths.Any()) { yield break; } // paths refers to file in the snapshot, we need to "translate" the paths to the paths in the git repository // assumes all paths are rooted var pathFilter = paths?.Select(p => GitBasedFileSystemSnapshot.SnapshotDirectoryName + p + FilePropertiesFile.FileNameSuffix).ToArray(); while (currentCommit.Sha != fromCommit) { var parentCommit = GetParentSnapshotCommit(currentCommit); // parent commit is initial commit if (parentCommit.Sha == m_Repository.GetInitialCommit().Sha) { var treeChanges = m_Repository.Diff.Compare<TreeChanges>(parentCommit.Tree, currentCommit.Tree, pathFilter, null, new CompareOptions() { IncludeUnmodified = false }); // build changes foreach (var change in GetChanges(treeChanges, null, currentSnapshot)) { yield return change; } // there won't be any commit after this (we already reached the inital commit) // => abort the loop break; } else { var parentSnapshot = GetSnapshot(parentCommit.Sha); var treeChanges = m_Repository.Diff.Compare<TreeChanges>(parentCommit.Tree, currentCommit.Tree, pathFilter, null, new CompareOptions() { IncludeUnmodified = false }); // build changes foreach(var change in GetChanges(treeChanges, parentSnapshot, currentSnapshot)) { yield return change; } currentCommit = parentCommit; currentSnapshot = parentSnapshot; } } }
IEnumerable<IChange> GetChanges(TreeChanges treeChanges, GitBasedFileSystemSnapshot fromSnapshot, GitBasedFileSystemSnapshot toSnapshot) { foreach (var treeChange in treeChanges.Where(c => !IgnoreTreeChange(c))) { switch (treeChange.Status) { case ChangeKind.Unmodified: throw new InvalidOperationException("Unmodified changes should have been filtered out"); case ChangeKind.Modified: var fromFile = fromSnapshot.GetFileForGitPath(treeChange.Path); var toFile = toSnapshot.GetFileForGitPath(treeChange.Path); yield return new Change(ChangeType.Modified, fromFile.ToReference(), toFile.ToReference()); break; case ChangeKind.Added: yield return new Change(ChangeType.Added, null, toSnapshot.GetFileForGitPath(treeChange.Path).ToReference()); break; case ChangeKind.Deleted: yield return new Change(ChangeType.Deleted, fromSnapshot.GetFileForGitPath(treeChange.Path).ToReference(), null); break; default: throw new NotImplementedException(); } } }
IEnumerable<ChangeList> GetChangeLists(string fromCommit, GitBasedFileSystemSnapshot toSnapshot, string[] paths) { var changeLists = GetAllChanges(fromCommit, toSnapshot, paths) .GroupBy(change => change.Path, StringComparer.InvariantCultureIgnoreCase) .Select(group => new ChangeList(group.Reverse())); return changeLists; }