public void CanCreateABlobIntoTheDatabaseOfABareRepository() { string path = InitNewRepository(); SelfCleaningDirectory directory = BuildSelfCleaningDirectory(); string filepath = Touch(directory.RootedDirectoryPath, "hello.txt", "I'm a new file\n"); using (var repo = new Repository(path)) { /* * $ echo "I'm a new file" | git hash-object --stdin * dc53d4c6b8684c21b0b57db29da4a2afea011565 */ Assert.Null(repo.Lookup<Blob>("dc53d4c6b8684c21b0b57db29da4a2afea011565")); Blob blob = repo.ObjectDatabase.CreateBlob(filepath); Assert.NotNull(blob); Assert.Equal("dc53d4c6b8684c21b0b57db29da4a2afea011565", blob.Sha); Assert.Equal("I'm a new file\n", blob.GetContentText()); var fetchedBlob = repo.Lookup<Blob>(blob.Id); Assert.Equal(blob, fetchedBlob); } }
public void CanCreateABlobIntoTheDatabaseOfABareRepository() { TemporaryCloneOfTestRepo scd = BuildTemporaryCloneOfTestRepo(); SelfCleaningDirectory directory = BuildSelfCleaningDirectory(); Directory.CreateDirectory(directory.RootedDirectoryPath); string filepath = Path.Combine(directory.RootedDirectoryPath, "hello.txt"); File.WriteAllText(filepath, "I'm a new file\n"); using (var repo = new Repository(scd.RepositoryPath)) { /* * $ echo "I'm a new file" | git hash-object --stdin * dc53d4c6b8684c21b0b57db29da4a2afea011565 */ Assert.Null(repo.Lookup<Blob>("dc53d4c6b8684c21b0b57db29da4a2afea011565")); Blob blob = repo.ObjectDatabase.CreateBlob(filepath); Assert.NotNull(blob); Assert.Equal("dc53d4c6b8684c21b0b57db29da4a2afea011565", blob.Sha); Assert.Equal("I'm a new file\n", blob.ContentAsUtf8()); var fetchedBlob = repo.Lookup<Blob>(blob.Id); Assert.Equal(blob, fetchedBlob); } }
public void CanAddAndRemoveStash() { string path = SandboxStandardTestRepo(); using (var repo = new Repository(path)) { var stasher = Constants.Signature; Assert.True(repo.RetrieveStatus().IsDirty); Stash stash = repo.Stashes.Add(stasher, "My very first stash", StashModifiers.IncludeUntracked); // Check that untracked files are deleted from working directory string untrackedFilename = "new_untracked_file.txt"; Assert.False(File.Exists(Path.Combine(repo.Info.WorkingDirectory, untrackedFilename))); Assert.NotNull(stash.Untracked[untrackedFilename]); Assert.NotNull(stash); Assert.Equal("stash@{0}", stash.CanonicalName); Assert.Contains("My very first stash", stash.Message); var stashRef = repo.Refs["refs/stash"]; Assert.Equal(stash.WorkTree.Sha, stashRef.TargetIdentifier); Assert.False(repo.RetrieveStatus().IsDirty); // Create extra file untrackedFilename = "stash_candidate.txt"; Touch(repo.Info.WorkingDirectory, untrackedFilename, "Oh, I'm going to be stashed!\n"); Stash secondStash = repo.Stashes.Add(stasher, "My second stash", StashModifiers.IncludeUntracked); Assert.NotNull(stash); Assert.Equal("stash@{0}", stash.CanonicalName); Assert.Contains("My second stash", secondStash.Message); Assert.Equal(2, repo.Stashes.Count()); Assert.Equal("stash@{0}", repo.Stashes.First().CanonicalName); Assert.Equal("stash@{1}", repo.Stashes.Last().CanonicalName); Assert.NotNull(secondStash.Untracked[untrackedFilename]); // Stash history has been shifted Assert.Equal(repo.Lookup<Commit>("stash@{0}").Sha, secondStash.WorkTree.Sha); Assert.Equal(repo.Lookup<Commit>("stash@{1}").Sha, stash.WorkTree.Sha); //Remove one stash repo.Stashes.Remove(0); Assert.Equal(1, repo.Stashes.Count()); Stash newTopStash = repo.Stashes.First(); Assert.Equal("stash@{0}", newTopStash.CanonicalName); Assert.Equal(stash.WorkTree.Sha, newTopStash.WorkTree.Sha); // Stash history has been shifted Assert.Equal(stash.WorkTree.Sha, repo.Lookup<Commit>("stash").Sha); Assert.Equal(stash.WorkTree.Sha, repo.Lookup<Commit>("stash@{0}").Sha); } }
public void CanAddAndRemoveStash() { TemporaryCloneOfTestRepo path = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath); using (var repo = new Repository(path.RepositoryPath)) { var stasher = DummySignature; Assert.True(repo.Index.RetrieveStatus().IsDirty); Stash stash = repo.Stashes.Add(stasher, "My very first stash", StashOptions.IncludeUntracked); // Check that untracked files are deleted from working directory Assert.False(File.Exists(Path.Combine(repo.Info.WorkingDirectory, "new_untracked_file.txt"))); Assert.NotNull(stash); Assert.Equal("stash@{0}", stash.CanonicalName); Assert.Contains("My very first stash", stash.Message); var stashRef = repo.Refs["refs/stash"]; Assert.Equal(stash.Target.Sha, stashRef.TargetIdentifier); Assert.False(repo.Index.RetrieveStatus().IsDirty); // Create extra file string newFileFullPath = Path.Combine(repo.Info.WorkingDirectory, "stash_candidate.txt"); File.WriteAllText(newFileFullPath, "Oh, I'm going to be stashed!\n"); Stash secondStash = repo.Stashes.Add(stasher, "My second stash", StashOptions.IncludeUntracked); Assert.NotNull(stash); Assert.Equal("stash@{0}", stash.CanonicalName); Assert.Contains("My second stash", secondStash.Message); Assert.Equal(2, repo.Stashes.Count()); Assert.Equal("stash@{0}", repo.Stashes.First().CanonicalName); Assert.Equal("stash@{1}", repo.Stashes.Last().CanonicalName); // Stash history has been shifted Assert.Equal(repo.Lookup<Commit>("stash@{0}").Sha, secondStash.Target.Sha); Assert.Equal(repo.Lookup<Commit>("stash@{1}").Sha, stash.Target.Sha); //Remove one stash repo.Stashes.Remove("stash@{0}"); Assert.Equal(1, repo.Stashes.Count()); Stash newTopStash = repo.Stashes.First(); Assert.Equal("stash@{0}", newTopStash.CanonicalName); Assert.Equal(stash.Target.Sha, newTopStash.Target.Sha); // Stash history has been shifted Assert.Equal(stash.Target.Sha, repo.Lookup<Commit>("stash").Sha); Assert.Equal(stash.Target.Sha, repo.Lookup<Commit>("stash@{0}").Sha); } }
public void CanFindCommonAncestorForTwoCommitsAsEnumerable() { using (var repo = new Repository(BareTestRepoPath)) { var first = repo.Lookup<Commit>("c47800c7266a2be04c571c04d5a6614691ea99bd"); var second = repo.Lookup<Commit>("9fd738e8f7967c078dceed8190330fc8648ee56a"); Commit ancestor = repo.Commits.FindCommonAncestor(new[] { first, second }); Assert.NotNull(ancestor); ancestor.Id.Sha.ShouldEqual("5b5b025afb0b4c913b4c338a42934a3863bf3644"); } }
public void CanFindCommonAncestorForSeveralCommits() { using (var repo = new Repository(BareTestRepoPath)) { var first = repo.Lookup<Commit>("4c062a6361ae6959e06292c1fa5e2822d9c96345"); var second = repo.Lookup<Commit>("be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); var third = repo.Lookup<Commit>("c47800c7266a2be04c571c04d5a6614691ea99bd"); var fourth = repo.Lookup<Commit>("5b5b025afb0b4c913b4c338a42934a3863bf3644"); Commit ancestor = repo.Commits.FindCommonAncestor(new[] { first, second, third, fourth }); Assert.NotNull(ancestor); ancestor.Id.Sha.ShouldEqual("5b5b025afb0b4c913b4c338a42934a3863bf3644"); } }
public void CanCalculateHistoryDivergenceWhenNoAncestorIsShared( string sinceSha, string untilSha, int? expectedAheadBy, int? expectedBehindBy) { using (var repo = new Repository(BareTestRepoPath)) { var since = repo.Lookup<Commit>(sinceSha); var until = repo.Lookup<Commit>(untilSha); HistoryDivergence div = repo.ObjectDatabase.CalculateHistoryDivergence(since, until); Assert.Equal(expectedAheadBy, div.AheadBy); Assert.Equal(expectedBehindBy, div.BehindBy); Assert.Null(div.CommonAncestor); } }
public void CanAmendACommitWithMoreThanOneParent() { string path = CloneStandardTestRepo(); using (var repo = new Repository(path)) { var mergedCommit = repo.Lookup<Commit>("be3563a"); Assert.NotNull(mergedCommit); Assert.Equal(2, mergedCommit.Parents.Count()); repo.Reset(ResetOptions.Soft, mergedCommit.Sha); CreateAndStageANewFile(repo); const string commitMessage = "I'm rewriting the history!"; Commit amendedCommit = repo.Commit(commitMessage, DummySignature, DummySignature, true); AssertCommitHasBeenAmended(repo, amendedCommit, mergedCommit); // Assert a reflog entry is created var reflogEntry = repo.Refs.Log("HEAD").First(); Assert.Equal(amendedCommit.Committer, reflogEntry.Commiter); Assert.Equal(amendedCommit.Id, reflogEntry.To); Assert.Equal(string.Format("commit (amend): {0}", commitMessage), reflogEntry.Message); } }
public void HardResetUpdatesTheContentOfTheWorkingDirectory() { bool progressCalled = false; string path = SandboxStandardTestRepo(); using (var repo = new Repository(path)) { var names = new DirectoryInfo(repo.Info.WorkingDirectory).GetFileSystemInfos().Select(fsi => fsi.Name).ToList(); File.Delete(Path.Combine(repo.Info.WorkingDirectory, "README")); Touch(repo.Info.WorkingDirectory, "WillNotBeRemoved.txt", "content\n"); Assert.True(names.Count > 4); var commit = repo.Lookup<Commit>("HEAD~3"); repo.Reset(ResetMode.Hard, commit, new CheckoutOptions() { OnCheckoutProgress = (_path, _completed, _total) => { progressCalled = true; }, }); names = new DirectoryInfo(repo.Info.WorkingDirectory).GetFileSystemInfos().Select(fsi => fsi.Name).ToList(); names.Sort(StringComparer.Ordinal); Assert.Equal(true, progressCalled); Assert.Equal(new[] { ".git", "README", "WillNotBeRemoved.txt", "branch_file.txt", "new.txt", "new_untracked_file.txt" }, names); } }
public void CanArchiveATree() { string path = SandboxBareTestRepo(); using (var repo = new Repository(path)) { var tree = repo.Lookup<Tree>("581f9824ecaf824221bd36edf5430f2739a7c4f5"); var archiver = new MockArchiver(); var before = DateTimeOffset.Now.TruncateMilliseconds(); repo.ObjectDatabase.Archive(tree, archiver); var expected = new ArrayList { new { Path = "1", Sha = "7f76480d939dc401415927ea7ef25c676b8ddb8f" }, new { Path = Path.Combine("1", "branch_file.txt"), Sha = "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, new { Path = "README", Sha = "a8233120f6ad708f843d861ce2b7228ec4e3dec6" }, new { Path = "branch_file.txt", Sha = "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, new { Path = "new.txt", Sha = "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd" }, }; Assert.Equal(expected, archiver.Files); Assert.Null(archiver.ReceivedCommitSha); Assert.InRange(archiver.ModificationTime, before, DateTimeOffset.UtcNow); } }
public void CanArchiveACommitWithDirectoryAsTar() { var path = SandboxBareTestRepo(); using (var repo = new Repository(path)) { // This tests generates an archive of the bare test repo, and compares it with // a pre-generated tar file. The expected tar file has been generated with the // crlf filter active (on windows), so we need to make sure that even if the test // is launched on linux then the files content has the crlf filter applied (not // active by default). var sb = new StringBuilder(); sb.Append("* text eol=crlf\n"); Touch(Path.Combine(repo.Info.Path, "info"), "attributes", sb.ToString()); var commit = repo.Lookup<Commit>("4c062a6361ae6959e06292c1fa5e2822d9c96345"); var scd = BuildSelfCleaningDirectory(); var archivePath = Path.Combine(scd.RootedDirectoryPath, Path.GetRandomFileName() + ".tar"); Directory.CreateDirectory(scd.RootedDirectoryPath); repo.ObjectDatabase.Archive(commit, archivePath); using (var expectedStream = new StreamReader(Path.Combine(ResourcesDirectory.FullName, "expected_archives/commit_with_directory.tar"))) using (var actualStream = new StreamReader(archivePath)) { string expected = expectedStream.ReadToEnd(); string actual = actualStream.ReadToEnd(); Assert.Equal(expected, actual); } } }
public void CanAmendACommitWithMoreThanOneParent() { string path = CloneStandardTestRepo(); using (var repo = new Repository(path)) { var mergedCommit = repo.Lookup<Commit>("be3563a"); Assert.NotNull(mergedCommit); Assert.Equal(2, mergedCommit.Parents.Count()); repo.Reset(ResetMode.Soft, mergedCommit.Sha); CreateAndStageANewFile(repo); const string commitMessage = "I'm rewriting the history!"; Commit amendedCommit = repo.Commit(commitMessage, Constants.Signature, Constants.Signature, new CommitOptions { AmendPreviousCommit = true }); AssertCommitHasBeenAmended(repo, amendedCommit, mergedCommit); AssertRefLogEntry(repo, "HEAD", amendedCommit.Id, string.Format("commit (amend): {0}", commitMessage), mergedCommit.Id, amendedCommit.Committer); } }
public void CanExtractStatisticsFromDiff() { using (var repo = new Repository(StandardTestRepoPath)) { var oldTree = repo.Lookup<Commit>("origin/packed-test").Tree; var newTree = repo.Lookup<Commit>("HEAD").Tree; var stats = repo.Diff.Compare<PatchStats>(oldTree, newTree); Assert.Equal(8, stats.TotalLinesAdded); Assert.Equal(1, stats.TotalLinesDeleted); var contentStats = stats["new.txt"]; Assert.Equal(1, contentStats.LinesAdded); Assert.Equal(1, contentStats.LinesDeleted); } }
public void CanCheckoutAnArbitraryCommit(string commitPointer) { TemporaryCloneOfTestRepo path = BuildTemporaryCloneOfTestRepo(StandardTestRepoWorkingDirPath); using (var repo = new Repository(path.RepositoryPath)) { Branch master = repo.Branches["master"]; Assert.True(master.IsCurrentRepositoryHead); // Set the working directory to the current head ResetAndCleanWorkingDirectory(repo); Assert.False(repo.Index.RetrieveStatus().IsDirty); Branch detachedHead = repo.Checkout(commitPointer); Assert.Equal(repo.Head, detachedHead); Assert.Equal(repo.Lookup(commitPointer).Sha, detachedHead.Tip.Sha); Assert.True(repo.Head.IsCurrentRepositoryHead); Assert.True(repo.Info.IsHeadDetached); Assert.False(repo.Index.RetrieveStatus().IsDirty); Assert.True(detachedHead.IsCurrentRepositoryHead); Assert.False(detachedHead.IsRemote); Assert.Equal(detachedHead.Name, detachedHead.CanonicalName); Assert.Equal("(no branch)", detachedHead.CanonicalName); Assert.False(master.IsCurrentRepositoryHead); } }
public void CanSpecifyConflictFileStrategy(CheckoutFileConflictStrategy conflictStrategy) { const string conflictFile = "a.txt"; const string conflictBranchName = "conflicts"; string path = CloneMergeTestRepo(); using (var repo = new Repository(path)) { Branch branch = repo.Branches[conflictBranchName]; Assert.NotNull(branch); CherryPickOptions cherryPickOptions = new CherryPickOptions() { FileConflictStrategy = conflictStrategy, }; CherryPickResult result = repo.CherryPick(branch.Tip, Constants.Signature, cherryPickOptions); Assert.Equal(CherryPickStatus.Conflicts, result.Status); // Get the information on the conflict. Conflict conflict = repo.Index.Conflicts[conflictFile]; Assert.NotNull(conflict); Assert.NotNull(conflict.Theirs); Assert.NotNull(conflict.Ours); // Get the blob containing the expected content. Blob expectedBlob = null; switch (conflictStrategy) { case CheckoutFileConflictStrategy.Theirs: expectedBlob = repo.Lookup<Blob>(conflict.Theirs.Id); break; case CheckoutFileConflictStrategy.Ours: expectedBlob = repo.Lookup<Blob>(conflict.Ours.Id); break; default: throw new Exception("Unexpected FileConflictStrategy"); } Assert.NotNull(expectedBlob); // Check the content of the file on disk matches what is expected. string expectedContent = expectedBlob.GetContentText(new FilteringOptions(conflictFile)); Assert.Equal(expectedContent, File.ReadAllText(Path.Combine(repo.Info.WorkingDirectory, conflictFile))); } }
public void CanEnumerateBlobs() { using (var repo = new Repository(Constants.TestRepoPath)) { var tree = repo.Lookup<Tree>(sha); tree.Files.Count().ShouldEqual(3); } }
public void CanLookUpBlob() { using (var repo = new Repository(BareTestRepoPath)) { var blob = repo.Lookup<Blob>("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); Assert.NotNull(blob); } }
public void CanGetBlobSize() { using (var repo = new Repository(Constants.BareTestRepoPath)) { var blob = repo.Lookup<Blob>("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); blob.Size.ShouldEqual(10); } }
public void CanEnumerateSubTrees() { using (var repo = new Repository(Constants.BareTestRepoPath)) { var tree = repo.Lookup<Tree>(sha); tree.Trees.Count().ShouldEqual(1); } }
public void CanLookUpBlob() { using (var repo = new Repository(Constants.BareTestRepoPath)) { var blob = repo.Lookup<Blob>("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); blob.ShouldNotBeNull(); } }
public void CanEnumerateSubTrees() { using (var repo = new Repository(BareTestRepoPath)) { var tree = repo.Lookup<Tree>(sha); Assert.Equal(1, tree.Trees.Count()); } }
public void CanGetBlobSize() { using (var repo = new Repository(BareTestRepoPath)) { var blob = repo.Lookup<Blob>("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); Assert.Equal(10, blob.Size); } }
public void CanCalculateHistoryDivergence( string sinceSha, string untilSha, string expectedAncestorSha, int? expectedAheadBy, int? expectedBehindBy) { string path = SandboxBareTestRepo(); using (var repo = new Repository(path)) { var since = repo.Lookup<Commit>(sinceSha); var until = repo.Lookup<Commit>(untilSha); HistoryDivergence div = repo.ObjectDatabase.CalculateHistoryDivergence(since, until); Assert.Equal(expectedAheadBy, div.AheadBy); Assert.Equal(expectedBehindBy, div.BehindBy); Assert.Equal(expectedAncestorSha, div.CommonAncestor.Id.ToString(7)); } }
public void CanLookupACommitByTheNameOfALightweightTag() { using (var repo = new Repository(Constants.TestRepoPath)) { var gitObject = repo.Lookup("refs/tags/lw"); gitObject.ShouldNotBeNull(); Assert.IsInstanceOf<Commit>(gitObject); } }
public void FindCommonAncestorForCommitsAsEnumerableThrows(string[] shas, MergeBaseFindingStrategy strategy) { using (var repo = new Repository(BareTestRepoPath)) { var commits = shas.Select(sha => sha == "-" ? CreateOrphanedCommit(repo) : repo.Lookup<Commit>(sha)).ToArray(); Assert.Throws<ArgumentException>(() => repo.Commits.FindMergeBase(commits, strategy)); } }
public void CanLookupACommitByTheNameOfABranch() { using (var repo = new Repository(Constants.TestRepoPath)) { var gitObject = repo.Lookup("refs/heads/master"); gitObject.ShouldNotBeNull(); Assert.IsInstanceOf<Commit>(gitObject); } }
public void CanEnumerateTreeEntries() { using (var repo = new Repository(Constants.BareTestRepoPath)) { var tree = repo.Lookup<Tree>(sha); tree.Count().ShouldEqual(tree.Count); CollectionAssert.AreEqual(new[] { "1", "README", "branch_file.txt", "new.txt" }, tree.Select(te => te.Name).ToArray()); } }
public void CanGetBlobAsUtf8() { using (var repo = new Repository(Constants.BareTestRepoPath)) { var blob = repo.Lookup<Blob>("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); var text = blob.ContentAsUtf8(); text.ShouldEqual("hey there\n"); } }
public void CanGetBlobAsUtf8() { using (var repo = new Repository(BareTestRepoPath)) { var blob = repo.Lookup<Blob>("a8233120f6ad708f843d861ce2b7228ec4e3dec6"); string text = blob.ContentAsUtf8(); Assert.Equal("hey there\n", text); } }
public void CanConvertEntryToTree() { using (var repo = new Repository(Constants.BareTestRepoPath)) { var tree = repo.Lookup<Tree>(sha); TreeEntry treeEntry = tree["1"]; var subtree = treeEntry.Target as Tree; subtree.ShouldNotBeNull(); } }
public void RevertFindsRenames(bool?findRenames) { // The environment is set up such that: // - file d.txt is edited in the commit that is to be reverted (commit A) // - file d.txt is renamed to d_renamed.txt // - commit A is reverted. // If rename detection is enabled, then the revert is applied // to d_renamed.txt. If rename detection is not enabled, // then the revert results in a conflict. const string revertBranchName = "refs/heads/revert_rename"; const string commitIdToRevert = "ca3e813"; const string expectedBlobId = "0ff3bbb9c8bba2291654cd64067fa417ff54c508"; const string modifiedFilePath = "d_renamed.txt"; string repoPath = CloneRevertTestRepo(); using (var repo = new Repository(repoPath)) { Branch currentBranch = repo.Checkout(revertBranchName); Assert.NotNull(currentBranch); Commit commitToRevert = repo.Lookup <Commit>(commitIdToRevert); Assert.NotNull(currentBranch); RevertOptions options; if (findRenames.HasValue) { options = new RevertOptions() { FindRenames = findRenames.Value, }; } else { options = new RevertOptions(); } RevertResult result = repo.Revert(commitToRevert, Constants.Signature, options); Assert.NotNull(result); if (!findRenames.HasValue || findRenames.Value == true) { Assert.Equal(RevertStatus.Reverted, result.Status); Assert.NotNull(result.Commit); Blob expectedBlob = repo.Lookup <Blob>(expectedBlobId); Assert.NotNull(expectedBlob); GitObject blob = result.Commit.Tree[modifiedFilePath].Target as Blob; Assert.NotNull(blob); Assert.Equal(blob.Id, expectedBlob.Id); // Verify contents of workspace string fullPath = Path.Combine(repo.Info.WorkingDirectory, modifiedFilePath); Assert.Equal(expectedBlob.GetContentText(new FilteringOptions(modifiedFilePath)), File.ReadAllText(fullPath)); } else { Assert.Equal(RevertStatus.Conflicts, result.Status); Assert.Null(result.Commit); } } }
private static IEnumerable <Tuple <ObjectId, ObjectId> > SplitRepository(Repository baseRepo, ICommitLog commits, string name, string path, IEnumerable <SharedRepo> sharedRepos, IEnumerable <MergedRepo> mergedRepos) { var shared = sharedRepos.Where(r => r.Paths.Any(p => p.StartsWith(path + "/"))).Select(r => new { Repo = "../" + r.Name + ".git", Path = r.Paths.First(p => p.StartsWith(path + "/")).Substring(path.Length + 1), Commits = r.Commits }); var merged = mergedRepos.Where(r => r.Name == name); using (var repo = new Repository(Repository.Init(Path.Combine("output", name)))) { File.Copy(Path.Combine(Config.Instance.MainRepo, ".gitignore"), Path.Combine("output", name, ".gitignore")); repo.Index.Add(".gitignore"); File.Copy(Path.Combine(Config.Instance.MainRepo, ".gitattributes"), Path.Combine("output", name, ".gitattributes")); repo.Index.Add(".gitattributes"); foreach (var toMerge in merged) { using (var mergeRepo = new Repository(toMerge.Repo)) { foreach (var c in mergeRepo.Commits.QueryBy(new CommitFilter { SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Reverse })) { bool any = false; foreach (var m in toMerge.Mapping) { if (Merge(repo, c, m.Key, m.Value)) { any = true; } } if (any) { var rewrittenCommit = repo.Commit(c.Message, new Signature(c.Author.Name, Config.Instance.MapEmail(c.Author.Email), c.Author.When), new Signature(c.Committer.Name, Config.Instance.MapEmail(c.Author.Email), c.Author.When), new CommitOptions { AllowEmptyCommit = true }); yield return(new Tuple <ObjectId, ObjectId>(c.Id, rewrittenCommit.Id)); } } } repo.Index.Clear(); repo.Index.Add(".gitignore"); repo.Index.Add(".gitattributes"); } if (shared.Any()) { File.WriteAllText(Path.Combine("output", name, ".gitmodules"), string.Join("", shared.Select(s => $"[submodule \"{s.Path}\"]\n path = {s.Path}\n url = {s.Repo}\n"))); repo.Index.Add(".gitmodules"); } foreach (var c in commits) { if (c.Tree[path] == null) { continue; } TreeDefinition tree = null; foreach (var s in shared) { var mapping = s.Commits.FirstOrDefault(commit => c.Id == commit.Item1); if (mapping != null) { if (tree == null) { var tempCommit = repo.Commit("temp", new Signature("temp", "*****@*****.**", DateTimeOffset.UtcNow), new Signature("temp", "*****@*****.**", DateTimeOffset.UtcNow), new CommitOptions { AllowEmptyCommit = true }); tree = TreeDefinition.From(tempCommit); repo.Reset(ResetMode.Soft, tempCommit.Parents.First()); } tree.AddGitLink(s.Path, mapping.Item2); } } if (tree != null) { repo.Index.Replace(repo.ObjectDatabase.CreateTree(tree)); } var oldTree = c.Parents.FirstOrDefault()?.Tree?[path]?.Target as Tree; if (oldTree != null) { var diff = baseRepo.Diff.Compare <TreeChanges>(oldTree, (Tree)c.Tree[path].Target); if (!diff.Any()) { continue; } foreach (var file in diff) { if (file.Mode == Mode.Directory) { continue; } if (!file.Exists || (file.OldPath != file.Path && file.Status != ChangeKind.Copied)) { if (!shared.Any(s => file.OldPath.Replace('\\', '/').StartsWith(s.Path + '/'))) { File.Delete(Path.Combine("output", name, file.OldPath)); repo.Index.Remove(file.OldPath); } } if (file.Exists) { if (!shared.Any(s => file.Path.Replace('\\', '/').StartsWith(s.Path + '/'))) { Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine("output", name, file.Path))); using (var input = baseRepo.Lookup <Blob>(file.Oid).GetContentStream()) using (var output = File.Create(Path.Combine("output", name, file.Path))) { input.CopyTo(output); } repo.Index.Add(file.Path); } } } } else { foreach (var entry in RecursiveTree((Tree)c.Tree[path].Target, path)) { if (shared.Any(s => entry.Item1.Replace('\\', '/').StartsWith(s.Path + '/'))) { continue; } var fullPath = Path.Combine("output", name, entry.Item1); Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); using (var content = entry.Item2.GetContentStream()) using (var output = File.Create(fullPath)) { content.CopyTo(output); } repo.Index.Add(entry.Item1); } } var email = Config.Instance.MapEmail(c.Author.Email); var rewrittenCommit = repo.Commit(c.Message, new Signature(c.Author.Name, email, c.Author.When), new Signature(c.Committer.Name, email, c.Author.When), new CommitOptions { AllowEmptyCommit = true }); yield return(new Tuple <ObjectId, ObjectId>(c.Id, rewrittenCommit.Id)); } repo.Network.Remotes.Add("origin", Config.Instance.Origin(name)); Console.WriteLine("Copying LFS files..."); var lfsCount = CopyLfsFiles(repo, Path.Combine("output", name, ".git", "lfs", "objects"), new[] { Path.Combine(baseRepo.Info.WorkingDirectory, ".git", "lfs", "objects") }.Concat(merged.Where(r => r.Name == name).Select(r => Path.Combine(r.Repo, ".git", "lfs", "objects")))); Console.WriteLine($"Copied {lfsCount} files."); // LibGit2Sharp doesn't support git gc, so we use the command line: using (var gc = Process.Start(new ProcessStartInfo("git", "gc --aggressive") { WorkingDirectory = repo.Info.WorkingDirectory, UseShellExecute = false })) { gc.WaitForExit(); } } }
public void CanContinueRebase() { SelfCleaningDirectory scd = BuildSelfCleaningDirectory(); var path = Repository.Init(scd.DirectoryPath); using (Repository repo = new Repository(path)) { ConstructRebaseTestRepository(repo); repo.Checkout(topicBranch1Name); Assert.False(repo.RetrieveStatus().IsDirty); Branch branch = repo.Branches[topicBranch1Name]; Branch upstream = repo.Branches[conflictBranch1Name]; Branch onto = repo.Branches[conflictBranch1Name]; int beforeStepCallCount = 0; int afterStepCallCount = 0; bool wasCheckoutProgressCalled = false; bool wasCheckoutNotifyCalled = false; RebaseOptions options = new RebaseOptions() { RebaseStepStarting = x => beforeStepCallCount++, RebaseStepCompleted = x => afterStepCallCount++, OnCheckoutProgress = (x, y, z) => wasCheckoutProgressCalled = true, OnCheckoutNotify = (x, y) => { wasCheckoutNotifyCalled = true; return(true); }, CheckoutNotifyFlags = CheckoutNotifyFlags.Updated, }; RebaseResult rebaseResult = repo.Rebase.Start(branch, upstream, onto, Constants.Identity, options); // Verify that we have a conflict. Assert.Equal(CurrentOperation.RebaseMerge, repo.Info.CurrentOperation); Assert.Equal(RebaseStatus.Conflicts, rebaseResult.Status); Assert.True(repo.RetrieveStatus().IsDirty); Assert.False(repo.Index.IsFullyMerged); Assert.Equal(0, rebaseResult.CompletedStepCount); Assert.Equal(3, rebaseResult.TotalStepCount); // Verify that expected callbacks were called Assert.Equal(1, beforeStepCallCount); Assert.Equal(0, afterStepCallCount); Assert.True(wasCheckoutProgressCalled, "CheckoutProgress callback was not called."); // Resolve the conflict foreach (Conflict conflict in repo.Index.Conflicts) { Touch(repo.Info.WorkingDirectory, conflict.Theirs.Path, repo.Lookup <Blob>(conflict.Theirs.Id).GetContentText(new FilteringOptions(conflict.Theirs.Path))); Commands.Stage(repo, conflict.Theirs.Path); } Assert.True(repo.Index.IsFullyMerged); // Clear the flags: wasCheckoutProgressCalled = false; wasCheckoutNotifyCalled = false; RebaseResult continuedRebaseResult = repo.Rebase.Continue(Constants.Identity, options); Assert.NotNull(continuedRebaseResult); Assert.Equal(RebaseStatus.Complete, continuedRebaseResult.Status); Assert.False(repo.RetrieveStatus().IsDirty); Assert.True(repo.Index.IsFullyMerged); Assert.Equal(0, rebaseResult.CompletedStepCount); Assert.Equal(3, rebaseResult.TotalStepCount); Assert.Equal(3, beforeStepCallCount); Assert.Equal(3, afterStepCallCount); Assert.True(wasCheckoutProgressCalled, "CheckoutProgress callback was not called."); Assert.True(wasCheckoutNotifyCalled, "CheckoutNotify callback was not called."); } }
private void CommitHistory() { Database db = new Database(); Repository repo; //List<Entities.Commit> commiList //Entities.Commit commit; //CommitFile commitFile; NotificationArgs notificationArgs; var directories = Directory.GetDirectories(downloadDirectory); int counter = 0; int groupSize = Convert.ToInt32(Math.Ceiling(directories.Count() / 3.0)); var result = directories.GroupBy(s => counter++ / groupSize).Select(g => g.ToArray()).ToList(); int threadCount = result.Count() + 1; Parallel.For(0, threadCount, i => { var dataSet = result.ElementAtOrDefault(i); if (dataSet != null) { Console.WriteLine("Processing dataset: " + i + "; Count: " + dataSet.Count()); foreach (var directory in dataSet) { string lastFolderName = Path.GetFileName(directory); long appId = db.GetAppByName(lastFolderName).Id; try { repo = new Repository(directory); List <Entities.Commit> commiList = new List <Entities.Commit>(); int commitCount = repo.Commits.Count(); notificationArgs = new NotificationArgs(string.Format("Started - Commit Histroy for {0} - Total Commits: {1}", lastFolderName, commitCount), DateTime.Now, NotificationType.INFORMATION); OnMessageIssued(notificationArgs); int j = repo.Commits.Count() - 1; foreach (var cx in repo.Commits) // for (int i = commitCount - 1; i >= 0; i--) { Entities.Commit commit = new Entities.Commit(); commit.AuthorEmail = cx.Author.Email; commit.AuthorEmail = cx.Author.Email; commit.AuthorName = cx.Author.Name; commit.Date = cx.Author.When.LocalDateTime; commit.Message = cx.Message; commit.GUID = cx.Sha; if (includeFiles) { if (j == commitCount - 1) { Tree firstCommit = repo.Lookup <Tree>(repo.Commits.ElementAt(j).Tree.Sha); Tree lastCommit = repo.Lookup <Tree>(repo.Commits.ElementAt(0).Tree.Sha); var changes = repo.Diff.Compare <TreeChanges>(lastCommit, firstCommit); foreach (var item in changes) { if (item.Status != ChangeKind.Deleted) { CommitFile commitFile = new CommitFile(item.Path, ChangeKind.Added.ToString()); commit.CommitFiles.Add(commitFile); } } } else { var changes = repo.Diff.Compare <TreeChanges>(repo.Commits.ElementAt(j + 1).Tree, repo.Commits.ElementAt(j).Tree); foreach (var item in changes) { CommitFile commitFile = new CommitFile(item.Path, item.Status.ToString()); commit.CommitFiles.Add(commitFile); } } } commiList.Add(commit); j--; } db.BatchInsertCommits(commiList, appId); notificationArgs = new NotificationArgs(string.Format("Completed - Commit Histroy for {0}", lastFolderName), DateTime.Now, NotificationType.SUCCESS); OnMessageIssued(notificationArgs); } catch (Exception error) { LogFailure(string.Format("Failed - Commit Histroy for {0} ; {1}", lastFolderName, error.Message)); notificationArgs = new NotificationArgs("Failed - Commit Histroy for " + lastFolderName, DateTime.Now, NotificationType.FAILURE); OnMessageIssued(notificationArgs); continue; } } } }); }
private Blob Upvote(Repository repo) { return(repo.Lookup <Blob>(repo.Tags[UPVOTE].Target.Id)); }
private MonitoredPath GetMonitoredPath(string commitId, MonitoredPath monitoredPath, DirectoryInfo[] directoriesToScan, string branchName) { MonitoredPath newmonitoredPath = new MonitoredPath(); List <GitCommit> commits = new List <GitCommit>(); foreach (DirectoryInfo dir in directoriesToScan) { try { GitRepository gitrepo = this.TryGetRepo(monitoredPath, dir.Name); using (Repository repo = new Repository(dir.FullName)) { try { string branch = repo.Info.IsBare ? branchName : $"origin/{branchName}"; gitrepo.Branch = branch; int commitCount = 0; Commit com = repo.Lookup <Commit>(commitId); if (com != null) { CommitFilter comFilter = new CommitFilter { IncludeReachableFrom = branch, ExcludeReachableFrom = com }; var coms = repo.Commits.QueryBy(comFilter).OrderBy(s => s.Author.When); string repositoryUrl = string.Empty; if (repo.Network.Remotes?["origin"] != null) { repositoryUrl = repo.Network.Remotes["origin"].Url; } foreach (Commit cm in coms) { if (!monitoredPath.IncludeMergeCommits) { // filter out merge commits if (com.Parents.Count() > 1) { continue; } } commits.Add(new GitCommit { Author = cm.Author.Name, AuthorEmail = string.IsNullOrWhiteSpace(com.Author.Email) ? string.Empty : cm.Author.Email, AuthorWhen = cm.Author.When.UtcDateTime, Committer = cm.Committer.Name, CommitterEmail = string.IsNullOrWhiteSpace(com.Committer.Email) ? string.Empty : cm.Committer.Email, CommitterWhen = cm.Committer.When.UtcDateTime, Sha = cm.Sha, Message = cm.Message, RepositoryFriendlyName = gitrepo.FriendlyName, RepositoryName = dir.Name, RepositoryUrl = repositoryUrl, CommitUrl = string.IsNullOrWhiteSpace(gitrepo.CommitUrl) ? string.Empty : string.Format($"{gitrepo.CommitUrl}{cm.Sha}"), IsMerge = com.Parents.Count() > 1 }); commitCount++; } gitrepo.CommitCount = commitCount; newmonitoredPath.Repositories.Add(gitrepo); } } catch (Exception ex) { this.locallogger.LogError("GetMonitoredPath Bad - ", ex); } newmonitoredPath.Name = monitoredPath.Name; newmonitoredPath.AllowFetch = monitoredPath.AllowFetch; newmonitoredPath.AllFolders = monitoredPath.AllFolders; newmonitoredPath.Path = monitoredPath.Path; newmonitoredPath.CommitCount = commits.Count; newmonitoredPath.Commits = commits; } } catch (Exception ex) { this.locallogger.LogError("GetMonitoredPath Bad - ", ex); } } return(newmonitoredPath); }
static int Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += (sender, e) => Console.Error.WriteLine($"Error: {e.ToString()}"); if (args.Length != 4) { Console.Error.WriteLine($"ERROR: Expected 4 arguments but got {args.Length}"); return(1); } if (args[0] != "-prev" || args[2] != "-curr") { Console.Error.WriteLine("ERROR: Invalid arguments. Invoke `prfinder -prev {sha} -curr {sha}`"); return(1); } var previousCommitSha = args[1]; var currentCommitSha = args[3]; using (var repo = new Repository(Environment.CurrentDirectory)) { var currentCommit = repo.Lookup <Commit>(currentCommitSha); var previousCommit = repo.Lookup <Commit>(previousCommitSha); if (currentCommit is null || previousCommit is null) { Console.WriteLine($"Couldn't find commit {(currentCommit is null ? currentCommitSha : previousCommitSha)}"); Console.WriteLine("Fetching and trying again..."); // it doesn't please me to do this, but libgit2sharp doesn't support ssh easily Process.Start("git", "fetch --all").WaitForExit(); Console.WriteLine("--- end of git output ---"); Console.WriteLine(); currentCommit = repo.Lookup <Commit>(currentCommitSha); previousCommit = repo.Lookup <Commit>(previousCommitSha); } // Get commit history starting at the current commit and ending at the previous commit var commitLog = repo.Commits.QueryBy( new CommitFilter { IncludeReachableFrom = currentCommit, ExcludeReachableFrom = previousCommit }); Console.WriteLine($@"Changes since [{previousCommitSha}]({RepoPRUrl}/commit/{previousCommitSha})"); foreach (var commit in commitLog) { // Exclude auto-merges if (commit.Author.Name == "dotnet-automerge-bot") { continue; } var match = IsMergePRCommit.Match(commit.MessageShort); if (!match.Success) { match = IsSquashedPRCommit.Match(commit.MessageShort); } if (!match.Success) { continue; } var prNumber = match.Groups[1].Value; var prLink = $@"- [{commit.MessageShort}]({RepoPRUrl}/pull/{prNumber})"; Console.WriteLine(prLink); } } return(0); }
/// <summary> /// This is just a base function to recurse from. /// </summary> private static void SafeCheckoutByIndividualFiles(Repository repo, string commit, CheckoutOptions options, ILogger log) { log.LogDebug($"Beginning individual file checkout for {repo.Info.WorkingDirectory} at {commit}"); SafeCheckoutTreeByIndividualFiles(repo, repo.Lookup(commit).Peel <Tree>(), "", commit, options, log); }
public IEnumerable <HunkRangeInfo> GetGitDiffFor(ITextDocument textDocument, string originalPath, ITextSnapshot snapshot) { var filename = textDocument.FilePath; var repositoryPath = GetGitRepository(Path.GetFullPath(filename), ref originalPath); if (repositoryPath == null) { yield break; } using (var repo = new Repository(repositoryPath)) { var workingDirectory = repo.Info.WorkingDirectory; if (workingDirectory == null) { yield break; } var retrieveStatus = repo.RetrieveStatus(originalPath); if (retrieveStatus == FileStatus.Nonexistent) { // this occurs if a file within the repository itself (not the working copy) is opened. yield break; } if ((retrieveStatus & FileStatus.Ignored) != 0) { // pointless to show diffs for ignored files yield break; } // Determine 'from' tree. var currentBranch = repo.Head.FriendlyName; var baseCommitEntry = repo.Config.Get <string>(string.Format("branch.{0}.diffmarginbase", currentBranch)); Commit from = null; if (baseCommitEntry != null) { var baseCommit = repo.Lookup <Commit>(baseCommitEntry.Value); if (baseCommit != null) { // Found a merge base to diff from. from = baseCommit; } } if (from == null && retrieveStatus == FileStatus.Unaltered && !textDocument.IsDirty && Path.GetFullPath(filename) == originalPath) { // Truly unaltered. The `IsDirty` check isn't valid for cases where the textDocument is a view of a // temporary copy of the file, since the temporary copy could have been made using unsaved changes // and still appear "not dirty". yield break; } var content = GetCompleteContent(textDocument, snapshot); if (content == null) { yield break; } using (var currentContent = new MemoryStream(content)) { var relativeFilepath = originalPath; if (relativeFilepath.StartsWith(workingDirectory, StringComparison.OrdinalIgnoreCase)) { relativeFilepath = relativeFilepath.Substring(workingDirectory.Length); } relativeFilepath = relativeFilepath.Replace('\\', '/'); var newBlob = repo.ObjectDatabase.CreateBlob(currentContent, relativeFilepath); bool suppressRollback; Blob blob; if ((retrieveStatus & FileStatus.NewInWorkdir) != 0 || (retrieveStatus & FileStatus.NewInIndex) != 0) { suppressRollback = true; // special handling for added files (would need updating to compare against index) using (var emptyContent = new MemoryStream()) { blob = repo.ObjectDatabase.CreateBlob(emptyContent, relativeFilepath); } } else { suppressRollback = false; from = from ?? repo.Head.Tip; TreeEntry fromEntry = from[relativeFilepath]; if (fromEntry == null) { // try again using case-insensitive comparison Tree tree = from.Tree; foreach (string segment in relativeFilepath.Split('/')) { if (tree == null) { yield break; } fromEntry = tree.FirstOrDefault(i => string.Equals(segment, i.Name, StringComparison.OrdinalIgnoreCase)); if (fromEntry == null) { yield break; } tree = fromEntry.Target as Tree; } } blob = fromEntry.Target as Blob; if (blob == null) { yield break; } } var treeChanges = repo.Diff.Compare(blob, newBlob, new CompareOptions { ContextLines = ContextLines, InterhunkLines = 0 }); var gitDiffParser = new GitDiffParser(treeChanges.Patch, ContextLines, suppressRollback); var hunkRangeInfos = gitDiffParser.Parse(); foreach (var hunkRangeInfo in hunkRangeInfos) { yield return(hunkRangeInfo); } } } }
public void FindCommonAncestorForCommitsAsEnumerable(string result, string[] shas, MergeBaseFindingStrategy strategy) { using (var repo = new Repository(BareTestRepoPath)) { var commits = shas.Select(sha => sha == "-" ? CreateOrphanedCommit(repo) : repo.Lookup <Commit>(sha)).ToArray(); Commit ancestor = repo.Commits.FindMergeBase(commits, strategy); if (result == null) { Assert.Null(ancestor); } else { Assert.NotNull(ancestor); Assert.Equal(result, ancestor.Id.Sha); } } }
public void StartExternalDiff(ITextDocument textDocument, string originalPath) { if (textDocument == null || string.IsNullOrEmpty(textDocument.FilePath)) { return; } var filename = textDocument.FilePath; var repositoryPath = GetGitRepository(Path.GetFullPath(filename), ref originalPath); if (repositoryPath == null) { return; } using (var repo = new Repository(repositoryPath)) { string workingDirectory = repo.Info.WorkingDirectory; string relativePath = originalPath; if (relativePath.StartsWith(workingDirectory, StringComparison.OrdinalIgnoreCase)) { relativePath = relativePath.Substring(workingDirectory.Length); } // the name of the object in the database string objectName = Path.GetFileName(filename); Blob oldBlob = null; var indexEntry = repo.Index[relativePath.Replace("\\", "/")]; if (indexEntry != null) { objectName = Path.GetFileName(indexEntry.Path); oldBlob = repo.Lookup <Blob>(indexEntry.Id); } var tempFileName = Path.GetTempFileName(); if (oldBlob != null) { File.WriteAllText(tempFileName, oldBlob.GetContentText(new FilteringOptions(relativePath)), GetEncoding(filename)); } IVsDifferenceService differenceService = _serviceProvider.GetService(typeof(SVsDifferenceService)) as IVsDifferenceService; string leftFileMoniker = tempFileName; // The difference service will automatically load the text from the file open in the editor, even if // it has changed. Don't use the original path here. string rightFileMoniker = filename; string actualFilename = objectName; string tempPrefix = Path.GetRandomFileName().Substring(0, 5); string caption = string.Format("{0}_{1} vs. {1}", tempPrefix, actualFilename); string tooltip = null; string leftLabel; if (indexEntry != null) { // determine if the file has been staged string revision; var stagedMask = FileStatus.NewInIndex | FileStatus.ModifiedInIndex; if ((repo.RetrieveStatus(relativePath) & stagedMask) != 0) { revision = "index"; } else { revision = repo.Head.Tip.Sha.Substring(0, 7); } leftLabel = string.Format("{0}@{1}", objectName, revision); } else if (oldBlob != null) { // file was added leftLabel = null; } else { // we just compared to head leftLabel = string.Format("{0}@{1}", objectName, repo.Head.Tip.Sha.Substring(0, 7)); } string rightLabel = originalPath; string inlineLabel = null; string roles = null; __VSDIFFSERVICEOPTIONS grfDiffOptions = __VSDIFFSERVICEOPTIONS.VSDIFFOPT_LeftFileIsTemporary; differenceService.OpenComparisonWindow2(leftFileMoniker, rightFileMoniker, caption, tooltip, leftLabel, rightLabel, inlineLabel, roles, (uint)grfDiffOptions); // Since the file is marked as temporary, we can delete it now File.Delete(tempFileName); } }
public void Y() { _repo.OnBranch("master", r => { r.Commit(JohnSmith, "M1", rf => { rf.SetFile(File1, "block1\n\nblock2\n"); rf.Stage(File1); }).Ref("mark/m/1"); }); _repo.OnBranch("branch", r => { r.Commit(JohnDoe, "B1", rf => { rf.SetFile(File1, "block1\n\nblock2\nline2.1\nline2.2\n"); rf.Stage(File1); }).Ref("mark/b/1"); }); _repo.OnBranch("master", r => { r.Commit(JohnSmith, "M2", rf => { rf.SetFile(File1, "block1\nline1.1\nline1.2\n\nblock2\n"); rf.Stage(File1); }).Ref("mark/m/2"); }); _repo.OnBranch("branch", r => { var mr = r.Merge(r.Branches["master"], JohnDoe); Console.WriteLine(mr); Assert.That(mr.Status, Is.EqualTo(MergeStatus.NonFastForward)); r.Refs.Add("mark/b/2m", mr.Commit.Id); r.Commit(JohnDoe, "B2", rc => { rc.AppendFile(File1, "\nblock3\nline3.1\nline3.2\n"); rc.Stage(File1); }).Ref("mark/b/3"); }); //var diff = _repo.NiceDiff(File1, "mark/b/1", "mark/b/3"); //PrintDiffText(_repo.CatFile(File1, "mark/b/1"), diff); var diff1 = _repo.Diff.Compare <Patch>( (_repo.Lookup <Commit>("mark/b/1").Tree), (_repo.Lookup <Commit>("mark/b/3").Tree) ); Console.WriteLine(diff1.Content); var mb1 = _repo.Lookup <Commit>("mark/m/1"); var mb2 = _repo.Lookup <Commit>("mark/b/2m"); var diff2 = _repo.Diff.Compare <Patch>( (mb1.Tree), (mb2.Tree) ); Console.WriteLine("\n\n\n===================\n\n\n"); Console.WriteLine(diff2.Content); }
public GitCommit GetCommit(string commitish) { return(new GitCommit(_repository.Lookup <Commit>(commitish))); }
static public LoadFromUrlResult LoadFromUrl(string sourceUrl) { var parsedUrl = ParseGitHubObjectUrl(sourceUrl); if (parsedUrl == null) return new LoadFromUrlResult { Error = "Failed to parse string '" + sourceUrl + "' as GitHub object URL.", }; var refLooksLikeCommit = Regex.IsMatch(parsedUrl.@ref, "[A-Fa-f0-9]{40}"); var tempWorkingDirectory = Kalmit.Filesystem.CreateRandomDirectoryInTempDirectory(); var gitRepositoryLocalDirectory = Path.Combine(tempWorkingDirectory, "git-repository"); // https://github.com/libgit2/libgit2sharp/wiki/git-clone Repository.Clone(parsedUrl.repository, gitRepositoryLocalDirectory, new CloneOptions { Checkout = false }); Composition.TreeComponent literalNodeObject = null; string urlInCommit = null; string urlInFirstParentCommitWithSameValueAtThisPath = null; (string hash, CommitContent content)? rootCommit = null; (string hash, CommitContent content)? firstParentCommitWithSameTree = null; using (var gitRepository = new Repository(gitRepositoryLocalDirectory)) { var commit = gitRepository.Lookup(parsedUrl.@ref) as Commit; if (commit == null) return new LoadFromUrlResult { Error = "I did not find the commit for ref '" + parsedUrl.@ref + "'.", }; urlInCommit = BackToUrl(parsedUrl.WithRef(commit.Sha)); rootCommit = GetCommitHashAndContent(commit); var pathNodesNames = parsedUrl.path.Split('/', StringSplitOptions.RemoveEmptyEntries); var findGitObjectResult = FindGitObjectAtPath(commit.Tree, pathNodesNames); var linkedObject = findGitObjectResult?.Success; if (linkedObject == null) return new LoadFromUrlResult { Error = "I did not find an object at path '" + parsedUrl.path + "'.", }; IEnumerable<Commit> traceBackTreeParents() { var queue = new Queue<Commit>(); queue.Enqueue(commit); while (queue.TryDequeue(out var currentCommit)) { yield return currentCommit; foreach (var parent in currentCommit.Parents) { if (FindGitObjectAtPath(parent.Tree, pathNodesNames)?.Success?.Sha != linkedObject?.Sha) continue; queue.Enqueue(parent); } } } firstParentCommitWithSameTree = GetCommitHashAndContent(traceBackTreeParents().OrderBy(commit => commit.Author.When).First()); urlInFirstParentCommitWithSameValueAtThisPath = BackToUrl(parsedUrl.WithRef(firstParentCommitWithSameTree.Value.hash));
public void FindCommonAncestorForCommitsAsEnumerableThrows(string[] shas, MergeBaseFindingStrategy strategy) { using (var repo = new Repository(BareTestRepoPath)) { var commits = shas.Select(sha => sha == "-" ? CreateOrphanedCommit(repo) : repo.Lookup <Commit>(sha)).ToArray(); Assert.Throws <ArgumentException>(() => repo.Commits.FindMergeBase(commits, strategy)); } }
static public Result <string, LoadFromUrlSuccess> LoadFromUrl( string sourceUrl, Func <GetRepositoryFilesPartialForCommitRequest, IImmutableDictionary <IImmutableList <string>, IReadOnlyList <byte> > > getRepositoryFilesPartialForCommit) { var parsedUrl = ParseUrl(sourceUrl); if (parsedUrl == null) { return(Result <string, LoadFromUrlSuccess> .err( "Failed to parse string '" + sourceUrl + "' as GitHub or GitLab URL.")); } string?branchName = null; bool refLooksLikeCommit = false; if (parsedUrl.inRepository != null) { refLooksLikeCommit = Regex.IsMatch(parsedUrl.inRepository.@ref, "[A-Fa-f0-9]{40}"); branchName = refLooksLikeCommit ? null : parsedUrl.inRepository.@ref; } var cloneUrl = parsedUrl.repository.TrimEnd('/') + ".git"; if (getRepositoryFilesPartialForCommit == null) { getRepositoryFilesPartialForCommit = req => GetRepositoryFilesPartialForCommitViaLibGitSharpCheckout( cloneUrl: req.cloneUrlCandidates[0], commit: req.commit); } var repositoryFilesPartial = refLooksLikeCommit ? getRepositoryFilesPartialForCommit( new GetRepositoryFilesPartialForCommitRequest( commit: parsedUrl.inRepository !.@ref, cloneUrlCandidates: ImmutableList.Create(cloneUrl))) : GetRepositoryFilesPartialForBranchViaLibGitSharpCheckout(cloneUrl, branchName); var tempWorkingDirectory = Filesystem.CreateRandomDirectoryInTempDirectory(); var gitRepositoryLocalDirectory = Path.Combine(tempWorkingDirectory, "git-repository"); try { foreach (var fileWithPath in repositoryFilesPartial) { var absoluteFilePath = Path.Combine(new[] { gitRepositoryLocalDirectory }.Concat(fileWithPath.Key).ToArray()); var absoluteDirectoryPath = Path.GetDirectoryName(absoluteFilePath) !; Directory.CreateDirectory(absoluteDirectoryPath); File.WriteAllBytes(absoluteFilePath, fileWithPath.Value.ToArray()); } (string hash, CommitContent content)? rootCommit = null; using var gitRepository = new Repository(gitRepositoryLocalDirectory); Commit?startCommit = null; if (parsedUrl.inRepository == null) { startCommit = gitRepository.Head.Commits.FirstOrDefault(); if (startCommit == null) { return(Result <string, LoadFromUrlSuccess> .err( "Failed to get the first commit from HEAD")); } } else { startCommit = gitRepository.Lookup(parsedUrl.inRepository.@ref) as Commit; if (startCommit == null) { return(Result <string, LoadFromUrlSuccess> .err( "I did not find the commit for ref '" + parsedUrl.inRepository.@ref + "'.")); } } ParsedUrlInRepository partInRepositoryWithCommit(Commit replacementCommit) => parsedUrl.inRepository == null ? new ParsedUrlInRepository(GitObjectType.tree, @ref: replacementCommit.Sha, path: "") : parsedUrl.inRepository with { @ref = replacementCommit.Sha }; var urlInCommit = BackToUrl(parsedUrl with { inRepository = partInRepositoryWithCommit(startCommit) }); rootCommit = GetCommitHashAndContent(startCommit); var parsedUrlPath = parsedUrl.inRepository == null ? "" : parsedUrl.inRepository.path; var pathNodesNames = parsedUrlPath.Split('/', StringSplitOptions.RemoveEmptyEntries); var findGitObjectResult = FindGitObjectAtPath(startCommit.Tree, pathNodesNames); var linkedObject = findGitObjectResult?.Ok; if (linkedObject == null) { return(Result <string, LoadFromUrlSuccess> .err( "I did not find an object at path '" + parsedUrlPath + "' in " + startCommit.Sha)); } IEnumerable <Commit> traceBackTreeParents() { var queue = new Queue <Commit>(); queue.Enqueue(startCommit); while (queue.TryDequeue(out var currentCommit)) { yield return(currentCommit); foreach (var parent in currentCommit.Parents) { if (FindGitObjectAtPath(parent.Tree, pathNodesNames)?.Ok?.Sha != linkedObject?.Sha) { continue; } queue.Enqueue(parent); } } } var firstParentCommitWithSameTreeRef = traceBackTreeParents().OrderBy(commit => commit.Author.When).First(); var firstParentCommitWithSameTree = GetCommitHashAndContent(firstParentCommitWithSameTreeRef); var urlInFirstParentCommitWithSameValueAtThisPath = BackToUrl(parsedUrl with { inRepository = partInRepositoryWithCommit(firstParentCommitWithSameTreeRef) });
public TreeEntryModel GetBlob(String path) { String referenceName; var commit = GetCommitByPath(ref path, out referenceName); if (commit == null) { return(null); } var entry = commit[path]; if (entry == null || entry.TargetType != TreeEntryTargetType.Blob) { return(null); } var blob = (Blob)entry.Target; var cacheAccessor = GitCacheAccessor.Singleton(new LastCommitAccessor(_repoId, _repository, commit, path)); var lastCommitSha = cacheAccessor.Result.Value; if (lastCommitSha != commit.Sha) { commit = _repository.Lookup <Commit>(lastCommitSha); } var data = blob.GetContentStream().ToBytes(); var encoding = FileHelper.DetectEncoding(data, CpToEncoding(commit.Encoding), _i18n.Value); var extension = Path.GetExtension(entry.Name).ToLower(); var model = new TreeEntryModel { Name = entry.Name, ReferenceName = referenceName, Sha = commit.Sha, Path = String.IsNullOrEmpty(path) ? "" : path, Commit = new CommitModel { Sha = commit.Sha, Author = commit.Author, Committer = commit.Committer, CommitMessage = commit.Message.RepetitionIfEmpty(UnknowString), CommitMessageShort = commit.MessageShort.RepetitionIfEmpty(UnknowString), Parents = commit.Parents.Select(s => s.Sha).ToArray() }, EntryType = entry.TargetType, RawData = data, SizeString = FileHelper.GetSizeString(data.Length), TextContent = encoding == null ? null : FileHelper.ReadToEnd(data, encoding), TextBrush = FileHelper.BrushMapping.ContainsKey(extension) ? FileHelper.BrushMapping[extension] : "no-highlight", BlobType = encoding == null ? FileHelper.ImageSet.Contains(extension) ? BlobType.Image : BlobType.Binary : extension == ".md" ? BlobType.MarkDown : BlobType.Text, BlobEncoding = encoding, BranchSelector = GetBranchSelectorModel(referenceName, commit.Sha, path), PathBar = new PathBarModel { Name = Name, Action = "Tree", Path = path, ReferenceName = referenceName, ReferenceSha = commit.Sha, HideLastSlash = true, }, }; return(model); }
private Blob Downvote(Repository repo) { return(repo.Lookup <Blob>(repo.Tags[DOWNVOTE].Target.Id)); }
public List <GitCommit> SearchForCommit(MonitoredPathConfig monitoredPathConfig, string monitoredPathName, string sha) { List <GitCommit> commits = new List <GitCommit>(); try { if (string.IsNullOrWhiteSpace(monitoredPathName)) { monitoredPathName = "default"; } foreach (MonitoredPath mp in monitoredPathConfig.MonitoredPaths) { if (string.Compare(mp.Name, monitoredPathName, StringComparison.OrdinalIgnoreCase) == 0 || monitoredPathName == "*") { DirectoryInfo[] directoriesToScan = new DirectoryInfo(mp.Path).GetDirectories("*", SearchOption.TopDirectoryOnly); foreach (DirectoryInfo dir in directoriesToScan) { try { using (Repository repo = new Repository(dir.FullName)) { try { Commit com = repo.Lookup <Commit>(sha); if (com != null) { GitRepository gitrepo = new GitRepository(); foreach (var repo1 in mp.Repositories) { if (string.Compare(repo1.Name, dir.Name, StringComparison.OrdinalIgnoreCase) == 0) { gitrepo = new GitRepository { AllowFetch = repo1.AllowFetch, CommitUrl = repo1.CommitUrl, FriendlyName = string.IsNullOrWhiteSpace(repo1.FriendlyName) ? dir.Name : repo1.FriendlyName, Name = dir.Name }; } } string url = string.IsNullOrWhiteSpace(gitrepo.CommitUrl) ? string.Empty : string.Format($"{gitrepo.CommitUrl}{com.Sha}"); string repositoryUrl = string.Empty; if (repo.Network.Remotes?["origin"] != null) { repositoryUrl = repo.Network.Remotes["origin"].Url; } commits.Add(new GitCommit { Author = com.Author.Name, AuthorEmail = string.IsNullOrWhiteSpace(com.Author.Email) ? string.Empty : com.Author.Email, AuthorWhen = com.Author.When.UtcDateTime, Committer = com.Committer.Name, CommitterEmail = string.IsNullOrWhiteSpace(com.Committer.Email) ? string.Empty : com.Committer.Email, CommitterWhen = com.Committer.When.UtcDateTime, Sha = com.Sha, Message = com.Message, RepositoryFriendlyName = gitrepo.FriendlyName, RepositoryName = dir.Name, RepositoryUrl = repositoryUrl, CommitUrl = url, IsMerge = com.Parents.Count() > 1 }); } } catch { // nothing } } } catch (Exception) { // do nothing } } } } return(commits); } catch (Exception ex) { this.locallogger.LogError("Bad - ", ex); } return(commits); }
private Tree EmptyTree(Repository repo) { return(repo.Lookup <Tree>(repo.Tags[EMPTY_TREE].Target.Id)); }
public TreeEntryModel GetBlob(string path) { string referenceName; var commit = GetCommitByPath(ref path, out referenceName); if (commit == null) { return(null); } var entry = commit[path]; if (entry == null || entry.TargetType != TreeEntryTargetType.Blob) { return(null); } var blob = (Blob)entry.Target; var lastCommitSha = GitCache.Get <string>(blob.Sha, "affectedcommit"); if (lastCommitSha == null) { var hs = new HashSet <string>(); var queue = new Queue <Commit>(); queue.Enqueue(commit); hs.Add(commit.Sha); while (queue.Count > 0) { commit = queue.Dequeue(); var has = false; foreach (var parent in commit.Parents) { var tree = parent[path]; if (tree == null) { continue; } var eq = tree.Target.Sha == blob.Sha; if (eq && hs.Add(parent.Sha)) { queue.Enqueue(parent); } has = has || eq; } if (!has) { break; } } lastCommitSha = commit.Sha; GitCache.Set(blob.Sha, "affectedcommit", lastCommitSha); } if (lastCommitSha != commit.Sha) { commit = _repository.Lookup <Commit>(lastCommitSha); } var data = blob.GetContentStream().ToBytes(); var encoding = FileHelper.DetectEncoding(data, CpToEncoding(commit.Encoding), _i18n.Value); var extension = Path.GetExtension(entry.Name).ToLower(); var model = new TreeEntryModel { Name = entry.Name, ReferenceName = referenceName, Sha = commit.Sha, Path = string.IsNullOrEmpty(path) ? "" : path, Commit = new CommitModel { Sha = commit.Sha, Author = commit.Author, Committer = commit.Committer, CommitMessage = commit.Message.RepetitionIfEmpty(NoCommitMessage), CommitMessageShort = commit.MessageShort.RepetitionIfEmpty(NoCommitMessage), Parents = commit.Parents.Select(s => s.Sha).ToArray() }, EntryType = entry.TargetType, RawData = data, SizeString = FileHelper.GetSizeString(data.Length), TextContent = encoding == null ? null : FileHelper.ReadToEnd(data, encoding), TextBrush = FileHelper.BrushMapping.ContainsKey(extension) ? FileHelper.BrushMapping[extension] : "no-highlight", BlobType = encoding == null ? FileHelper.ImageSet.Contains(extension) ? BlobType.Image : BlobType.Binary : extension == ".md" ? BlobType.MarkDown : BlobType.Text, BlobEncoding = encoding, BranchSelector = GetBranchSelectorModel(referenceName, commit.Sha, path), PathBar = new PathBarModel { Name = Name, Action = "Tree", Path = path, ReferenceName = referenceName, ReferenceSha = commit.Sha, HideLastSlash = true, }, }; return(model); }
static bool HandleSingle(string path, string hash) { using (var repo = new Repository(path)) return(repo.Lookup <Commit> (hash) != null); }
string TryFindCommit(RepositoryInfoOptions options, Repository r, out Commit commit, out CIBranchVersionMode ciVersionMode, out string branchNameForCIVersion) { ciVersionMode = CIBranchVersionMode.None; commit = null; branchNameForCIVersion = null; string commitSha = options.StartingCommitSha; // Find current commit (the head) if none is provided. if (string.IsNullOrWhiteSpace(commitSha)) { IEnumerable <string> branchNames; if (string.IsNullOrWhiteSpace(options.StartingBranchName)) { // locCommit is here because one cannot use an out parameter inside a lambda. var locCommit = commit = r.Head.Tip; if (locCommit == null) { return("Unitialized Git repository."); } // Save the branches! // By doing this, when we are in 'Detached Head' state (the head of the repository is on a commit and not on a branch: git checkout <sha>), // we can detect that it is the head of a branch and hence apply possible options (mainly CI) for it. // We take into account only the branches from options.RemoteName remote here. string branchName = r.Head.FriendlyName; if (branchName == "(no branch)") { string remotePrefix = options.RemoteName + '/'; branchNames = r.Branches .Where(b => b.Tip == locCommit && (!b.IsRemote || b.FriendlyName.StartsWith(remotePrefix))) .Select(b => b.IsRemote ? b.FriendlyName.Substring(remotePrefix.Length) : b.FriendlyName); } else { branchNames = new[] { branchName } }; } else { string remotePrefix = options.RemoteName + '/'; string localBranchName = options.StartingBranchName.StartsWith(remotePrefix) ? options.StartingBranchName.Substring(remotePrefix.Length) : options.StartingBranchName; Branch br = r.Branches[options.StartingBranchName]; if (br == null && ReferenceEquals(localBranchName, options.StartingBranchName)) { string remoteName = remotePrefix + options.StartingBranchName; br = r.Branches[remoteName]; if (br == null) { return($"Unknown StartingBranchName: '{options.StartingBranchName}' (also tested on remote '{remoteName}')."); } } if (br == null) { return($"Unknown (remote) StartingBranchName: '{options.StartingBranchName}'."); } commit = br.Tip; branchNames = new[] { localBranchName }; } RepositoryInfoOptionsBranch bOpt; if (options.Branches != null && (bOpt = options.Branches.FirstOrDefault(b => branchNames.Contains(b.Name))) != null && bOpt.CIVersionMode != CIBranchVersionMode.None) { ciVersionMode = bOpt.CIVersionMode; branchNameForCIVersion = string.IsNullOrWhiteSpace(bOpt.VersionName) ? bOpt.Name : bOpt.VersionName; } } else { commit = r.Lookup <Commit>(commitSha); if (commit == null) { return($"Commit '{commitSha}' not found."); } } return(null); }
private void AddCommit(string commitSha) { var commit = _repository.Lookup(commitSha, GitObjectType.Commit) as Commit; AddCommit(commit); }
/// <summary> /// Looks up a commit by an integer that captures the first for bytes of its ID. /// </summary> /// <param name="repo">The repo to search for a matching commit.</param> /// <param name="truncatedId">The value returned from <see cref="GetTruncatedCommitIdAsInt32(Commit)"/>.</param> /// <returns>A matching commit.</returns> public static Commit GetCommitFromTruncatedIdInteger(this Repository repo, int truncatedId) { byte[] rawId = BitConverter.GetBytes(truncatedId); return(repo.Lookup <Commit>(EncodeAsHex(rawId))); }
public static async Task <ConfigurationState <RunnerRepoInfo> > CheckoutRunnerRepository( string proj, string localRepoDir, GitPatcherVersioning patcherVersioning, NugetVersioningTarget nugetVersioning, Action <string>?logger, CancellationToken cancel, bool compile = true) { try { cancel.ThrowIfCancellationRequested(); logger?.Invoke($"Targeting {patcherVersioning}"); using var repo = new Repository(localRepoDir); var runnerBranch = repo.Branches[RunnerBranch] ?? repo.CreateBranch(RunnerBranch); repo.Reset(ResetMode.Hard); Commands.Checkout(repo, runnerBranch); string?targetSha; string?target; bool fetchIfMissing = patcherVersioning.Versioning switch { PatcherVersioningEnum.Commit => true, _ => false }; switch (patcherVersioning.Versioning) { case PatcherVersioningEnum.Tag: if (string.IsNullOrWhiteSpace(patcherVersioning.Target)) { return(GetResponse <RunnerRepoInfo> .Fail("No tag selected")); } repo.Fetch(); targetSha = repo.Tags[patcherVersioning.Target]?.Target.Sha; if (string.IsNullOrWhiteSpace(targetSha)) { return(GetResponse <RunnerRepoInfo> .Fail("Could not locate tag")); } target = patcherVersioning.Target; break; case PatcherVersioningEnum.Commit: targetSha = patcherVersioning.Target; if (string.IsNullOrWhiteSpace(targetSha)) { return(GetResponse <RunnerRepoInfo> .Fail("Could not locate commit")); } target = patcherVersioning.Target; break; case PatcherVersioningEnum.Branch: if (string.IsNullOrWhiteSpace(patcherVersioning.Target)) { return(GetResponse <RunnerRepoInfo> .Fail($"Target branch had no name.")); } repo.Fetch(); var targetBranch = repo.Branches[$"origin/{patcherVersioning.Target}"]; if (targetBranch == null) { return(GetResponse <RunnerRepoInfo> .Fail($"Could not locate branch: {patcherVersioning.Target}")); } targetSha = targetBranch.Tip.Sha; target = patcherVersioning.Target; break; default: throw new NotImplementedException(); } if (!ObjectId.TryParse(targetSha, out var objId)) { return(GetResponse <RunnerRepoInfo> .Fail("Malformed sha string")); } cancel.ThrowIfCancellationRequested(); var commit = repo.Lookup(objId, ObjectType.Commit) as Commit; if (commit == null) { if (!fetchIfMissing) { return(GetResponse <RunnerRepoInfo> .Fail("Could not locate commit with given sha")); } repo.Fetch(); commit = repo.Lookup(objId, ObjectType.Commit) as Commit; if (commit == null) { return(GetResponse <RunnerRepoInfo> .Fail("Could not locate commit with given sha")); } } cancel.ThrowIfCancellationRequested(); var slnPath = GitPatcherRun.GetPathToSolution(localRepoDir); if (slnPath == null) { return(GetResponse <RunnerRepoInfo> .Fail("Could not locate solution to run.")); } var foundProjSubPath = SolutionPatcherRun.AvailableProject(slnPath, proj); if (foundProjSubPath == null) { return(GetResponse <RunnerRepoInfo> .Fail($"Could not locate target project file: {proj}.")); } cancel.ThrowIfCancellationRequested(); logger?.Invoke($"Checking out {targetSha}"); repo.Reset(ResetMode.Hard, commit, new CheckoutOptions()); var projPath = Path.Combine(localRepoDir, foundProjSubPath); cancel.ThrowIfCancellationRequested(); logger?.Invoke($"Mutagen Nuget: {nugetVersioning.MutagenVersioning} {nugetVersioning.MutagenVersion}"); logger?.Invoke($"Synthesis Nuget: {nugetVersioning.SynthesisVersioning} {nugetVersioning.SynthesisVersion}"); GitPatcherRun.SwapInDesiredVersionsForSolution( slnPath, drivingProjSubPath: foundProjSubPath, mutagenVersion: nugetVersioning.MutagenVersioning == NugetVersioningEnum.Match ? null : nugetVersioning.MutagenVersion, listedMutagenVersion: out var listedMutagenVersion, synthesisVersion: nugetVersioning.SynthesisVersioning == NugetVersioningEnum.Match ? null : nugetVersioning.SynthesisVersion, listedSynthesisVersion: out var listedSynthesisVersion); // Compile to help prep if (compile) { var compileResp = await SolutionPatcherRun.CompileWithDotnet(projPath, cancel); if (compileResp.Failed) { return(compileResp.BubbleFailure <RunnerRepoInfo>()); } } return(GetResponse <RunnerRepoInfo> .Succeed( new RunnerRepoInfo( slnPath : slnPath, projPath : projPath, target : target, commitMsg : commit.Message, commitDate : commit.Author.When.LocalDateTime, listedSynthesis : listedSynthesisVersion, listedMutagen : listedMutagenVersion))); } catch (OperationCanceledException) { throw; } catch (Exception ex) { return(GetResponse <RunnerRepoInfo> .Fail(ex)); } }
public IEnumerable <Change> GetChanges(string since, string extensionFilter) { using (var repo = new Repository(this.WorkingDirectory)) { var tree = repo.Head.Tip.Tree; var ancestor = repo.Lookup <Commit>(since).Tree; using (var changes = repo.Diff.Compare <TreeChanges>(ancestor, tree, extensionFilter.Split())) { foreach (var change in changes) { switch (change.Status) { case ChangeKind.Added: { var entry = tree[change.Path]; var blob = (Blob)entry.Target; var contentStream = blob.GetContentStream(); using (var tr = new StreamReader(contentStream, Encoding.UTF8)) { string content = tr.ReadToEnd(); yield return(new Change(GetFilePath(change.Path), "", content, ChangeType.Addition)); } } break; case ChangeKind.Modified: { var oldEntry = ancestor[change.OldPath]; var newEntry = tree[change.Path]; var oldBlob = (Blob)oldEntry.Target; var newBlob = (Blob)newEntry.Target; var oldContentStream = oldBlob.GetContentStream(); var newContentStream = newBlob.GetContentStream(); using (var oldTr = new StreamReader(oldContentStream, Encoding.UTF8)) using (var newTr = new StreamReader(newContentStream, Encoding.UTF8)) { string oldContent = oldTr.ReadToEnd(); string newContent = newTr.ReadToEnd(); yield return(new Change(GetFilePath(change.Path), oldContent, newContent, ChangeType.Modification)); } } break; case ChangeKind.Deleted: { var entry = ancestor[change.OldPath]; var blob = (Blob)entry.Target; var contentStream = blob.GetContentStream(); using (var tr = new StreamReader(contentStream, Encoding.UTF8)) { string content = tr.ReadToEnd(); yield return(new Change(GetFilePath(change.OldPath), "", content, ChangeType.Deletion)); } } break; } } } } }
public void StartExternalDiff(ITextDocument textDocument) { if (textDocument == null || string.IsNullOrEmpty(textDocument.FilePath)) { return; } var filename = textDocument.FilePath; var repositoryPath = GetGitRepository(Path.GetFullPath(filename)); if (repositoryPath == null) { return; } using (var repo = new Repository(repositoryPath)) { string workingDirectory = repo.Info.WorkingDirectory; string relativePath = Path.GetFullPath(filename); if (relativePath.StartsWith(workingDirectory, StringComparison.OrdinalIgnoreCase)) { relativePath = relativePath.Substring(workingDirectory.Length); } // the name of the object in the database string objectName = Path.GetFileName(filename); Blob oldBlob = null; var indexEntry = repo.Index[relativePath]; if (indexEntry != null) { objectName = Path.GetFileName(indexEntry.Path); oldBlob = repo.Lookup <Blob>(indexEntry.Id); } var tempFileName = Path.GetTempFileName(); if (oldBlob != null) { File.WriteAllText(tempFileName, oldBlob.GetContentText(new FilteringOptions(relativePath))); } IVsDifferenceService differenceService = _serviceProvider.GetService(typeof(SVsDifferenceService)) as IVsDifferenceService; if (differenceService != null) { string leftFileMoniker = tempFileName; // The difference service will automatically load the text from the file open in the editor, even if // it has changed. string rightFileMoniker = filename; string actualFilename = objectName; string tempPrefix = Path.GetRandomFileName().Substring(0, 5); string caption = string.Format("{0}_{1} vs. {1}", tempPrefix, actualFilename); string tooltip = null; string leftLabel; if (indexEntry != null) { // determine if the file has been staged string revision; var stagedMask = FileStatus.NewInIndex | FileStatus.ModifiedInIndex; if ((repo.RetrieveStatus(relativePath) & stagedMask) != 0) { revision = "index"; } else { revision = repo.Head.Tip.Sha.Substring(0, 7); } leftLabel = string.Format("{0}@{1}", objectName, revision); } else if (oldBlob != null) { // file was added leftLabel = null; } else { // we just compared to head leftLabel = string.Format("{0}@{1}", objectName, repo.Head.Tip.Sha.Substring(0, 7)); } string rightLabel = filename; string inlineLabel = null; string roles = null; __VSDIFFSERVICEOPTIONS grfDiffOptions = __VSDIFFSERVICEOPTIONS.VSDIFFOPT_LeftFileIsTemporary; differenceService.OpenComparisonWindow2(leftFileMoniker, rightFileMoniker, caption, tooltip, leftLabel, rightLabel, inlineLabel, roles, (uint)grfDiffOptions); // Since the file is marked as temporary, we can delete it now File.Delete(tempFileName); } else { // Can't use __VSDIFFSERVICEOPTIONS, so mark the temporary file(s) read only on disk File.SetAttributes(tempFileName, File.GetAttributes(tempFileName) | FileAttributes.ReadOnly); string remoteFile; if (textDocument.IsDirty) { remoteFile = Path.GetTempFileName(); File.WriteAllBytes(remoteFile, GetCompleteContent(textDocument, textDocument.TextBuffer.CurrentSnapshot)); File.SetAttributes(remoteFile, File.GetAttributes(remoteFile) | FileAttributes.ReadOnly); } else { remoteFile = filename; } var diffGuiTool = repo.Config.Get <string>("diff.guitool"); if (diffGuiTool == null) { diffGuiTool = repo.Config.Get <string>("diff.tool"); if (diffGuiTool == null) { return; } } var diffCmd = repo.Config.Get <string>("difftool." + diffGuiTool.Value + ".cmd"); if (diffCmd == null || diffCmd.Value == null) { return; } var cmd = diffCmd.Value.Replace("$LOCAL", tempFileName).Replace("$REMOTE", remoteFile); string fileName = Regex.Match(cmd, ParameterPattern).Value; string arguments = cmd.Substring(fileName.Length); ProcessStartInfo startInfo = new ProcessStartInfo(fileName, arguments); Process.Start(startInfo); } } }
public GitCommitFileSystem Tag(Tag tag) { var commit = _repo.Lookup <Commit>(tag.Target.Id); return(new GitCommitFileSystem(_repo, commit)); }