diff --git a/.editorconfig b/.editorconfig
index 096ff2565..5021a5b28 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,6 +10,9 @@ trim_trailing_whitespace = true
insert_final_newline = true
; Not change VS generated files
-[*.{sln,csroj}]
+[*.{sln,csproj}]
trim_trailing_whitespace = false
insert_final_newline = false
+
+[*.{props,targets,csproj}]
+indent_size = 2
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE
new file mode 100644
index 000000000..c37520864
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE
@@ -0,0 +1,17 @@
+You are opening a _bug report_ against the LibGit2Sharp project: we
+use GitHub Issues for tracking bug reports and feature requests. If
+you have a question about an API or usage, please ask on StackOverflow:
+http://stackoverflow.com/questions/tagged/libgit2sharp.
+
+Otherwise, to report a bug, please fill out the reproduction steps
+(below) and delete these introductory paragraphs. Thanks!
+
+### Reproduction steps
+
+### Expected behavior
+
+### Actual behavior
+
+### Version of LibGit2Sharp (release number or SHA1)
+
+### Operating system(s) tested; .NET runtime tested
diff --git a/.github/workflows/libgit2sharp.yml b/.github/workflows/libgit2sharp.yml
new file mode 100644
index 000000000..e1eb6ff7c
--- /dev/null
+++ b/.github/workflows/libgit2sharp.yml
@@ -0,0 +1,80 @@
+name: .NET
+
+on:
+ push:
+ branches:
+ - dotdevelop
+ pull_request:
+ branches:
+ - dotdevelop
+
+jobs:
+ build:
+
+ runs-on: ubuntu-20.04
+
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: 3.1.401
+ - name: Restore dependencies
+ run: dotnet restore LibGit2Sharp.sln
+ - name: Build
+ run: dotnet build --no-restore LibGit2Sharp.sln
+ - name: Pack
+ run: |
+ echo running on branch $(echo ${GITHUB_SHA} | cut -c1-10)
+ dotnet pack --include-symbols -c Release LibGit2Sharp.sln
+ ls ./bin/Packages/Release/
+
+ - name: Short Sha
+ id: short-sha
+ run: echo "::set-output name=short_sha::$(echo ${GITHUB_SHA} | cut -c1-10)"
+
+ - name: Push generated package to GitHub registry
+ run: dotnet nuget push ./bin/Packages/Release/LibGit2Sharp.0.27.0-preview-g${{steps.short-sha.outputs.short_sha}}.nupkg --source https://nuget.pkg.github.com/dotdevelop --api-key ${{github.token}} --skip-duplicate --no-symbols true
+
+ - name: Create Release
+ id: create_release
+ uses: actions/create-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ github.ref }}
+ release_name: Release ${{ github.ref }}
+ draft: true
+ prerelease: true
+ - name: Upload Release Asset
+ id: upload-release-asset
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ SHORT_SHA: ${{ steps.short-sha.outputs.short_sha }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
+ asset_path: ./bin/Packages/Release/LibGit2Sharp.0.27.0-preview-g${{steps.short-sha.outputs.short_sha}}.nupkg
+ asset_name: LibGit2Sharp.0.27.0-preview-g${{steps.short-sha.outputs.short_sha}}.nupkg
+ asset_content_type: application/nupkg
+
+ test:
+ runs-on: ubuntu-20.04
+
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: 3.1.401
+ - name: Restore dependencies
+ run: dotnet restore LibGit2Sharp.sln
+ - name: Build
+ run: dotnet build --no-restore LibGit2Sharp.sln
+
+ - name: Test
+ run: dotnet test --no-build --verbosity normal LibGit2Sharp.sln
diff --git a/.gitignore b/.gitignore
index 6a6337edb..6ec9f6ae8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ Thumbs.db
*_p.c
*.ncb
*.suo
+.vs/
*.sln.ide/
*.tlb
*.tlh
@@ -35,10 +36,9 @@ _ReSharper*/
*.userprefs
*.swp
*.DotSettings
-#Ignore custom generated files
-LibGit2Sharp/Core/UniqueIdentifier.cs
-LibGit2Sharp/Core/NativeDllName.cs
-!nuget.package/build/
_NCrunch_LibGit2Sharp/
packages/
+worktree.playlist
+
+.idea/
diff --git a/.nuget/packages.config b/.nuget/packages.config
deleted file mode 100644
index 05ac50048..000000000
--- a/.nuget/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/.travis.yml b/.travis.yml
index 5ab00c105..18e8b5c24 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,32 +1,7 @@
-# Travis-CI Build for libgit2sharp
-# see travis-ci.org for details
+language: csharp
+mono: none
-language: c
-
-os:
- - osx
- - linux
-
-before_install:
- - date -u
- - uname -a
- - export PATH=/opt/mono/bin:$PATH
- - env | sort
-
-# Make sure CMake and Mono are installed
-install: ./CI/travis.${TRAVIS_OS_NAME}.install.deps.sh
-
-# Build libgit2, LibGit2Sharp and run the tests
-script:
- - ./build.libgit2sharp.sh 'LEAKS_IDENTIFYING'
-
-# Only watch the development branch
+# Disable Travis-CI
branches:
only:
- - vNext
- - master
-
-# Notify of build changes
-notifications:
- email:
- - emeric.fermas@gmail.com
+ - NOTTHISONE
diff --git a/CHANGES.md b/CHANGES.md
index 3fbecda78..78bd537f6 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,135 @@
- Windows (x86/amd64):
- Linux/Mac OS X:
+## v0.26 - ([diff](https://github.com/libgit2/libgit2sharp/compare/v0.25..v0.26))
+
+### Additions
+
+* Add `CherryPickCommitIntoIndex` to `ObjectDatabase`
+* The underlying native library (libgit2) now no longer relies on libcurl
+* The underlying native library now no longer relies on zlib
+* Add `IndentHeuristic` option to `CompareOptions`
+
+## v0.25 - ([diff](https://github.com/libgit2/libgit2sharp/compare/v0.24..v0.25))
+
+LibGit2Sharp is now .NET Core 2.0+ and .NET Framework compatible.
+
+### Additions
+
+ - `GitObject` now has a `Peel` method that will let you peel (for example)
+ a `Tag` to a `Tree`.
+ - `MergeOptions` now includes an option to `IgnoreWhitespaceChanges`.
+ - `TreeDefinition` can now `Add` an object with only the ID, which allows
+ users of large files to add entries without realizing a `Blob`.
+ - `ObjectDatabase` can now `Write` a `Stream`, which allows users of
+ large files to stream an object into storage without loading it into
+ memory.
+ - `ObjectDatabase` can now `MergeCommitsIntoIndex` allowing users to perform
+ an in-memory merge that produces an `Index` structure with conflicts.
+ - Users can enable or disable dependent object existence checks when
+ creating new objects with `GlobalSettings.SetEnableStrictObjectCreation`
+ - Users can enable or disable `ofs_delta` support with
+ `GlobalSettings.SetEnableOfsDelta`
+
+### Changes
+
+ - Status now does not show untracked files by default. To retrieve
+ untracked files, included the `StatusOptions.IncludeUntracked` and/or
+ the `StatusOptions.RecurseUntrackedDirs` options.
+ - Status now does not show the ignored files by default. To retrieve
+ ignored files, include the `StatusOptions.IncludeIgnored` option.
+ - `Commands.Pull` can now provide a `null` value for `PullOptions`,
+ which indicates that default values should be used.
+
+### Fixes
+
+ - The exception thrown when the native library cannot be loaded is now
+ able to be caught and will no longer crash the process.
+ - Getting the `Notes` collection from a `Repository` no longer throws an
+ exception when the repository has no notes.
+
+## v0.24 - ([diff](https://github.com/libgit2/libgit2sharp/compare/v0.23..v0.24))
+
+This is the last release before a moving to .NET Core compatible library.
+
+It will be the last supported release with the prior architecture; as a
+result, this release is primarily bugfixes and does not include major new
+APIs.
+
+## v0.23 - ([diff](https://github.com/libgit2/libgit2sharp/compare/v0.22..v0.23))
+
+### Additions
+
+ - Add `CherryPickCommit` and `RevertCommit` to `ObjectDatabase`.
+ - Add `IncludeIgnored` field to `SatusOptions`.
+ - Add `Commit.CreateBuffer` to write a commit object to a buffer and
+ `ObjectDatabase.CreateCommitWithSignature` to create commits which include a
+ signature.
+ - Add `Commit.ExtractSignature` to get a commit's signature.
+ - Add `ObjectDatabase.Write` to write arbitrary objects to the object db.
+ - Add `Commit.PrettifyMessage`
+
+
+### Changes
+
+ - The native libraries are now expected to be in the `lib` directory,
+ instead of `NativeBinaries` for improved mono compatibility. In
+ addition, the names of platform architectures now better reflect
+ the vendor naming (eg, `x86_64` instead of `amd64` on Linux).
+ - Deprecate the config paths in RepositoryOptions
+ - Deprecate the `QueryBy` overload with `FollowFilter`.
+ - Deprecate `Branch.Remote` in favour of `Branch.RemoteName`
+ - `Remote` no longer implement the equality operator.
+ - `Remote.Update` takes a remote name instead of an instance.
+ - `Fetch`, `Pull`, `Move`, `Remove`, `Stage` are now in a commands namespace to
+ indicate what they represent.
+
+## v0.22 - ([diff](https://github.com/libgit2/libgit2sharp/compare/v0.21.1...v0.22))
+
+### Additions
+
+ - Add CustomHeaders in the push options (#1217)
+ - Expose the minimal diff algorithm (#1229)
+ - Expose Reset() with checkout options (#1219)
+ - Add a prettify option to history rewrite options (#1185)
+ - Add option to describe to only follow the first parent (#1190)
+ - Allow setting the config search path (#1123)
+ - Provide access to the remote's host HTTPS certificate (#1134)
+ - Add support for rebase (#964)
+ - ListReferences() now accepts a credentials provider (#1099)
+ - Introduce FileStatus.Conflicted and introduce staging of conflicts (#1062)
+ - Support streaming filters written in C# (#1030)
+ - Add support for the pre-push callback (#1061)
+ - Add support for listing remote references without a Repository instance (#1065)
+ - Add StashCollection.Apply() and .Pop() (#1068)
+ - Support retrieving a configuration for a repository without instantiating it (#1042)
+ - Implement 'log --follow'-like functionality (#963)
+ - Introduce in-memory merging via Repository.MergeCommits() (#990)
+ - Allow setting whether to prune during a fetch (#1258)
+
+### Changes
+
+ - Deprecate MergeConflictException in a backwards-compatible way (#1243)
+ - Improve type safety in the generic type for Diff.Compare() (#1180)
+ - Obsolete Repository.Commit(), NoteCollection.Add() and
+ NoteCollection.Remove() overloads which do not require a signature (#1173)
+ - BuildSignature() no longer tries to build a signature from the
+ environment if there is none configured (#1171)
+ - Rename the commit walker's Since to IncludeReachableFrom and Until to ExcludeReachableFrom (#1069)
+ - Rename MergeConflictException to CheckoutConflictException to more
+ accurately reflect what it means (#1059)
+ - Specify the diff algorithm instead of setting a boolean to use patience (#1043)
+ - Remove optional parameters (#1031)
+ - Move Repository.Reset(paths) into Index (#959)
+ - Move FindMergeBase() overloads to ObjectDatabase (#957)
+
+### Fixes
+
+ - ListReferences() is now able to handle symbolic references (#1132)
+ - Repository.IsValid() returns false on empty paths (#1156)
+ - The included version of libgit2 includes racy-git support
+ - Fix a racy NRE in the filters (#1113)
+
## v0.21.1 - ([diff](https://github.com/libgit2/libgit2sharp/compare/v0.21...v0.21.1))
### Changes
diff --git a/CI/build.msbuild b/CI/build.msbuild
deleted file mode 100644
index 89a3ead0e..000000000
--- a/CI/build.msbuild
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
- Release
- $(MSBuildProjectDirectory)\..
- $(RootDir)\LibGit2Sharp.Tests\bin\$(Configuration)
- $(RootDir)\Build
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/CI/travis.linux.install.deps.sh b/CI/travis.linux.install.deps.sh
deleted file mode 100755
index 365fc51a6..000000000
--- a/CI/travis.linux.install.deps.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-set -ev
-
-sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-
-echo "deb http://download.mono-project.com/repo/debian wheezy/snapshots/3.12.0 main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
-echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
-
-sudo apt-get update
-sudo apt-get install mono-devel cmake
diff --git a/CI/travis.osx.install.deps.sh b/CI/travis.osx.install.deps.sh
deleted file mode 100755
index c6621b735..000000000
--- a/CI/travis.osx.install.deps.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-set -ev
-
-MONO_VER=3.6.0
-
-brew update
-which cmake || brew install cmake
-
-wget "http://download.mono-project.com/archive/${MONO_VER}/macos-10-x86/MonoFramework-MDK-${MONO_VER}.macos10.xamarin.x86.pkg"
-sudo installer -pkg "MonoFramework-MDK-${MONO_VER}.macos10.xamarin.x86.pkg" -target /
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..218cb2a28
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,58 @@
+# How to Contribute
+
+We love Pull Requests! Your contributions help make LibGit2Sharp great.
+
+## Getting Started
+
+So you want to contribute to LibGit2Sharp. Great! Contributions take many forms from
+submitting issues, writing documentation, to making code changes. We welcome it all.
+
+But first things first...
+
+* Make sure you have a [GitHub account](https://github.com/signup/free)
+* Submit a ticket for your issue, assuming one does not already exist.
+ * Clearly describe the issue including steps to reproduce when it is a bug.
+ * Make sure you fill in the earliest version that you know has the issue.
+* Fork the repository on GitHub, then clone it using your favorite Git client.
+* Make sure the project builds and all tests pass on your machine by running
+ the `buildandtest.cmd` script on Windows or `buildandtest.sh` on Linux/Mac.
+
+## LibGit2
+
+LibGit2Sharp brings all the might and speed of libgit2, a native Git implementation, to the managed world of .Net and Mono.
+LibGit2 is a git submodule referencing the [libgit2 project](https://github.com/libgit2/libgit2). To learn more about
+submodules read [here](http://git-scm.com/book/en/v2/Git-Tools-Submodules).
+To build libgit2 see [here](https://github.com/libgit2/libgit2sharp/wiki/How-to-build-x64-libgit2-and-LibGit2Sharp).
+
+## Making Changes
+
+Make sure you have the required .NET Core SDK and runtimes installed.
+The easiest way to do this is run our `tools\Install-DotNetSdk.ps1` script.
+Using the `-InstallLocality Machine` switch requires elevation but ensures
+that Visual Studio will be able to load the solution even when launched from a shortcut.
+
+Then proceed to:
+
+* Create a topic branch off master (don't work directly on master).
+* Implement your feature or fix your bug. Please following existing coding styles and do not introduce new ones.
+* Make atomic, focused commits with good commit messages.
+* Make sure you have added the necessary tests for your changes.
+* Run _all_ the tests to assure nothing else was accidentally broken.
+
+## Submitting Changes
+
+* Push your changes to a topic branch in your fork of the repository.
+* Send a Pull Request targeting the master branch. Note what issue/issues your patch fixes.
+
+Some things that will increase the chance that your pull request is accepted.
+
+* Following existing code conventions.
+* Including unit tests that would otherwise fail without the patch, but pass after applying it.
+* Updating the documentation and tests that are affected by the contribution.
+* If code from elsewhere is used, proper credit and a link to the source should exist in the code comments.
+ Then licensing issues can be checked against LibGit2Sharp's very permissive MIT based open source license.
+* Having a configured git client that converts line endings to LF. [See here.](https://help.github.com/articles/dealing-with-line-endings/).
+# Additional Resources
+
+* [General GitHub documentation](http://help.github.com/)
+* [GitHub pull request documentation](https://help.github.com/articles/using-pull-requests/)
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 000000000..d98520a64
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,14 @@
+
+
+
+ true
+ $(MSBuildThisFileDirectory)bin\$(MSBuildProjectName)\$(Configuration)\
+ $(MSBuildThisFileDirectory)obj\$(MSBuildProjectName)\
+ $(MSBuildThisFileDirectory)bin\Packages\$(Configuration)\
+ $(DefineConstants);$(ExtraDefine)
+
+
+
+
+
+
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 000000000..0209658db
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,14 @@
+
+
+ cobertura
+ [xunit.*]*
+
+ $(OutputPath)/
+
+
+
+
+
+
+
diff --git a/Lib/.gitattributes b/Lib/.gitattributes
deleted file mode 100644
index 2fa88711b..000000000
--- a/Lib/.gitattributes
+++ /dev/null
@@ -1,3 +0,0 @@
-* binary
-.gitattributes text -binary
-*.txt text -binary
diff --git a/Lib/CustomBuildTasks/CustomBuildTasks.csproj b/Lib/CustomBuildTasks/CustomBuildTasks.csproj
deleted file mode 100644
index 1c50a44aa..000000000
--- a/Lib/CustomBuildTasks/CustomBuildTasks.csproj
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {B6138573-A4B9-44E7-83C2-8964CAF51EDA}
- Library
- Properties
- CustomBuildTasks
- CustomBuildTasks
- v3.5
- 512
-
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Lib/CustomBuildTasks/CustomBuildTasks.dll b/Lib/CustomBuildTasks/CustomBuildTasks.dll
deleted file mode 100644
index 5bc63169d..000000000
Binary files a/Lib/CustomBuildTasks/CustomBuildTasks.dll and /dev/null differ
diff --git a/Lib/CustomBuildTasks/GenerateNativeDllNameTask.cs b/Lib/CustomBuildTasks/GenerateNativeDllNameTask.cs
deleted file mode 100644
index f68724978..000000000
--- a/Lib/CustomBuildTasks/GenerateNativeDllNameTask.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.IO;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace CustomBuildTasks
-{
- public class GenerateNativeDllNameTask : Task
- {
- public ITaskItem InputHashFile { get; set; }
-
- public string OutputFile { get; set; }
-
- public override bool Execute()
- {
- var fileName = InputHashFile.GetMetadata("FullPath");
- string hash;
-
- using (var sr = new StreamReader(fileName))
- {
- hash = sr.ReadLine();
- }
-
- var shortHash = hash.Substring(0, 7);
-
- var nativeDllName = @"namespace LibGit2Sharp.Core
-{{
- internal static class NativeDllName
- {{
- public const string Name = ""git2-{0}"";
- }}
-}}
-";
-
- using (var sw = new StreamWriter(OutputFile))
- {
- sw.Write(nativeDllName, shortHash);
- }
-
- return true;
- }
- }
-}
diff --git a/Lib/CustomBuildTasks/GenerateUniqueIdentifierTask.cs b/Lib/CustomBuildTasks/GenerateUniqueIdentifierTask.cs
deleted file mode 100644
index 2f26ac94d..000000000
--- a/Lib/CustomBuildTasks/GenerateUniqueIdentifierTask.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.IO;
-using System.Text;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-
-namespace CustomBuildTasks
-{
- public class GenerateUniqueIdentifierTask : Task
- {
- public override bool Execute()
- {
- using (FileStream fs = new FileStream(this.OutputFile, FileMode.Create, FileAccess.Write, FileShare.None))
- using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
- {
- sw.WriteLine("using System;");
- sw.WriteLine();
- sw.WriteLine("namespace LibGit2Sharp.Core");
- sw.WriteLine("{");
- sw.WriteLine(" internal static class UniqueId");
- sw.WriteLine(" {");
- sw.WriteLine(" public const String UniqueIdentifier = \"" + Guid.NewGuid().ToString() + "\";");
- sw.WriteLine(" }");
- sw.WriteLine("}");
- }
-
- return true;
- }
-
- public String OutputFile
- {
- get;
- set;
- }
- }
-}
diff --git a/Lib/NuGet/NuGet.exe b/Lib/NuGet/NuGet.exe
deleted file mode 100644
index ed2b0a221..000000000
Binary files a/Lib/NuGet/NuGet.exe and /dev/null differ
diff --git a/Lib/NuGet/NuGet.license.txt b/Lib/NuGet/NuGet.license.txt
deleted file mode 100644
index 48715cacc..000000000
--- a/Lib/NuGet/NuGet.license.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
-
-1. Definitions
-
-The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
-
-A "contribution" is the original software, or any additions or changes to the software.
-
-A "contributor" is any person that distributes its contribution under this license.
-
-"Licensed patents" are a contributor's patent claims that read directly on its contribution.
-
-2. Grant of Rights
-
-(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
-
-(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
-
-3. Conditions and Limitations
-
-(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
-
-(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
-
-(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
-
-(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
-
-(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
diff --git a/LibGit2Sharp.Tests/ArchiveFixture.cs b/LibGit2Sharp.Tests/ArchiveFixture.cs
index 7253e2fe8..19860ca0b 100644
--- a/LibGit2Sharp.Tests/ArchiveFixture.cs
+++ b/LibGit2Sharp.Tests/ArchiveFixture.cs
@@ -18,6 +18,8 @@ public void CanArchiveATree()
var archiver = new MockArchiver();
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
repo.ObjectDatabase.Archive(tree, archiver);
var expected = new ArrayList
@@ -30,7 +32,7 @@ public void CanArchiveATree()
};
Assert.Equal(expected, archiver.Files);
Assert.Null(archiver.ReceivedCommitSha);
- Assert.InRange(archiver.ModificationTime, DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMilliseconds(100)), DateTimeOffset.UtcNow);
+ Assert.InRange(archiver.ModificationTime, before, DateTimeOffset.UtcNow);
}
}
@@ -66,8 +68,10 @@ public void ArchivingANullTreeOrCommitThrows()
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
- Assert.Throws(() => repo.ObjectDatabase.Archive((Commit)null, null));
- Assert.Throws(() => repo.ObjectDatabase.Archive((Tree)null, null));
+ Assert.Throws(() => repo.ObjectDatabase.Archive(default(Commit), default(ArchiverBase)));
+ Assert.Throws(() => repo.ObjectDatabase.Archive(default(Commit), default(string)));
+ Assert.Throws(() => repo.ObjectDatabase.Archive(default(Tree), default(ArchiverBase)));
+ Assert.Throws(() => repo.ObjectDatabase.Archive(default(Tree), default(string)));
}
}
diff --git a/LibGit2Sharp.Tests/ArchiveTarFixture.cs b/LibGit2Sharp.Tests/ArchiveTarFixture.cs
index a21847ea0..247a9a3b0 100644
--- a/LibGit2Sharp.Tests/ArchiveTarFixture.cs
+++ b/LibGit2Sharp.Tests/ArchiveTarFixture.cs
@@ -30,8 +30,8 @@ public void CanArchiveACommitWithDirectoryAsTar()
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))
+ using (var expectedStream = new StreamReader(File.OpenRead(Path.Combine(ResourcesDirectory.FullName, "expected_archives/commit_with_directory.tar"))))
+ using (var actualStream = new StreamReader(File.OpenRead(archivePath)))
{
string expected = expectedStream.ReadToEnd();
string actual = actualStream.ReadToEnd();
diff --git a/LibGit2Sharp.Tests/AttributesFixture.cs b/LibGit2Sharp.Tests/AttributesFixture.cs
index c9c4eb712..3ac8326d3 100644
--- a/LibGit2Sharp.Tests/AttributesFixture.cs
+++ b/LibGit2Sharp.Tests/AttributesFixture.cs
@@ -9,8 +9,7 @@ public class AttributesFixture : BaseFixture
[Fact]
public void StagingHonorsTheAttributesFiles()
{
- string path = SandboxStandardTestRepo();
- using (var repo = new Repository(path))
+ using (var repo = new Repository(InitNewRepository()))
{
CreateAttributesFile(repo);
@@ -30,7 +29,7 @@ private static void AssertNormalization(IRepository repo, string filename, bool
Touch(repo.Info.WorkingDirectory, filename, sb.ToString());
- repo.Stage(filename);
+ Commands.Stage(repo, filename);
IndexEntry entry = repo.Index[filename];
Assert.NotNull(entry);
diff --git a/LibGit2Sharp.Tests/BlameFixture.cs b/LibGit2Sharp.Tests/BlameFixture.cs
index 9138646c3..da63dc124 100644
--- a/LibGit2Sharp.Tests/BlameFixture.cs
+++ b/LibGit2Sharp.Tests/BlameFixture.cs
@@ -9,7 +9,7 @@ public class BlameFixture : BaseFixture
{
private static void AssertCorrectHeadBlame(BlameHunkCollection blame)
{
- Assert.Equal(1, blame.Count());
+ Assert.Single(blame);
Assert.Equal(0, blame[0].FinalStartLineNumber);
Assert.Equal("schacon@gmail.com", blame[0].FinalSignature.Email);
Assert.Equal("4a202b3", blame[0].FinalCommit.Id.ToString(7));
@@ -39,7 +39,7 @@ public void CanBlameFromADifferentCommit()
Assert.Throws(() => repo.Blame("ancestor-only.txt"));
var blame = repo.Blame("ancestor-only.txt", new BlameOptions { StartingAt = "9107b30" });
- Assert.Equal(1, blame.Count());
+ Assert.Single(blame);
}
}
@@ -79,7 +79,7 @@ public void CanStopBlame()
// 9fd738e8 (Scott Chacon 2010-05-24 10:19:19 -0700 1) my new file
// (be3563a comes after 9fd738e8)
var blame = repo.Blame("new.txt", new BlameOptions {StoppingAt = "be3563a"});
- Assert.True(blame[0].FinalCommit.Sha.StartsWith("be3563a"));
+ Assert.StartsWith("be3563a", blame[0].FinalCommit.Sha);
}
}
}
diff --git a/LibGit2Sharp.Tests/BlobFixture.cs b/LibGit2Sharp.Tests/BlobFixture.cs
index 4c984bd34..e6a5f3c57 100644
--- a/LibGit2Sharp.Tests/BlobFixture.cs
+++ b/LibGit2Sharp.Tests/BlobFixture.cs
@@ -63,7 +63,7 @@ public void CanGetBlobAsTextWithVariousEncodings(string encodingName, int expect
var bomPath = Touch(repo.Info.WorkingDirectory, bomFile, content, encoding);
Assert.Equal(expectedContentBytes, File.ReadAllBytes(bomPath).Length);
- repo.Stage(bomFile);
+ Commands.Stage(repo, bomFile);
var commit = repo.Commit("bom", Constants.Signature, Constants.Signature);
var blob = (Blob)commit.Tree[bomFile].Target;
@@ -190,7 +190,7 @@ public void CanStageAFileGeneratedFromABlobContentStream()
File.AppendAllText(Path.Combine(repo.Info.WorkingDirectory, "small.txt"), sb.ToString());
}
- repo.Stage("small.txt");
+ Commands.Stage(repo, "small.txt");
IndexEntry entry = repo.Index["small.txt"];
Assert.Equal("baae1fb3760a73481ced1fa03dc15614142c19ef", entry.Id.Sha);
@@ -202,7 +202,7 @@ public void CanStageAFileGeneratedFromABlobContentStream()
CopyStream(stream, file);
}
- repo.Stage("small.fromblob.txt");
+ Commands.Stage(repo, "small.fromblob.txt");
IndexEntry newentry = repo.Index["small.fromblob.txt"];
Assert.Equal("baae1fb3760a73481ced1fa03dc15614142c19ef", newentry.Id.Sha);
@@ -216,7 +216,7 @@ public void CanTellIfTheBlobContentLooksLikeBinary()
using (var repo = new Repository(path))
{
var blob = repo.Lookup("a8233120f6ad708f843d861ce2b7228ec4e3dec6");
- Assert.Equal(false, blob.IsBinary);
+ Assert.False(blob.IsBinary);
}
}
diff --git a/LibGit2Sharp.Tests/BranchFixture.cs b/LibGit2Sharp.Tests/BranchFixture.cs
index 43bcff91d..736b0faec 100644
--- a/LibGit2Sharp.Tests/BranchFixture.cs
+++ b/LibGit2Sharp.Tests/BranchFixture.cs
@@ -24,6 +24,8 @@ public void CanCreateBranch(string name)
const string committish = "be3563ae3f795b2b4353bcce3a527ad0a4f7f644";
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Branch newBranch = repo.CreateBranch(name, committish);
Assert.NotNull(newBranch);
Assert.Equal(name, newBranch.FriendlyName);
@@ -42,13 +44,26 @@ public void CanCreateBranch(string name)
"branch: Created from " + committish,
null,
newBranch.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
repo.Branches.Remove(newBranch.FriendlyName);
Assert.Null(repo.Branches[name]);
}
}
+ [Theory]
+ [InlineData("32eab9cb1f450b5fe7ab663462b77d7f4b703344")]
+ public void CanHeadBeDetached(string commit)
+ {
+ string path = SandboxStandardTestRepo();
+ using (var repo = new Repository(path))
+ {
+ Assert.False(repo.Info.IsHeadDetached);
+ Commands.Checkout(repo, commit);
+ Assert.True(repo.Info.IsHeadDetached);
+ }
+ }
+
[Fact]
public void CanCreateAnUnbornBranch()
{
@@ -72,7 +87,7 @@ public void CanCreateAnUnbornBranch()
Commit c = repo.Commit("New initial root commit", Constants.Signature, Constants.Signature);
// Ensure this commit has no parent
- Assert.Equal(0, c.Parents.Count());
+ Assert.Empty(c.Parents);
// The branch now exists...
Branch orphan = repo.Branches["orphan"];
@@ -95,6 +110,8 @@ public void CanCreateBranchUsingAbbreviatedSha()
const string name = "unit_test";
const string committish = "be3563a";
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Branch newBranch = repo.CreateBranch(name, committish);
Assert.Equal("refs/heads/" + name, newBranch.CanonicalName);
Assert.Equal("be3563ae3f795b2b4353bcce3a527ad0a4f7f644", newBranch.Tip.Sha);
@@ -103,7 +120,7 @@ public void CanCreateBranchUsingAbbreviatedSha()
"branch: Created from " + committish,
null,
newBranch.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -117,9 +134,12 @@ public void CanCreateBranchFromImplicitHead(string headCommitOrBranchSpec)
{
EnableRefLog(repo);
- repo.Checkout(headCommitOrBranchSpec);
+ Commands.Checkout(repo, headCommitOrBranchSpec);
const string name = "unit_test";
+
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Branch newBranch = repo.CreateBranch(name);
Assert.NotNull(newBranch);
Assert.Equal(name, newBranch.FriendlyName);
@@ -133,7 +153,7 @@ public void CanCreateBranchFromImplicitHead(string headCommitOrBranchSpec)
"branch: Created from " + headCommitOrBranchSpec,
null,
newBranch.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -147,9 +167,12 @@ public void CanCreateBranchFromExplicitHead(string headCommitOrBranchSpec)
{
EnableRefLog(repo);
- repo.Checkout(headCommitOrBranchSpec);
+ Commands.Checkout(repo, headCommitOrBranchSpec);
const string name = "unit_test";
+
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Branch newBranch = repo.CreateBranch(name, "HEAD");
Assert.NotNull(newBranch);
Assert.Equal("32eab9cb1f450b5fe7ab663462b77d7f4b703344", newBranch.Tip.Sha);
@@ -158,7 +181,7 @@ public void CanCreateBranchFromExplicitHead(string headCommitOrBranchSpec)
"branch: Created from HEAD",
null,
newBranch.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -172,6 +195,9 @@ public void CanCreateBranchFromCommit()
const string name = "unit_test";
var commit = repo.Lookup("HEAD");
+
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Branch newBranch = repo.CreateBranch(name, commit);
Assert.NotNull(newBranch);
Assert.Equal("4c062a6361ae6959e06292c1fa5e2822d9c96345", newBranch.Tip.Sha);
@@ -180,7 +206,7 @@ public void CanCreateBranchFromCommit()
"branch: Created from " + newBranch.Tip.Sha,
null,
newBranch.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -195,6 +221,8 @@ public void CanCreateBranchFromRevparseSpec()
const string name = "revparse_branch";
const string committish = "master~2";
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Branch newBranch = repo.CreateBranch(name, committish);
Assert.NotNull(newBranch);
Assert.Equal("9fd738e8f7967c078dceed8190330fc8648ee56a", newBranch.Tip.Sha);
@@ -203,7 +231,7 @@ public void CanCreateBranchFromRevparseSpec()
"branch: Created from " + committish,
null,
newBranch.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -219,6 +247,8 @@ public void CreatingABranchFromATagPeelsToTheCommit(string committish)
const string name = "i-peel-tag";
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Branch newBranch = repo.CreateBranch(name, committish);
Assert.NotNull(newBranch);
Assert.Equal("e90810b8df3e80c413d903f631643c716887138d", newBranch.Tip.Sha);
@@ -227,7 +257,7 @@ public void CreatingABranchFromATagPeelsToTheCommit(string committish)
"branch: Created from " + committish,
null,
newBranch.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -245,7 +275,7 @@ public void CreatingABranchTriggersTheCreationOfADirectReference()
Reference reference = repo.Refs[newBranch.CanonicalName];
Assert.NotNull(reference);
- Assert.IsType(typeof(DirectReference), reference);
+ Assert.IsType(reference);
}
}
@@ -377,7 +407,7 @@ public void CanResolveRemote()
using (var repo = new Repository(path))
{
Branch master = repo.Branches["master"];
- Assert.Equal(repo.Network.Remotes["origin"], master.Remote);
+ Assert.Equal("origin", master.RemoteName);
}
}
@@ -388,7 +418,7 @@ public void RemoteAndUpstreamBranchCanonicalNameForNonTrackingBranchIsNull()
using (var repo = new Repository(path))
{
Branch test = repo.Branches["i-do-numbers"];
- Assert.Null(test.Remote);
+ Assert.Null(test.RemoteName);
Assert.Null(test.UpstreamBranchCanonicalName);
}
}
@@ -401,7 +431,7 @@ public void QueryRemoteForLocalTrackingBranch()
using (var repo = new Repository(path))
{
Branch trackLocal = repo.Branches["track-local"];
- Assert.Null(trackLocal.Remote);
+ Assert.Null(trackLocal.RemoteName);
}
}
@@ -423,44 +453,42 @@ public void QueryRemoteForRemoteBranch()
using (var repo = new Repository(path))
{
var master = repo.Branches["origin/master"];
- Assert.Equal(repo.Network.Remotes["origin"], master.Remote);
+ Assert.Equal("origin", master.RemoteName);
}
}
[Fact]
public void QueryUnresolvableRemoteForRemoteBranch()
{
- var path = SandboxStandardTestRepo();
-
var fetchRefSpecs = new string[] { "+refs/heads/notfound/*:refs/remotes/origin/notfound/*" };
- using (var repo = InitIsolatedRepository(path))
+ var path = SandboxStandardTestRepo();
+ using (var repo = new Repository(path))
{
// Update the remote config such that the remote for a
// remote branch cannot be resolved
Remote remote = repo.Network.Remotes["origin"];
Assert.NotNull(remote);
- repo.Network.Remotes.Update(remote, r => r.FetchRefSpecs = fetchRefSpecs);
+ repo.Network.Remotes.Update("origin", r => r.FetchRefSpecs = fetchRefSpecs);
Branch branch = repo.Branches["refs/remotes/origin/master"];
Assert.NotNull(branch);
Assert.True(branch.IsRemote);
- Assert.Null(branch.Remote);
+ Assert.Null(branch.RemoteName);
}
}
[Fact]
public void QueryAmbigousRemoteForRemoteBranch()
{
- var path = SandboxStandardTestRepo();
-
const string fetchRefSpec = "+refs/heads/*:refs/remotes/origin/*";
const string url = "http://github.com/libgit2/TestGitRepository";
- using (var repo = InitIsolatedRepository(path))
+ var path = SandboxStandardTestRepo();
+ using (var repo = new Repository(path))
{
// Add a second remote so that it is ambiguous which remote
// the remote-tracking branch tracks.
@@ -471,7 +499,7 @@ public void QueryAmbigousRemoteForRemoteBranch()
Assert.NotNull(branch);
Assert.True(branch.IsRemote);
- Assert.Null(branch.Remote);
+ Assert.Null(branch.RemoteName);
}
}
@@ -548,7 +576,7 @@ public void CanGetInformationFromUnbornBranch()
var head = repo.Head;
Assert.Equal("refs/heads/master", head.CanonicalName);
- Assert.Equal(0, head.Commits.Count());
+ Assert.Empty(head.Commits);
Assert.True(head.IsCurrentRepositoryHead);
Assert.False(head.IsRemote);
Assert.Equal("master", head.FriendlyName);
@@ -717,7 +745,7 @@ public void CanSetTrackedBranch()
Assert.True(branch.IsTracking);
Assert.Equal(trackedBranch, branch.TrackedBranch);
- Assert.Equal(upstreamRemote, branch.Remote);
+ Assert.Equal("origin", branch.RemoteName);
}
}
@@ -735,7 +763,7 @@ public void SetTrackedBranchForUnreasolvableRemoteThrows()
// cannot be resolved.
Remote remote = repo.Network.Remotes["origin"];
Assert.NotNull(remote);
- repo.Network.Remotes.Update(remote, r => r.FetchRefSpecs = fetchRefSpecs);
+ repo.Network.Remotes.Update("origin", r => r.FetchRefSpecs = fetchRefSpecs);
// Now attempt to update the tracked branch
Branch branch = repo.CreateBranch(testBranchName);
@@ -778,7 +806,7 @@ public void CanSetUpstreamBranch()
Assert.True(updatedBranch.IsTracking);
Assert.Equal(trackedBranch, updatedBranch.TrackedBranch);
Assert.Equal(upstreamBranchName, updatedBranch.UpstreamBranchCanonicalName);
- Assert.Equal(upstreamRemote, updatedBranch.Remote);
+ Assert.Equal(remoteName, updatedBranch.RemoteName);
}
}
@@ -805,7 +833,7 @@ public void CanSetLocalTrackedBranch()
// Branches that track the local remote do not have the "Remote" property set.
// Verify (through the configuration entry) that the local remote is set as expected.
- Assert.Null(branch.Remote);
+ Assert.Null(branch.RemoteName);
ConfigurationEntry remoteConfigEntry = repo.Config.Get("branch", testBranchName, "remote");
Assert.NotNull(remoteConfigEntry);
Assert.Equal(".", remoteConfigEntry.Value);
@@ -846,7 +874,7 @@ public void CanUnsetTrackedBranch()
// Verify this is no longer a tracking branch
Assert.False(branch.IsTracking);
- Assert.Null(branch.Remote);
+ Assert.Null(branch.RemoteName);
Assert.Null(branch.UpstreamBranchCanonicalName);
}
}
@@ -902,6 +930,24 @@ public void CanRemoveAnExistingBranch(string branchName)
}
}
+ [Fact]
+ public void CanCreateBranchInDeletedNestedBranchNamespace()
+ {
+ const string namespaceName = "level_one";
+ string branchWithNamespaceName = string.Join("/", namespaceName, "level_two");
+
+ string path = SandboxStandardTestRepo();
+ using (var repo = new Repository(path))
+ {
+ Commit commit = repo.Head.Tip;
+
+ Branch branchWithNamespace = repo.Branches.Add(branchWithNamespaceName, commit);
+ repo.Branches.Remove(branchWithNamespace);
+
+ repo.Branches.Add(namespaceName, commit);
+ }
+ }
+
[Theory]
[InlineData("I-donot-exist", false)]
[InlineData("me/neither", true)]
@@ -927,7 +973,8 @@ public void RemovingABranchWithBadParamsThrows()
using (var repo = new Repository(path))
{
Assert.Throws(() => repo.Branches.Remove(string.Empty));
- Assert.Throws(() => repo.Branches.Remove(null));
+ Assert.Throws(() => repo.Branches.Remove(default(string)));
+ Assert.Throws(() => repo.Branches.Remove(default(Branch)));
}
}
@@ -986,6 +1033,8 @@ public void CanRenameABranch()
var br2 = repo.Branches["br2"];
Assert.NotNull(br2);
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Branch newBranch = repo.Branches.Rename("br2", "br3");
Assert.Equal("br3", newBranch.FriendlyName);
@@ -997,7 +1046,7 @@ public void CanRenameABranch()
string.Format("branch: renamed {0} to {1}", br2.CanonicalName, newBranch.CanonicalName),
br2.Tip.Id,
newBranch.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -1025,6 +1074,8 @@ public void CanRenameABranchWhileOverwritingAnExistingOne()
Branch br2 = repo.Branches["br2"];
Assert.NotNull(br2);
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Branch newBranch = repo.Branches.Rename("br2", "test", true);
Assert.Equal("test", newBranch.FriendlyName);
@@ -1040,7 +1091,7 @@ public void CanRenameABranchWhileOverwritingAnExistingOne()
string.Format("branch: renamed {0} to {1}", br2.CanonicalName, newBranch.CanonicalName),
br2.Tip.Id,
newTest.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -1054,7 +1105,7 @@ public void DetachedHeadIsNotATrackingBranch()
repo.RemoveUntrackedFiles();
string headSha = repo.Head.Tip.Sha;
- repo.Checkout(headSha);
+ Commands.Checkout(repo, headSha);
Assert.False(repo.Head.IsTracking);
Assert.Null(repo.Head.TrackedBranch);
@@ -1075,7 +1126,7 @@ public void TrackedBranchExistsFromDefaultConfigInEmptyClone()
using (var emptyRepo = new Repository(repoPath))
{
- uri = new Uri(emptyRepo.Info.Path);
+ uri = new Uri($"file://{emptyRepo.Info.Path}");
}
SelfCleaningDirectory scd2 = BuildSelfCleaningDirectory();
@@ -1085,7 +1136,7 @@ public void TrackedBranchExistsFromDefaultConfigInEmptyClone()
using (var repo = new Repository(clonedRepoPath))
{
Assert.Empty(Directory.GetFiles(scd2.RootedDirectoryPath));
- Assert.Equal(repo.Head.FriendlyName, "master");
+ Assert.Equal("master", repo.Head.FriendlyName);
Assert.Null(repo.Head.Tip);
Assert.NotNull(repo.Head.TrackedBranch);
@@ -1096,11 +1147,10 @@ public void TrackedBranchExistsFromDefaultConfigInEmptyClone()
Assert.Null(repo.Head.TrackingDetails.BehindBy);
Assert.Null(repo.Head.TrackingDetails.CommonAncestor);
- Assert.NotNull(repo.Head.Remote);
- Assert.Equal("origin", repo.Head.Remote.Name);
+ Assert.Equal("origin", repo.Head.RemoteName);
Touch(repo.Info.WorkingDirectory, "a.txt", "a");
- repo.Stage("a.txt");
+ Commands.Stage(repo, "a.txt");
repo.Commit("A file", Constants.Signature, Constants.Signature);
Assert.NotNull(repo.Head.Tip);
@@ -1125,7 +1175,7 @@ public void RemoteBranchesDoNotTrackAnything()
foreach (var branch in branches)
{
Assert.True(branch.IsRemote);
- Assert.NotNull(branch.Remote);
+ Assert.NotNull(branch.RemoteName);
Assert.False(branch.IsTracking);
Assert.Null(branch.TrackedBranch);
@@ -1149,19 +1199,24 @@ public void CreatingABranchIncludesTheCorrectReflogEntries()
using (var repo = new Repository(path, new RepositoryOptions { Identity = Constants.Identity }))
{
EnableRefLog(repo);
+
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
var branch = repo.Branches.Add("foo", repo.Head.Tip);
AssertRefLogEntry(repo, branch.CanonicalName,
string.Format("branch: Created from {0}", repo.Head.Tip.Sha),
null, branch.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
+
+ before = DateTimeOffset.Now.TruncateMilliseconds();
branch = repo.Branches.Add("bar", repo.Head.Tip);
AssertRefLogEntry(repo, branch.CanonicalName,
"branch: Created from " + repo.Head.Tip.Sha,
null, repo.Head.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -1173,15 +1228,20 @@ public void RenamingABranchIncludesTheCorrectReflogEntries()
{
EnableRefLog(repo);
var master = repo.Branches["master"];
+
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
var newMaster = repo.Branches.Rename(master, "new-master");
AssertRefLogEntry(repo, newMaster.CanonicalName, "branch: renamed refs/heads/master to refs/heads/new-master",
newMaster.Tip.Id, newMaster.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
+
+ before = DateTimeOffset.Now.TruncateMilliseconds();
var newMaster2 = repo.Branches.Rename(newMaster, "new-master2");
AssertRefLogEntry(repo, newMaster2.CanonicalName, "branch: renamed refs/heads/new-master to refs/heads/new-master2",
newMaster.Tip.Id, newMaster2.Tip.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
}
diff --git a/LibGit2Sharp.Tests/CheckoutFixture.cs b/LibGit2Sharp.Tests/CheckoutFixture.cs
index c91f1d691..f0c2c36ed 100644
--- a/LibGit2Sharp.Tests/CheckoutFixture.cs
+++ b/LibGit2Sharp.Tests/CheckoutFixture.cs
@@ -34,7 +34,7 @@ public void CanCheckoutAnExistingBranch(string branchName)
Assert.NotNull(branch);
AssertBelongsToARepository(repo, branch);
- Branch test = repo.Checkout(branch);
+ Branch test = Commands.Checkout(repo, branch);
Assert.False(repo.Info.IsHeadDetached);
AssertBelongsToARepository(repo, test);
@@ -73,7 +73,7 @@ public void CanCheckoutAnExistingBranchByName(string branchName)
Assert.False(repo.RetrieveStatus().IsDirty);
- Branch test = repo.Checkout(branchName);
+ Branch test = Commands.Checkout(repo, branchName);
Assert.False(repo.Info.IsHeadDetached);
Assert.False(test.IsRemote);
@@ -97,7 +97,7 @@ public void CanCheckoutAnExistingBranchByName(string branchName)
[Theory]
[InlineData("6dcf9bf", true, "6dcf9bf")]
- [InlineData("refs/tags/lw", true, "refs/tags/lw")]
+ [InlineData("refs/tags/lw", true, "lw")]
[InlineData("HEAD~2", true, "HEAD~2")]
[InlineData("6dcf9bf", false, "6dcf9bf7541ee10456529833502442f385010c3d")]
[InlineData("refs/tags/lw", false, "e90810b8df3e80c413d903f631643c716887138d")]
@@ -118,7 +118,7 @@ public void CanCheckoutAnArbitraryCommit(string commitPointer, bool checkoutByCo
var commit = repo.Lookup(commitPointer);
AssertBelongsToARepository(repo, commit);
- Branch detachedHead = checkoutByCommitOrBranchSpec ? repo.Checkout(commitPointer) : repo.Checkout(commit);
+ Branch detachedHead = checkoutByCommitOrBranchSpec ? Commands.Checkout(repo, commitPointer) : Commands.Checkout(repo, commit);
Assert.Equal(repo.Head, detachedHead);
Assert.Equal(commit.Sha, detachedHead.Tip.Sha);
@@ -156,13 +156,13 @@ public void CheckoutAddsMissingFilesInWorkingDirectory()
// Remove the file in master branch
// Verify it exists after checking out otherBranch.
string fileFullPath = Path.Combine(repo.Info.WorkingDirectory, originalFilePath);
- repo.Remove(fileFullPath);
+ Commands.Remove(repo, fileFullPath);
repo.Commit("2nd commit", Constants.Signature, Constants.Signature);
// Checkout other_branch
Branch otherBranch = repo.Branches[otherBranchName];
Assert.NotNull(otherBranch);
- repo.Checkout(otherBranch);
+ Commands.Checkout(repo, otherBranch);
// Verify working directory is updated
Assert.False(repo.RetrieveStatus().IsDirty);
@@ -184,13 +184,13 @@ public void CheckoutRemovesExtraFilesInWorkingDirectory()
string newFileFullPath = Touch(
repo.Info.WorkingDirectory, "b.txt", "hello from master branch!\n");
- repo.Stage(newFileFullPath);
+ Commands.Stage(repo, newFileFullPath);
repo.Commit("2nd commit", Constants.Signature, Constants.Signature);
// Checkout other_branch
Branch otherBranch = repo.Branches[otherBranchName];
Assert.NotNull(otherBranch);
- repo.Checkout(otherBranch);
+ Commands.Checkout(repo, otherBranch);
// Verify working directory is updated
Assert.False(repo.RetrieveStatus().IsDirty);
@@ -212,13 +212,13 @@ public void CheckoutUpdatesModifiedFilesInWorkingDirectory()
string fullPath = Touch(
repo.Info.WorkingDirectory, originalFilePath, "Update : hello from master branch!\n");
- repo.Stage(fullPath);
+ Commands.Stage(repo, fullPath);
repo.Commit("2nd commit", Constants.Signature, Constants.Signature);
// Checkout other_branch
Branch otherBranch = repo.Branches[otherBranchName];
Assert.NotNull(otherBranch);
- repo.Checkout(otherBranch);
+ Commands.Checkout(repo, otherBranch);
// Verify working directory is updated
Assert.False(repo.RetrieveStatus().IsDirty);
@@ -254,22 +254,22 @@ public void CanForcefullyCheckoutWithConflictingStagedChanges()
// Add change to master.
Touch(repo.Info.WorkingDirectory, originalFilePath, originalFileContent);
- repo.Stage(originalFilePath);
+ Commands.Stage(repo, originalFilePath);
repo.Commit("change in master", Constants.Signature, Constants.Signature);
// Checkout otherBranch.
- repo.Checkout(otherBranchName);
+ Commands.Checkout(repo, otherBranchName);
// Add change to otherBranch.
Touch(repo.Info.WorkingDirectory, originalFilePath, alternateFileContent);
- repo.Stage(originalFilePath);
+ Commands.Stage(repo, originalFilePath);
// Assert that normal checkout throws exception
// for the conflict.
- Assert.Throws(() => repo.Checkout(master.CanonicalName));
+ Assert.Throws(() => Commands.Checkout(repo, master.CanonicalName));
// Checkout with force option should succeed.
- repo.Checkout(master.CanonicalName, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force});
+ Commands.Checkout(repo, master.CanonicalName, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force});
// Assert that master branch is checked out.
Assert.True(repo.Branches["master"].IsCurrentRepositoryHead);
@@ -287,7 +287,7 @@ public void CheckingOutWithMergeConflictsThrows()
using (var repo = new Repository(repoPath))
{
Touch(repo.Info.WorkingDirectory, originalFilePath, "Hello\n");
- repo.Stage(originalFilePath);
+ Commands.Stage(repo, originalFilePath);
repo.Commit("Initial commit", Constants.Signature, Constants.Signature);
// Create 2nd branch
@@ -295,20 +295,20 @@ public void CheckingOutWithMergeConflictsThrows()
// Update file in main
Touch(repo.Info.WorkingDirectory, originalFilePath, "Hello from master!\n");
- repo.Stage(originalFilePath);
+ Commands.Stage(repo, originalFilePath);
repo.Commit("2nd commit", Constants.Signature, Constants.Signature);
// Checkout branch2
- repo.Checkout("branch2");
+ Commands.Checkout(repo, "branch2");
Touch(repo.Info.WorkingDirectory, originalFilePath, "Hello From branch2!\n");
// Assert that checking out master throws
// when there are unstaged commits
- Assert.Throws(() => repo.Checkout("master"));
+ Assert.Throws(() => Commands.Checkout(repo, "master"));
// And when there are staged commits
- repo.Stage(originalFilePath);
- Assert.Throws(() => repo.Checkout("master"));
+ Commands.Stage(repo, originalFilePath);
+ Assert.Throws(() => Commands.Checkout(repo, "master"));
}
}
@@ -322,7 +322,7 @@ public void CanCancelCheckoutThroughNotifyCallback()
const string relativePath = "a.txt";
Touch(repo.Info.WorkingDirectory, relativePath, "Hello\n");
- repo.Stage(relativePath);
+ Commands.Stage(repo, relativePath);
repo.Commit("Initial commit", Constants.Signature, Constants.Signature);
// Create 2nd branch
@@ -330,11 +330,11 @@ public void CanCancelCheckoutThroughNotifyCallback()
// Update file in main
Touch(repo.Info.WorkingDirectory, relativePath, "Hello from master!\n");
- repo.Stage(relativePath);
+ Commands.Stage(repo, relativePath);
repo.Commit("2nd commit", Constants.Signature, Constants.Signature);
// Checkout branch2
- repo.Checkout("branch2");
+ Commands.Checkout(repo, "branch2");
// Update the context of a.txt - a.txt will then conflict between branch2 and master.
Touch(repo.Info.WorkingDirectory, relativePath, "Hello From branch2!\n");
@@ -348,7 +348,7 @@ public void CanCancelCheckoutThroughNotifyCallback()
CheckoutNotifyFlags = CheckoutNotifyFlags.Conflict,
};
- Assert.Throws(() => repo.Checkout("master", options));
+ Assert.Throws(() => Commands.Checkout(repo, "master", options));
Assert.Equal(relativePath, conflictPath);
}
}
@@ -359,8 +359,8 @@ public void CheckingOutInABareRepoThrows()
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
- Assert.Throws(() => repo.Checkout(repo.Branches["refs/heads/test"]));
- Assert.Throws(() => repo.Checkout("refs/heads/test"));
+ Assert.Throws(() => Commands.Checkout(repo, repo.Branches["refs/heads/test"]));
+ Assert.Throws(() => Commands.Checkout(repo, "refs/heads/test"));
}
}
@@ -373,7 +373,7 @@ public void CheckingOutAgainstAnUnbornBranchThrows()
{
Assert.True(repo.Info.IsHeadUnborn);
- Assert.Throws(() => repo.Checkout(repo.Head));
+ Assert.Throws(() => Commands.Checkout(repo, repo.Head));
}
}
@@ -383,7 +383,7 @@ public void CheckingOutANonExistingBranchThrows()
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
- Assert.Throws(() => repo.Checkout("i-do-not-exist"));
+ Assert.Throws(() => Commands.Checkout(repo, "i-do-not-exist"));
}
}
@@ -393,9 +393,9 @@ public void CheckingOutABranchWithBadParamsThrows()
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
- Assert.Throws(() => repo.Checkout(string.Empty));
- Assert.Throws(() => repo.Checkout(default(Branch)));
- Assert.Throws(() => repo.Checkout(default(string)));
+ Assert.Throws(() => Commands.Checkout(repo, string.Empty));
+ Assert.Throws(() => Commands.Checkout(repo, default(Branch)));
+ Assert.Throws(() => Commands.Checkout(repo, default(string)));
}
}
@@ -410,7 +410,7 @@ public void CheckingOutThroughBranchCallsCheckoutProgress()
bool wasCalled = false;
Branch branch = repo.Branches[otherBranchName];
- repo.Checkout(branch,
+ Commands.Checkout(repo, branch,
new CheckoutOptions { OnCheckoutProgress = (path, completed, total) => wasCalled = true});
Assert.True(wasCalled);
@@ -427,7 +427,7 @@ public void CheckingOutThroughRepositoryCallsCheckoutProgress()
PopulateBasicRepository(repo);
bool wasCalled = false;
- repo.Checkout(otherBranchName, new CheckoutOptions() { OnCheckoutProgress = (path, completed, total) => wasCalled = true});
+ Commands.Checkout(repo, otherBranchName, new CheckoutOptions() { OnCheckoutProgress = (path, completed, total) => wasCalled = true});
Assert.True(wasCalled);
}
@@ -453,13 +453,13 @@ public void CheckingOutCallsCheckoutNotify(CheckoutNotifyFlags notifyFlags, stri
const string relativePathUpdated = "updated.txt";
Touch(repo.Info.WorkingDirectory, relativePathUpdated, "updated file text A");
- repo.Stage(relativePathUpdated);
+ Commands.Stage(repo, relativePathUpdated);
repo.Commit("Commit initial update file", Constants.Signature, Constants.Signature);
// Create conflicting change
const string relativePathConflict = "conflict.txt";
Touch(repo.Info.WorkingDirectory, relativePathConflict, "conflict file text A");
- repo.Stage(relativePathConflict);
+ Commands.Stage(repo, relativePathConflict);
repo.Commit("Initial commit of conflict.txt and update.txt", Constants.Signature, Constants.Signature);
// Create another branch
@@ -467,25 +467,25 @@ public void CheckingOutCallsCheckoutNotify(CheckoutNotifyFlags notifyFlags, stri
// Make an edit to conflict.txt and update.txt
Touch(repo.Info.WorkingDirectory, relativePathUpdated, "updated file text BB");
- repo.Stage(relativePathUpdated);
+ Commands.Stage(repo, relativePathUpdated);
Touch(repo.Info.WorkingDirectory, relativePathConflict, "conflict file text BB");
- repo.Stage(relativePathConflict);
+ Commands.Stage(repo, relativePathConflict);
repo.Commit("2nd commit of conflict.txt and update.txt on master branch", Constants.Signature, Constants.Signature);
// Checkout other branch
- repo.Checkout("newbranch");
+ Commands.Checkout(repo, "newbranch");
// Make alternate edits to conflict.txt and update.txt
Touch(repo.Info.WorkingDirectory, relativePathUpdated, "updated file text CCC");
- repo.Stage(relativePathUpdated);
+ Commands.Stage(repo, relativePathUpdated);
Touch(repo.Info.WorkingDirectory, relativePathConflict, "conflict file text CCC");
- repo.Stage(relativePathConflict);
+ Commands.Stage(repo, relativePathConflict);
repo.Commit("2nd commit of conflict.txt and update.txt on newbranch", Constants.Signature, Constants.Signature);
// make conflicting change to conflict.txt
Touch(repo.Info.WorkingDirectory, relativePathConflict, "conflict file text DDDD");
- repo.Stage(relativePathConflict);
+ Commands.Stage(repo, relativePathConflict);
// Create ignored change
string relativePathIgnore = Path.Combine("bin", "ignored.txt");
@@ -505,7 +505,7 @@ public void CheckingOutCallsCheckoutNotify(CheckoutNotifyFlags notifyFlags, stri
CheckoutNotifyFlags = notifyFlags,
};
- Assert.Throws(() => repo.Checkout("master", options));
+ Assert.Throws(() => Commands.Checkout(repo, "master", options));
Assert.True(wasCalled);
Assert.Equal(expectedNotificationPath, actualNotificationPath);
@@ -526,13 +526,13 @@ public void CheckoutRetainsUntrackedChanges()
string fullPathFileB = Touch(repo.Info.WorkingDirectory, "b.txt", alternateFileContent);
// Verify that there is an untracked entry.
- Assert.Equal(1, repo.RetrieveStatus().Untracked.Count());
+ Assert.Single(repo.RetrieveStatus().Untracked);
Assert.Equal(FileStatus.NewInWorkdir, repo.RetrieveStatus(fullPathFileB));
- repo.Checkout(otherBranchName);
+ Commands.Checkout(repo, otherBranchName);
// Verify untracked entry still exists.
- Assert.Equal(1, repo.RetrieveStatus().Untracked.Count());
+ Assert.Single(repo.RetrieveStatus().Untracked);
Assert.Equal(FileStatus.NewInWorkdir, repo.RetrieveStatus(fullPathFileB));
}
}
@@ -550,13 +550,13 @@ public void ForceCheckoutRetainsUntrackedChanges()
string fullPathFileB = Touch(repo.Info.WorkingDirectory, "b.txt", alternateFileContent);
// Verify that there is an untracked entry.
- Assert.Equal(1, repo.RetrieveStatus().Untracked.Count());
+ Assert.Single(repo.RetrieveStatus().Untracked);
Assert.Equal(FileStatus.NewInWorkdir, repo.RetrieveStatus(fullPathFileB));
- repo.Checkout(otherBranchName, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });
+ Commands.Checkout(repo, otherBranchName, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });
// Verify untracked entry still exists.
- Assert.Equal(1, repo.RetrieveStatus().Untracked.Count());
+ Assert.Single(repo.RetrieveStatus().Untracked);
Assert.Equal(FileStatus.NewInWorkdir, repo.RetrieveStatus(fullPathFileB));
}
}
@@ -574,13 +574,13 @@ public void CheckoutRetainsUnstagedChanges()
string fullPathFileA = Touch(repo.Info.WorkingDirectory, originalFilePath, alternateFileContent);
// Verify that there is a modified entry.
- Assert.Equal(1, repo.RetrieveStatus().Modified.Count());
+ Assert.Single(repo.RetrieveStatus().Modified);
Assert.Equal(FileStatus.ModifiedInWorkdir, repo.RetrieveStatus(fullPathFileA));
- repo.Checkout(otherBranchName);
+ Commands.Checkout(repo, otherBranchName);
// Verify modified entry still exists.
- Assert.Equal(1, repo.RetrieveStatus().Modified.Count());
+ Assert.Single(repo.RetrieveStatus().Modified);
Assert.Equal(FileStatus.ModifiedInWorkdir, repo.RetrieveStatus(fullPathFileA));
}
}
@@ -596,16 +596,16 @@ public void CheckoutRetainsStagedChanges()
// Generate a staged change.
string fullPathFileA = Touch(repo.Info.WorkingDirectory, originalFilePath, alternateFileContent);
- repo.Stage(fullPathFileA);
+ Commands.Stage(repo, fullPathFileA);
// Verify that there is a staged entry.
- Assert.Equal(1, repo.RetrieveStatus().Staged.Count());
+ Assert.Single(repo.RetrieveStatus().Staged);
Assert.Equal(FileStatus.ModifiedInIndex, repo.RetrieveStatus(fullPathFileA));
- repo.Checkout(otherBranchName);
+ Commands.Checkout(repo, otherBranchName);
// Verify staged entry still exists.
- Assert.Equal(1, repo.RetrieveStatus().Staged.Count());
+ Assert.Single(repo.RetrieveStatus().Staged);
Assert.Equal(FileStatus.ModifiedInIndex, repo.RetrieveStatus(fullPathFileA));
}
}
@@ -625,11 +625,11 @@ public void CheckoutRetainsIgnoredChanges()
"bin/some_ignored_file.txt",
"hello from this ignored file.");
- Assert.Equal(1, repo.RetrieveStatus().Ignored.Count());
+ Assert.Single(repo.RetrieveStatus(new StatusOptions { IncludeIgnored = true }).Ignored);
Assert.Equal(FileStatus.Ignored, repo.RetrieveStatus(ignoredFilePath));
- repo.Checkout(otherBranchName);
+ Commands.Checkout(repo, otherBranchName);
// Verify that the ignored file still exists.
Assert.Equal(FileStatus.Ignored, repo.RetrieveStatus(ignoredFilePath));
@@ -652,11 +652,11 @@ public void ForceCheckoutRetainsIgnoredChanges()
"bin/some_ignored_file.txt",
"hello from this ignored file.");
- Assert.Equal(1, repo.RetrieveStatus().Ignored.Count());
+ Assert.Single(repo.RetrieveStatus(new StatusOptions { IncludeIgnored = true }).Ignored);
Assert.Equal(FileStatus.Ignored, repo.RetrieveStatus(ignoredFilePath));
- repo.Checkout(otherBranchName, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });
+ Commands.Checkout(repo, otherBranchName, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });
// Verify that the ignored file still exists.
Assert.Equal(FileStatus.Ignored, repo.RetrieveStatus(ignoredFilePath));
@@ -680,12 +680,12 @@ public void CheckoutBranchSnapshot()
// Add commit to master
string fullPath = Touch(repo.Info.WorkingDirectory, originalFilePath, "Update : hello from master branch!\n");
- repo.Stage(fullPath);
+ Commands.Stage(repo, fullPath);
repo.Commit("2nd commit", Constants.Signature, Constants.Signature);
Assert.False(repo.Info.IsHeadDetached);
- repo.Checkout(initial);
+ Commands.Checkout(repo, initial);
// Head should point at initial commit.
Assert.Equal(repo.Head.Tip, initialCommit);
@@ -712,7 +712,7 @@ public void CheckingOutRemoteBranchResultsInDetachedHead(string remoteBranchSpec
// Set the working directory to the current head
ResetAndCleanWorkingDirectory(repo);
- repo.Checkout(remoteBranchSpec);
+ Commands.Checkout(repo, remoteBranchSpec);
// Verify that HEAD is detached.
Assert.Equal(repo.Refs["HEAD"].TargetIdentifier, repo.Branches["origin/master"].Tip.Sha);
@@ -733,7 +733,7 @@ public void CheckingOutABranchDoesNotAlterBinaryFiles()
// The blob actually exists in the object database with the correct Sha
Assert.Equal(expectedSha, repo.Lookup(expectedSha).Sha);
- repo.Checkout("refs/heads/logo", new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });
+ Commands.Checkout(repo, "refs/heads/logo", new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });
// The Index has been updated as well with the blob
Assert.Equal(expectedSha, repo.Index["square-logo.png"].Id.Sha);
@@ -748,7 +748,7 @@ public void CheckingOutABranchDoesNotAlterBinaryFiles()
[Theory]
[InlineData("a447ba2ca8")]
- [InlineData("refs/tags/lw")]
+ [InlineData("lw")]
[InlineData("e90810^{}")]
public void CheckoutFromDetachedHead(string commitPointer)
{
@@ -761,9 +761,9 @@ public void CheckoutFromDetachedHead(string commitPointer)
var commitSha = repo.Lookup(commitPointer).Sha;
- Branch initialHead = repo.Checkout("6dcf9bf");
+ Branch initialHead = Commands.Checkout(repo, "6dcf9bf");
- repo.Checkout(commitPointer);
+ Commands.Checkout(repo, commitPointer);
// Assert reflog entry is created
var reflogEntry = repo.Refs.Log(repo.Refs.Head).First();
@@ -785,16 +785,18 @@ public void CheckoutBranchFromDetachedHead()
ResetAndCleanWorkingDirectory(repo);
Assert.False(repo.RetrieveStatus().IsDirty);
- Branch initialHead = repo.Checkout("6dcf9bf");
+ Branch initialHead = Commands.Checkout(repo, "6dcf9bf");
Assert.True(repo.Info.IsHeadDetached);
- Branch newHead = repo.Checkout(repo.Branches["master"]);
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
+ Branch newHead = Commands.Checkout(repo, repo.Branches["master"]);
// Assert reflog entry is created
AssertRefLogEntry(repo, "HEAD",
string.Format("checkout: moving from {0} to {1}", initialHead.Tip.Sha, newHead.FriendlyName),
- initialHead.Tip.Id, newHead.Tip.Id, Constants.Identity, DateTimeOffset.Now);
+ initialHead.Tip.Id, newHead.Tip.Id, Constants.Identity, before);
}
}
@@ -810,10 +812,10 @@ public void CheckoutBranchByShortNameAttachesTheHead(string shortBranchName, str
ResetAndCleanWorkingDirectory(repo);
Assert.False(repo.RetrieveStatus().IsDirty);
- repo.Checkout("6dcf9bf");
+ Commands.Checkout(repo, "6dcf9bf");
Assert.True(repo.Info.IsHeadDetached);
- var branch = repo.Checkout(shortBranchName);
+ var branch = Commands.Checkout(repo, shortBranchName);
Assert.False(repo.Info.IsHeadDetached);
Assert.Equal(referenceName, repo.Head.CanonicalName);
@@ -831,11 +833,11 @@ public void CheckoutPreviousCheckedOutBranch()
ResetAndCleanWorkingDirectory(repo);
Assert.False(repo.RetrieveStatus().IsDirty);
- Branch previousHead = repo.Checkout("i-do-numbers");
- repo.Checkout("diff-test-cases");
+ Branch previousHead = Commands.Checkout(repo, "i-do-numbers");
+ Commands.Checkout(repo, "diff-test-cases");
//Go back to previous branch checked out
- var branch = repo.Checkout(@"@{-1}");
+ var branch = Commands.Checkout(repo, @"@{-1}");
Assert.False(repo.Info.IsHeadDetached);
Assert.Equal(previousHead.CanonicalName, repo.Head.CanonicalName);
@@ -858,33 +860,36 @@ public void CheckoutCurrentReference()
var reflogEntriesCount = repo.Refs.Log(repo.Refs.Head).Count();
// Checkout branch
- repo.Checkout(master);
+ Commands.Checkout(repo, master);
Assert.Equal(reflogEntriesCount, repo.Refs.Log(repo.Refs.Head).Count());
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
// Checkout in detached mode
- repo.Checkout(master.Tip.Sha);
+ Commands.Checkout(repo, master.Tip.Sha);
Assert.True(repo.Info.IsHeadDetached);
AssertRefLogEntry(repo, "HEAD",
- string.Format("checkout: moving from master to {0}", master.Tip.Sha), master.Tip.Id, master.Tip.Id, Constants.Identity, DateTimeOffset.Now);
+ string.Format("checkout: moving from master to {0}", master.Tip.Sha),
+ master.Tip.Id, master.Tip.Id, Constants.Identity, before);
// Checkout detached "HEAD" => nothing should happen
reflogEntriesCount = repo.Refs.Log(repo.Refs.Head).Count();
- repo.Checkout(repo.Head);
+ Commands.Checkout(repo, repo.Head);
Assert.Equal(reflogEntriesCount, repo.Refs.Log(repo.Refs.Head).Count());
// Checkout attached "HEAD" => nothing should happen
- repo.Checkout("master");
+ Commands.Checkout(repo, "master");
reflogEntriesCount = repo.Refs.Log(repo.Refs.Head).Count();
- repo.Checkout(repo.Head);
+ Commands.Checkout(repo, repo.Head);
Assert.Equal(reflogEntriesCount, repo.Refs.Log(repo.Refs.Head).Count());
- repo.Checkout("HEAD");
+ Commands.Checkout(repo, "HEAD");
Assert.Equal(reflogEntriesCount, repo.Refs.Log(repo.Refs.Head).Count());
}
@@ -896,7 +901,7 @@ public void CheckoutLowerCasedHeadThrows()
string path = SandboxStandardTestRepo();
using (var repo = new Repository(path))
{
- Assert.Throws(() => repo.Checkout("head"));
+ Assert.Throws(() => Commands.Checkout(repo, "head"));
}
}
@@ -908,10 +913,10 @@ public void CanCheckoutAttachedHead()
{
Assert.False(repo.Info.IsHeadDetached);
- repo.Checkout(repo.Head);
+ Commands.Checkout(repo, repo.Head);
Assert.False(repo.Info.IsHeadDetached);
- repo.Checkout("HEAD");
+ Commands.Checkout(repo, "HEAD");
Assert.False(repo.Info.IsHeadDetached);
}
}
@@ -922,14 +927,14 @@ public void CanCheckoutDetachedHead()
string path = SandboxStandardTestRepo();
using (var repo = new Repository(path))
{
- repo.Checkout(repo.Head.Tip.Sha);
+ Commands.Checkout(repo, repo.Head.Tip.Sha);
Assert.True(repo.Info.IsHeadDetached);
- repo.Checkout(repo.Head);
+ Commands.Checkout(repo, repo.Head);
Assert.True(repo.Info.IsHeadDetached);
- repo.Checkout("HEAD");
+ Commands.Checkout(repo, "HEAD");
Assert.True(repo.Info.IsHeadDetached);
}
}
@@ -947,13 +952,13 @@ public void CanCheckoutPath(string originalBranch, string checkoutFrom, string p
// Set the working directory to the current head
ResetAndCleanWorkingDirectory(repo);
- repo.Checkout(originalBranch);
+ Commands.Checkout(repo, originalBranch);
Assert.False(repo.RetrieveStatus().IsDirty);
repo.CheckoutPaths(checkoutFrom, new[] { path });
Assert.Equal(expectedStatus, repo.RetrieveStatus(path));
- Assert.Equal(1, repo.RetrieveStatus().Count());
+ Assert.Single(repo.RetrieveStatus());
}
}
@@ -990,8 +995,7 @@ public void CannotCheckoutPathsWithEmptyOrNullPathArgument()
Assert.False(repo.RetrieveStatus().IsDirty);
// Passing null 'paths' parameter should throw
- Assert.Throws(typeof(ArgumentNullException),
- () => repo.CheckoutPaths("i-do-numbers", null));
+ Assert.Throws(() => repo.CheckoutPaths("i-do-numbers", null));
// Passing empty list should do nothing
repo.CheckoutPaths("i-do-numbers", Enumerable.Empty());
@@ -1033,10 +1037,10 @@ private void PopulateBasicRepository(IRepository repo)
{
// Generate a .gitignore file.
string gitIgnoreFilePath = Touch(repo.Info.WorkingDirectory, ".gitignore", "bin");
- repo.Stage(gitIgnoreFilePath);
+ Commands.Stage(repo, gitIgnoreFilePath);
string fullPathFileA = Touch(repo.Info.WorkingDirectory, originalFilePath, originalFileContent);
- repo.Stage(fullPathFileA);
+ Commands.Stage(repo, fullPathFileA);
repo.Commit("Initial commit", Constants.Signature, Constants.Signature);
diff --git a/LibGit2Sharp.Tests/CherryPickFixture.cs b/LibGit2Sharp.Tests/CherryPickFixture.cs
index d9828e266..f4a383fef 100644
--- a/LibGit2Sharp.Tests/CherryPickFixture.cs
+++ b/LibGit2Sharp.Tests/CherryPickFixture.cs
@@ -19,7 +19,7 @@ public void CanCherryPick(bool fromDetachedHead)
{
if (fromDetachedHead)
{
- repo.Checkout(repo.Head.Tip.Id.Sha);
+ Commands.Checkout(repo, repo.Head.Tip.Id.Sha);
}
Commit commitToMerge = repo.Branches["fast_forward"].Tip;
@@ -46,7 +46,7 @@ public void CherryPickWithConflictDoesNotCommit()
using (var repo = new Repository(path))
{
var firstBranch = repo.CreateBranch("FirstBranch");
- repo.Checkout(firstBranch);
+ Commands.Checkout(repo, firstBranch);
// Commit with ONE new file to both first & second branch (SecondBranch is created on this commit).
AddFileCommitToRepo(repo, sharedBranchFileName);
@@ -56,7 +56,7 @@ public void CherryPickWithConflictDoesNotCommit()
AddFileCommitToRepo(repo, firstBranchFileName);
AddFileCommitToRepo(repo, sharedBranchFileName, "The first branches comment"); // Change file in first branch
- repo.Checkout(secondBranch);
+ Commands.Checkout(repo, secondBranch);
// Commit with ONE new file to second branch (FirstBranch and SecondBranch now point to separate commits that both have the same parent commit).
AddFileCommitToRepo(repo, secondBranchFileName);
AddFileCommitToRepo(repo, sharedBranchFileName, "The second branches comment"); // Change file in second branch
@@ -66,7 +66,7 @@ public void CherryPickWithConflictDoesNotCommit()
Assert.Equal(CherryPickStatus.Conflicts, cherryPickResult.Status);
Assert.Null(cherryPickResult.Commit);
- Assert.Equal(1, repo.Index.Conflicts.Count());
+ Assert.Single(repo.Index.Conflicts);
var conflict = repo.Index.Conflicts.First();
var changes = repo.Diff.Compare(repo.Lookup(conflict.Theirs.Id), repo.Lookup(conflict.Ours.Id));
@@ -126,11 +126,97 @@ public void CanSpecifyConflictFileStrategy(CheckoutFileConflictStrategy conflict
}
}
+ [Fact]
+ public void CanCherryPickCommit()
+ {
+ string path = SandboxMergeTestRepo();
+ using (var repo = new Repository(path))
+ {
+ var ours = repo.Head.Tip;
+
+ Commit commitToMerge = repo.Branches["fast_forward"].Tip;
+
+ var result = repo.ObjectDatabase.CherryPickCommit(commitToMerge, ours, 0, null);
+
+ Assert.Equal(MergeTreeStatus.Succeeded, result.Status);
+ Assert.Empty(result.Conflicts);
+ }
+ }
+
+ [Fact]
+ public void CherryPickWithConflictsReturnsConflicts()
+ {
+ const string conflictBranchName = "conflicts";
+
+ string path = SandboxMergeTestRepo();
+ using (var repo = new Repository(path))
+ {
+ Branch branch = repo.Branches[conflictBranchName];
+ Assert.NotNull(branch);
+
+ var result = repo.ObjectDatabase.CherryPickCommit(branch.Tip, repo.Head.Tip, 0, null);
+
+ Assert.Equal(MergeTreeStatus.Conflicts, result.Status);
+ Assert.NotEmpty(result.Conflicts);
+
+ }
+ }
+
+ [Fact]
+ public void CanCherryPickCommitIntoIndex()
+ {
+ string path = SandboxMergeTestRepo();
+ using (var repo = new Repository(path))
+ {
+ var ours = repo.Head.Tip;
+
+ Commit commitToMerge = repo.Branches["fast_forward"].Tip;
+
+ using (TransientIndex index = repo.ObjectDatabase.CherryPickCommitIntoIndex(commitToMerge, ours, 0, null))
+ {
+ var tree = index.WriteToTree();
+ Assert.Equal(commitToMerge.Tree.Id, tree.Id);
+ }
+ }
+ }
+
+ [Fact]
+ public void CanCherryPickIntoIndexWithConflicts()
+ {
+ const string conflictBranchName = "conflicts";
+
+ string path = SandboxMergeTestRepo();
+ using (var repo = new Repository(path))
+ {
+ Branch branch = repo.Branches[conflictBranchName];
+ Assert.NotNull(branch);
+
+ using (TransientIndex index = repo.ObjectDatabase.CherryPickCommitIntoIndex(branch.Tip, repo.Head.Tip, 0, null))
+ {
+ Assert.False(index.IsFullyMerged);
+
+ var conflict = index.Conflicts.First();
+
+ //Resolve the conflict by taking the blob from branch
+ var blob = repo.Lookup(conflict.Theirs.Id);
+ //Add() does not remove conflict entries for the same path, so they must be explicitly removed first.
+ index.Remove(conflict.Ours.Path);
+ index.Add(blob, conflict.Ours.Path, Mode.NonExecutableFile);
+
+ Assert.True(index.IsFullyMerged);
+ var tree = index.WriteToTree();
+
+ //Since we took the conflicted blob from the branch, the merged result should be the same as the branch.
+ Assert.Equal(branch.Tip.Tree.Id, tree.Id);
+ }
+ }
+ }
+
private Commit AddFileCommitToRepo(IRepository repository, string filename, string content = null)
{
Touch(repository.Info.WorkingDirectory, filename, content);
- repository.Stage(filename);
+ Commands.Stage(repository, filename);
return repository.Commit("New commit", Constants.Signature, Constants.Signature);
}
diff --git a/LibGit2Sharp.Tests/CleanFixture.cs b/LibGit2Sharp.Tests/CleanFixture.cs
index f674285c6..39c7a6152 100644
--- a/LibGit2Sharp.Tests/CleanFixture.cs
+++ b/LibGit2Sharp.Tests/CleanFixture.cs
@@ -14,13 +14,13 @@ public void CanCleanWorkingDirectory()
{
// Verify that there are the expected number of entries and untracked files
Assert.Equal(6, repo.RetrieveStatus().Count());
- Assert.Equal(1, repo.RetrieveStatus().Untracked.Count());
+ Assert.Single(repo.RetrieveStatus().Untracked);
repo.RemoveUntrackedFiles();
// Verify that there are the expected number of entries and 0 untracked files
Assert.Equal(5, repo.RetrieveStatus().Count());
- Assert.Equal(0, repo.RetrieveStatus().Untracked.Count());
+ Assert.Empty(repo.RetrieveStatus().Untracked);
}
}
diff --git a/LibGit2Sharp.Tests/CloneFixture.cs b/LibGit2Sharp.Tests/CloneFixture.cs
index 7fb05048f..09af475fd 100644
--- a/LibGit2Sharp.Tests/CloneFixture.cs
+++ b/LibGit2Sharp.Tests/CloneFixture.cs
@@ -33,8 +33,8 @@ public void CanClone(string url)
Assert.False(repo.Info.IsBare);
Assert.True(File.Exists(Path.Combine(scd.RootedDirectoryPath, "master.txt")));
- Assert.Equal(repo.Head.FriendlyName, "master");
- Assert.Equal(repo.Head.Tip.Id.ToString(), "49322bb17d3acc9146f98c97d078513228bbf3c0");
+ Assert.Equal("master", repo.Head.FriendlyName);
+ Assert.Equal("49322bb17d3acc9146f98c97d078513228bbf3c0", repo.Head.Tip.Id.ToString());
}
}
@@ -74,14 +74,14 @@ private void AssertLocalClone(string url, string path = null, bool isCloningAnEm
Assert.Equal(isCloningAnEmptyRepository ? 0 : 1, clonedRepo.Branches.Count(b => !b.IsRemote));
Assert.Equal(originalRepo.Tags.Count(), clonedRepo.Tags.Count());
- Assert.Equal(1, clonedRepo.Network.Remotes.Count());
+ Assert.Single(clonedRepo.Network.Remotes);
}
}
[Fact]
public void CanCloneALocalRepositoryFromALocalUri()
{
- var uri = new Uri(Path.GetFullPath(BareTestRepoPath));
+ var uri = new Uri($"file://{Path.GetFullPath(BareTestRepoPath)}");
AssertLocalClone(uri.AbsoluteUri, BareTestRepoPath);
}
@@ -195,19 +195,34 @@ public void CanCloneWithCredentials()
}
}
+ static Credentials CreateUsernamePasswordCredentials (string user, string pass, bool secure)
+ {
+ if (secure)
+ {
+ return new SecureUsernamePasswordCredentials
+ {
+ Username = user,
+ Password = Constants.StringToSecureString(pass),
+ };
+ }
+
+ return new UsernamePasswordCredentials
+ {
+ Username = user,
+ Password = pass,
+ };
+ }
+
[Theory]
- [InlineData("https://libgit2@bitbucket.org/libgit2/testgitrepository.git", "libgit3", "libgit3")]
- public void CanCloneFromBBWithCredentials(string url, string user, string pass)
+ [InlineData("https://libgit2@bitbucket.org/libgit2/testgitrepository.git", "libgit3", "libgit3", true)]
+ [InlineData("https://libgit2@bitbucket.org/libgit2/testgitrepository.git", "libgit3", "libgit3", false)]
+ public void CanCloneFromBBWithCredentials(string url, string user, string pass, bool secure)
{
var scd = BuildSelfCleaningDirectory();
string clonedRepoPath = Repository.Clone(url, scd.DirectoryPath, new CloneOptions()
{
- CredentialsProvider = (_url, _user, _cred) => new UsernamePasswordCredentials
- {
- Username = user,
- Password = pass,
- }
+ CredentialsProvider = (_url, _user, _cred) => CreateUsernamePasswordCredentials (user, pass, secure)
});
using (var repo = new Repository(clonedRepoPath))
@@ -222,12 +237,64 @@ public void CanCloneFromBBWithCredentials(string url, string user, string pass)
}
}
- [Fact]
- public void CloningAnUrlWithoutPathThrows()
+ [SkippableTheory]
+ [InlineData("https://github.com/libgit2/TestGitRepository.git", "github.com", typeof(CertificateX509))]
+ [InlineData("git@github.com:libgit2/TestGitRepository.git", "github.com", typeof(CertificateSsh))]
+ public void CanInspectCertificateOnClone(string url, string hostname, Type certType)
{
var scd = BuildSelfCleaningDirectory();
- Assert.Throws(() => Repository.Clone("http://github.com", scd.DirectoryPath));
+ InconclusiveIf(
+ () =>
+ certType == typeof (CertificateSsh) && !GlobalSettings.Version.Features.HasFlag(BuiltInFeatures.Ssh),
+ "SSH not supported");
+
+ bool wasCalled = false;
+ bool checksHappy = false;
+
+ var options = new CloneOptions {
+ CertificateCheck = (cert, valid, host) => {
+ wasCalled = true;
+
+ Assert.Equal(hostname, host);
+ Assert.Equal(certType, cert.GetType());
+
+ if (certType == typeof(CertificateX509)) {
+ Assert.True(valid);
+ var x509 = ((CertificateX509)cert).Certificate;
+ // we get a string with the different fields instead of a structure, so...
+ Assert.Contains("CN=github.com,", x509.Subject);
+ checksHappy = true;
+ return false;
+ }
+
+ if (certType == typeof(CertificateSsh)) {
+ var hostkey = (CertificateSsh)cert;
+ Assert.True(hostkey.HasMD5);
+ /*
+ * Once you've connected and thus your ssh has stored the hostkey,
+ * you can get the hostkey for a host with
+ *
+ * ssh-keygen -F github.com -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':'
+ *
+ * though GitHub's hostkey won't change anytime soon.
+ */
+ Assert.Equal("1627aca576282d36631b564debdfa648",
+ BitConverter.ToString(hostkey.HashMD5).ToLower().Replace("-", ""));
+ checksHappy = true;
+ return false;
+ }
+
+ return false;
+ },
+ };
+
+ Assert.Throws(() =>
+ Repository.Clone(url, scd.DirectoryPath, options)
+ );
+
+ Assert.True(wasCalled);
+ Assert.True(checksHappy);
}
[Theory]
@@ -286,7 +353,7 @@ private class CloneCallbackInfo
[Fact]
public void CanRecursivelyCloneSubmodules()
{
- var uri = new Uri(Path.GetFullPath(SandboxSubmoduleSmallTestRepo()));
+ var uri = new Uri($"file://{Path.GetFullPath(SandboxSubmoduleSmallTestRepo())}");
var scd = BuildSelfCleaningDirectory();
string relativeSubmodulePath = "submodule_target_wd";
@@ -437,7 +504,7 @@ public void CanRecursivelyCloneSubmodules()
[Fact]
public void CanCancelRecursiveClone()
{
- var uri = new Uri(Path.GetFullPath(SandboxSubmoduleSmallTestRepo()));
+ var uri = new Uri($"file://{Path.GetFullPath(SandboxSubmoduleSmallTestRepo())}");
var scd = BuildSelfCleaningDirectory();
string relativeSubmodulePath = "submodule_target_wd";
@@ -482,5 +549,54 @@ public void CanCancelRecursiveClone()
}
}
+
+ [Fact]
+ public void CannotCloneWithForbiddenCustomHeaders()
+ {
+ var scd = BuildSelfCleaningDirectory();
+
+ const string url = "https://github.com/libgit2/TestGitRepository";
+
+ const string knownHeader = "User-Agent: mygit-201";
+ var cloneOptions = new CloneOptions()
+ {
+ FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } }
+ };
+
+ Assert.Throws(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions));
+ }
+
+ [Fact]
+ public void CannotCloneWithMalformedCustomHeaders()
+ {
+ var scd = BuildSelfCleaningDirectory();
+
+ const string url = "https://github.com/libgit2/TestGitRepository";
+
+ const string knownHeader = "hello world";
+ var cloneOptions = new CloneOptions()
+ {
+ FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } }
+ };
+
+ Assert.Throws(() => Repository.Clone(url, scd.DirectoryPath, cloneOptions));
+ }
+
+ [Fact]
+ public void CanCloneWithCustomHeaders()
+ {
+ var scd = BuildSelfCleaningDirectory();
+
+ const string url = "https://github.com/libgit2/TestGitRepository";
+
+ const string knownHeader = "X-Hello: world";
+ var cloneOptions = new CloneOptions()
+ {
+ FetchOptions = new FetchOptions { CustomHeaders = new String[] { knownHeader } }
+ };
+
+ var clonedRepoPath = Repository.Clone(url, scd.DirectoryPath, cloneOptions);
+ Assert.True(Directory.Exists(clonedRepoPath));
+ }
}
}
diff --git a/LibGit2Sharp.Tests/CommitFixture.cs b/LibGit2Sharp.Tests/CommitFixture.cs
index 18fec45ba..f555e7874 100644
--- a/LibGit2Sharp.Tests/CommitFixture.cs
+++ b/LibGit2Sharp.Tests/CommitFixture.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text;
using LibGit2Sharp.Core;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
@@ -34,11 +35,11 @@ public void CanCorrectlyCountCommitsWhenSwitchingToAnotherBranch()
repo.Reset(ResetMode.Hard);
repo.RemoveUntrackedFiles();
- repo.Checkout("test");
+ Commands.Checkout(repo, "test");
Assert.Equal(2, repo.Commits.Count());
Assert.Equal("e90810b8df3e80c413d903f631643c716887138d", repo.Commits.First().Id.Sha);
- repo.Checkout("master");
+ Commands.Checkout(repo, "master");
Assert.Equal(9, repo.Commits.Count());
Assert.Equal("32eab9cb1f450b5fe7ab663462b77d7f4b703344", repo.Commits.First().Id.Sha);
}
@@ -69,7 +70,7 @@ public void CanEnumerateCommitsInDetachedHeadState()
ObjectId parentOfHead = repo.Head.Tip.Parents.First().Id;
repo.Refs.Add("HEAD", parentOfHead.Sha, true);
- Assert.Equal(true, repo.Info.IsHeadDetached);
+ Assert.True(repo.Info.IsHeadDetached);
Assert.Equal(6, repo.Commits.Count());
}
@@ -92,7 +93,7 @@ public void CanEnumerateCommitsFromSha()
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
- foreach (Commit commit in repo.Commits.QueryBy(new CommitFilter { Since = "a4a7dce85cf63874e984719f4fdd239f5145052f" }))
+ foreach (Commit commit in repo.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = "a4a7dce85cf63874e984719f4fdd239f5145052f" }))
{
Assert.NotNull(commit);
count++;
@@ -107,9 +108,9 @@ public void QueryingTheCommitHistoryWithUnknownShaOrInvalidEntryPointThrows()
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
- Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { Since = Constants.UnknownSha }).Count());
- Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { Since = "refs/heads/deadbeef" }).Count());
- Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { Since = null }).Count());
+ Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = Constants.UnknownSha }).Count());
+ Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = "refs/heads/deadbeef" }).Count());
+ Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = null }).Count());
}
}
@@ -121,8 +122,8 @@ public void QueryingTheCommitHistoryFromACorruptedReferenceThrows()
{
CreateCorruptedDeadBeefHead(repo.Info.Path);
- Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { Since = repo.Branches["deadbeef"] }).Count());
- Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { Since = repo.Refs["refs/heads/deadbeef"] }).Count());
+ Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = repo.Branches["deadbeef"] }).Count());
+ Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = repo.Refs["refs/heads/deadbeef"] }).Count());
}
}
@@ -132,8 +133,8 @@ public void QueryingTheCommitHistoryWithBadParamsThrows()
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
- Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { Since = string.Empty }));
- Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { Since = null }));
+ Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = string.Empty }));
+ Assert.Throws(() => repo.Commits.QueryBy(new CommitFilter { IncludeReachableFrom = null }));
Assert.Throws(() => repo.Commits.QueryBy(default(CommitFilter)));
}
}
@@ -150,12 +151,12 @@ public void CanEnumerateCommitsWithReverseTimeSorting()
{
foreach (Commit commit in repo.Commits.QueryBy(new CommitFilter
{
- Since = "a4a7dce85cf63874e984719f4fdd239f5145052f",
+ IncludeReachableFrom = "a4a7dce85cf63874e984719f4fdd239f5145052f",
SortBy = CommitSortStrategies.Time | CommitSortStrategies.Reverse
}))
{
Assert.NotNull(commit);
- Assert.True(commit.Sha.StartsWith(reversedShas[count]));
+ Assert.StartsWith(reversedShas[count], commit.Sha);
count++;
}
}
@@ -170,7 +171,7 @@ public void CanEnumerateCommitsWithReverseTopoSorting()
{
List commits = repo.Commits.QueryBy(new CommitFilter
{
- Since = "a4a7dce85cf63874e984719f4fdd239f5145052f",
+ IncludeReachableFrom = "a4a7dce85cf63874e984719f4fdd239f5145052f",
SortBy = CommitSortStrategies.Time | CommitSortStrategies.Reverse
}).ToList();
foreach (Commit commit in commits)
@@ -189,7 +190,7 @@ public void CanEnumerateCommitsWithReverseTopoSorting()
public void CanSimplifyByFirstParent()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = repo.Head, FirstParentOnly = true },
+ repo => new CommitFilter { IncludeReachableFrom = repo.Head, FirstParentOnly = true },
new[]
{
"4c062a6", "be3563a", "9fd738e",
@@ -203,7 +204,7 @@ public void CanGetParentsCount()
string path = SandboxBareTestRepo();
using (var repo = new Repository(path))
{
- Assert.Equal(1, repo.Commits.First().Parents.Count());
+ Assert.Single(repo.Commits.First().Parents);
}
}
@@ -216,12 +217,12 @@ public void CanEnumerateCommitsWithTimeSorting()
{
foreach (Commit commit in repo.Commits.QueryBy(new CommitFilter
{
- Since = "a4a7dce85cf63874e984719f4fdd239f5145052f",
+ IncludeReachableFrom = "a4a7dce85cf63874e984719f4fdd239f5145052f",
SortBy = CommitSortStrategies.Time
}))
{
Assert.NotNull(commit);
- Assert.True(commit.Sha.StartsWith(expectedShas[count]));
+ Assert.StartsWith(expectedShas[count], commit.Sha);
count++;
}
}
@@ -236,7 +237,7 @@ public void CanEnumerateCommitsWithTopoSorting()
{
List commits = repo.Commits.QueryBy(new CommitFilter
{
- Since = "a4a7dce85cf63874e984719f4fdd239f5145052f",
+ IncludeReachableFrom = "a4a7dce85cf63874e984719f4fdd239f5145052f",
SortBy = CommitSortStrategies.Topological
}).ToList();
foreach (Commit commit in commits)
@@ -255,7 +256,7 @@ public void CanEnumerateCommitsWithTopoSorting()
public void CanEnumerateFromHead()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = repo.Head },
+ repo => new CommitFilter { IncludeReachableFrom = repo.Head },
new[]
{
"4c062a6", "be3563a", "c47800c", "9fd738e",
@@ -274,10 +275,10 @@ public void CanEnumerateFromDetachedHead()
repoClone.RemoveUntrackedFiles();
string headSha = repoClone.Head.Tip.Sha;
- repoClone.Checkout(headSha);
+ Commands.Checkout(repoClone, headSha);
AssertEnumerationOfCommitsInRepo(repoClone,
- repo => new CommitFilter { Since = repo.Head },
+ repo => new CommitFilter { IncludeReachableFrom = repo.Head },
new[]
{
"32eab9c", "592d3c8", "4c062a6",
@@ -291,7 +292,7 @@ public void CanEnumerateFromDetachedHead()
public void CanEnumerateUsingTwoHeadsAsBoundaries()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = "HEAD", Until = "refs/heads/br2" },
+ repo => new CommitFilter { IncludeReachableFrom = "HEAD", ExcludeReachableFrom = "refs/heads/br2" },
new[] { "4c062a6", "be3563a" }
);
}
@@ -300,7 +301,7 @@ public void CanEnumerateUsingTwoHeadsAsBoundaries()
public void CanEnumerateUsingImplicitHeadAsSinceBoundary()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Until = "refs/heads/br2" },
+ repo => new CommitFilter { ExcludeReachableFrom = "refs/heads/br2" },
new[] { "4c062a6", "be3563a" }
);
}
@@ -309,7 +310,7 @@ public void CanEnumerateUsingImplicitHeadAsSinceBoundary()
public void CanEnumerateUsingTwoAbbreviatedShasAsBoundaries()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = "a4a7dce", Until = "4a202b3" },
+ repo => new CommitFilter { IncludeReachableFrom = "a4a7dce", ExcludeReachableFrom = "4a202b3" },
new[] { "a4a7dce", "c47800c", "9fd738e" }
);
}
@@ -318,7 +319,7 @@ public void CanEnumerateUsingTwoAbbreviatedShasAsBoundaries()
public void CanEnumerateCommitsFromTwoHeads()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = new[] { "refs/heads/br2", "refs/heads/master" } },
+ repo => new CommitFilter { IncludeReachableFrom = new[] { "refs/heads/br2", "refs/heads/master" } },
new[]
{
"4c062a6", "a4a7dce", "be3563a", "c47800c",
@@ -330,7 +331,7 @@ public void CanEnumerateCommitsFromTwoHeads()
public void CanEnumerateCommitsFromMixedStartingPoints()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = new object[] { repo.Branches["br2"],
+ repo => new CommitFilter { IncludeReachableFrom = new object[] { repo.Branches["br2"],
"refs/heads/master",
new ObjectId("e90810b8df3e80c413d903f631643c716887138d") } },
new[]
@@ -345,7 +346,7 @@ public void CanEnumerateCommitsFromMixedStartingPoints()
public void CanEnumerateCommitsUsingGlob()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = repo.Refs.FromGlob("refs/heads/*") },
+ repo => new CommitFilter { IncludeReachableFrom = repo.Refs.FromGlob("refs/heads/*") },
new[]
{
"4c062a6", "e90810b", "6dcf9bf", "a4a7dce", "be3563a", "c47800c", "9fd738e", "4a202b3", "41bc8c6", "5001298", "5b5b025", "8496071"
@@ -356,7 +357,7 @@ public void CanEnumerateCommitsUsingGlob()
public void CanHideCommitsUsingGlob()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = "refs/heads/packed-test", Until = repo.Refs.FromGlob("*/packed") },
+ repo => new CommitFilter { IncludeReachableFrom = "refs/heads/packed-test", ExcludeReachableFrom = repo.Refs.FromGlob("*/packed") },
new[]
{
"4a202b3", "5b5b025", "8496071"
@@ -378,7 +379,7 @@ public void CanEnumerateCommitsFromATagAnnotation()
private void CanEnumerateCommitsFromATag(Func transformer)
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = transformer(repo.Tags["test"]) },
+ repo => new CommitFilter { IncludeReachableFrom = transformer(repo.Tags["test"]) },
new[] { "e90810b", "6dcf9bf", }
);
}
@@ -389,7 +390,7 @@ public void CanEnumerateAllCommits()
AssertEnumerationOfCommits(
repo => new CommitFilter
{
- Since = repo.Refs.OrderBy(r => r.CanonicalName, StringComparer.Ordinal),
+ IncludeReachableFrom = repo.Refs.OrderBy(r => r.CanonicalName, StringComparer.Ordinal),
},
new[]
{
@@ -404,7 +405,7 @@ public void CanEnumerateAllCommits()
public void CanEnumerateCommitsFromATagWhichPointsToABlob()
{
AssertEnumerationOfCommits(
- repo => new CommitFilter { Since = repo.Tags["point_to_blob"] },
+ repo => new CommitFilter { IncludeReachableFrom = repo.Tags["point_to_blob"] },
new string[] { });
}
@@ -419,7 +420,7 @@ public void CanEnumerateCommitsFromATagWhichPointsToATree()
Tag tag = repo.ApplyTag("point_to_tree", headTreeSha);
AssertEnumerationOfCommitsInRepo(repo,
- r => new CommitFilter { Since = tag },
+ r => new CommitFilter { IncludeReachableFrom = tag },
new string[] { });
}
}
@@ -474,16 +475,16 @@ public void CanReadCommitData()
Assert.NotNull(commit.Author);
Assert.Equal("Scott Chacon", commit.Author.Name);
Assert.Equal("schacon@gmail.com", commit.Author.Email);
- Assert.Equal(1273360386, commit.Author.When.ToSecondsSinceEpoch());
+ Assert.Equal(1273360386, commit.Author.When.ToUnixTimeSeconds());
Assert.NotNull(commit.Committer);
Assert.Equal("Scott Chacon", commit.Committer.Name);
Assert.Equal("schacon@gmail.com", commit.Committer.Email);
- Assert.Equal(1273360386, commit.Committer.When.ToSecondsSinceEpoch());
+ Assert.Equal(1273360386, commit.Committer.When.ToUnixTimeSeconds());
Assert.Equal("181037049a54a1eb5fab404658a3a250b44335d7", commit.Tree.Sha);
- Assert.Equal(0, commit.Parents.Count());
+ Assert.Empty(commit.Parents);
}
}
@@ -538,55 +539,35 @@ public void DirectlyAccessingAnUnknownTreeEntryOfTheCommitReturnsNull()
}
}
- [Theory]
- [InlineData(null, "x@example.com")]
- [InlineData("", "x@example.com")]
- [InlineData("X", null)]
- [InlineData("X", "")]
- public void CommitWithInvalidSignatureConfigThrows(string name, string email)
- {
- string repoPath = InitNewRepository();
- string configPath = CreateConfigurationWithDummyUser(name, email);
- var options = new RepositoryOptions { GlobalConfigurationLocation = configPath };
-
- using (var repo = new Repository(repoPath, options))
- {
- Assert.Equal(name, repo.Config.GetValueOrDefault("user.name"));
- Assert.Equal(email, repo.Config.GetValueOrDefault("user.email"));
-
- Assert.Throws(
- () => repo.Commit("Initial egotistic commit", new CommitOptions { AllowEmptyCommit = true }));
- }
- }
-
[Fact]
public void CanCommitWithSignatureFromConfig()
{
string repoPath = InitNewRepository();
- string configPath = CreateConfigurationWithDummyUser(Constants.Signature);
- var options = new RepositoryOptions { GlobalConfigurationLocation = configPath };
- using (var repo = new Repository(repoPath, options))
+ using (var repo = new Repository(repoPath))
{
+ CreateConfigurationWithDummyUser(repo, Constants.Identity);
string dir = repo.Info.Path;
Assert.True(Path.IsPathRooted(dir));
Assert.True(Directory.Exists(dir));
const string relativeFilepath = "new.txt";
string filePath = Touch(repo.Info.WorkingDirectory, relativeFilepath, "null");
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
File.AppendAllText(filePath, "token\n");
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
Assert.Null(repo.Head[relativeFilepath]);
- Commit commit = repo.Commit("Initial egotistic commit");
+ Signature signature = repo.Config.BuildSignature(DateTimeOffset.Now);
+
+ Commit commit = repo.Commit("Initial egotistic commit", signature, signature);
AssertBlobContent(repo.Head[relativeFilepath], "nulltoken\n");
AssertBlobContent(commit[relativeFilepath], "nulltoken\n");
- AssertCommitSignaturesAre(commit, Constants.Signature);
+ AssertCommitIdentitiesAre(commit, Constants.Identity);
}
}
@@ -609,8 +590,8 @@ public void CommitParentsAreMergeHeads()
Assert.Equal(CurrentOperation.None, repo.Info.CurrentOperation);
Assert.Equal(2, newMergedCommit.Parents.Count());
- Assert.Equal(newMergedCommit.Parents.First().Sha, "c47800c7266a2be04c571c04d5a6614691ea99bd");
- Assert.Equal(newMergedCommit.Parents.Skip(1).First().Sha, "9fd738e8f7967c078dceed8190330fc8648ee56a");
+ Assert.Equal("c47800c7266a2be04c571c04d5a6614691ea99bd", newMergedCommit.Parents.First().Sha);
+ Assert.Equal("9fd738e8f7967c078dceed8190330fc8648ee56a", newMergedCommit.Parents.Skip(1).First().Sha);
// Assert reflog entry is created
var reflogEntry = repo.Refs.Log(repo.Refs.Head).First();
@@ -634,7 +615,7 @@ public void CommitCleansUpMergeMetadata()
const string relativeFilepath = "new.txt";
Touch(repo.Info.WorkingDirectory, relativeFilepath, "this is a new file");
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
string mergeHeadPath = Touch(repo.Info.Path, "MERGE_HEAD", "abcdefabcdefabcdefabcdefabcdefabcdefabcd");
string mergeMsgPath = Touch(repo.Info.Path, "MERGE_MSG", "This is a dummy merge.\n");
@@ -671,9 +652,9 @@ public void CanCommitALittleBit()
const string relativeFilepath = "new.txt";
string filePath = Touch(repo.Info.WorkingDirectory, relativeFilepath, "null");
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
File.AppendAllText(filePath, "token\n");
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
Assert.Null(repo.Head[relativeFilepath]);
@@ -682,23 +663,25 @@ public void CanCommitALittleBit()
const string shortMessage = "Initial egotistic commit";
const string commitMessage = shortMessage + "\n\nOnly the coolest commits from us";
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Commit commit = repo.Commit(commitMessage, author, author);
AssertBlobContent(repo.Head[relativeFilepath], "nulltoken\n");
AssertBlobContent(commit[relativeFilepath], "nulltoken\n");
- Assert.Equal(0, commit.Parents.Count());
+ Assert.Empty(commit.Parents);
Assert.False(repo.Info.IsHeadUnborn);
// Assert a reflog entry is created on HEAD
- Assert.Equal(1, repo.Refs.Log("HEAD").Count());
+ Assert.Single(repo.Refs.Log("HEAD"));
var reflogEntry = repo.Refs.Log("HEAD").First();
Assert.Equal(identity.Name, reflogEntry.Committer.Name);
Assert.Equal(identity.Email, reflogEntry.Committer.Email);
var now = DateTimeOffset.Now;
- Assert.InRange(reflogEntry.Committer.When, now - TimeSpan.FromSeconds(1), now);
+ Assert.InRange(reflogEntry.Committer.When, before, now);
Assert.Equal(commit.Id, reflogEntry.To);
Assert.Equal(ObjectId.Zero, reflogEntry.From);
@@ -706,11 +689,11 @@ public void CanCommitALittleBit()
// Assert a reflog entry is created on HEAD target
var targetCanonicalName = repo.Refs.Head.TargetIdentifier;
- Assert.Equal(1, repo.Refs.Log(targetCanonicalName).Count());
+ Assert.Single(repo.Refs.Log(targetCanonicalName));
Assert.Equal(commit.Id, repo.Refs.Log(targetCanonicalName).First().To);
File.WriteAllText(filePath, "nulltoken commits!\n");
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
var author2 = new Signature(author.Name, author.Email, author.When.AddSeconds(5));
Commit commit2 = repo.Commit("Are you trying to fork me?", author2, author2);
@@ -718,7 +701,7 @@ public void CanCommitALittleBit()
AssertBlobContent(repo.Head[relativeFilepath], "nulltoken commits!\n");
AssertBlobContent(commit2[relativeFilepath], "nulltoken commits!\n");
- Assert.Equal(1, commit2.Parents.Count());
+ Assert.Single(commit2.Parents);
Assert.Equal(commit.Id, commit2.Parents.First().Id);
// Assert the reflog is shifted
@@ -726,19 +709,19 @@ public void CanCommitALittleBit()
Assert.Equal(reflogEntry.To, repo.Refs.Log("HEAD").First().From);
Branch firstCommitBranch = repo.CreateBranch("davidfowl-rules", commit);
- repo.Checkout(firstCommitBranch);
+ Commands.Checkout(repo, firstCommitBranch);
File.WriteAllText(filePath, "davidfowl commits!\n");
var author3 = new Signature("David Fowler", "david.fowler@microsoft.com", author.When.AddSeconds(2));
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
Commit commit3 = repo.Commit("I'm going to branch you backwards in time!", author3, author3);
AssertBlobContent(repo.Head[relativeFilepath], "davidfowl commits!\n");
AssertBlobContent(commit3[relativeFilepath], "davidfowl commits!\n");
- Assert.Equal(1, commit3.Parents.Count());
+ Assert.Single(commit3.Parents);
Assert.Equal(commit.Id, commit3.Parents.First().Id);
AssertBlobContent(firstCommitBranch[relativeFilepath], "nulltoken\n");
@@ -757,7 +740,7 @@ private static void AddCommitToRepo(string path)
{
const string relativeFilepath = "test.txt";
Touch(repo.Info.WorkingDirectory, relativeFilepath, "test\n");
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
var author = new Signature("nulltoken", "emeric.fermas@gmail.com", DateTimeOffset.Parse("Wed, Dec 14 2011 08:29:03 +0100"));
repo.Commit("Initial commit", author, author);
@@ -793,17 +776,17 @@ public void CanAmendARootCommit()
using (var repo = new Repository(repoPath))
{
- Assert.Equal(1, repo.Head.Commits.Count());
+ Assert.Single(repo.Head.Commits);
Commit originalCommit = repo.Head.Tip;
- Assert.Equal(0, originalCommit.Parents.Count());
+ Assert.Empty(originalCommit.Parents);
CreateAndStageANewFile(repo);
Commit amendedCommit = repo.Commit("I'm rewriting the history!", Constants.Signature, Constants.Signature,
new CommitOptions { AmendPreviousCommit = true });
- Assert.Equal(1, repo.Head.Commits.Count());
+ Assert.Single(repo.Head.Commits);
AssertCommitHasBeenAmended(repo, amendedCommit, originalCommit);
}
@@ -824,6 +807,8 @@ public void CanAmendACommitWithMoreThanOneParent()
CreateAndStageANewFile(repo);
const string commitMessage = "I'm rewriting the history!";
+ var before = DateTimeOffset.Now.TruncateMilliseconds();
+
Commit amendedCommit = repo.Commit(commitMessage, Constants.Signature, Constants.Signature,
new CommitOptions { AmendPreviousCommit = true });
@@ -833,7 +818,7 @@ public void CanAmendACommitWithMoreThanOneParent()
string.Format("commit (amend): {0}", commitMessage),
mergedCommit.Id,
amendedCommit.Id,
- Constants.Identity, DateTimeOffset.Now);
+ Constants.Identity, before);
}
}
@@ -841,7 +826,7 @@ private static void CreateAndStageANewFile(IRepository repo)
{
string relativeFilepath = string.Format("new-file-{0}.txt", Path.GetRandomFileName());
Touch(repo.Info.WorkingDirectory, relativeFilepath, "brand new content\n");
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
}
private static void AssertCommitHasBeenAmended(IRepository repo, Commit amendedCommit, Commit originalCommit)
@@ -876,10 +861,10 @@ public void CanRetrieveChildrenOfASpecificCommit()
var filter = new CommitFilter
{
/* Revwalk from all the refs (git log --all) ... */
- Since = repo.Refs,
+ IncludeReachableFrom = repo.Refs,
/* ... and stop when the parent is reached */
- Until = parentSha
+ ExcludeReachableFrom = parentSha
};
var commits = repo.Commits.QueryBy(filter);
@@ -904,9 +889,9 @@ public void CanCorrectlyDistinguishAuthorFromCommitter()
using (var repo = new Repository(path))
{
var author = new Signature("Wilbert van Dolleweerd", "getit@xs4all.nl",
- Epoch.ToDateTimeOffset(1244187936, 120));
+ DateTimeOffset.FromUnixTimeSeconds(1244187936).ToOffset(TimeSpan.FromMinutes(120)));
var committer = new Signature("Henk Westhuis", "Henk_Westhuis@hotmail.com",
- Epoch.ToDateTimeOffset(1244286496, 120));
+ DateTimeOffset.FromUnixTimeSeconds(1244286496).ToOffset(TimeSpan.FromMinutes(120)));
Commit c = repo.Commit("I can haz an author and a committer!", author, committer);
@@ -930,10 +915,10 @@ public void CanCommitOnOrphanedBranch()
const string relativeFilepath = "test.txt";
Touch(repo.Info.WorkingDirectory, relativeFilepath, "test\n");
- repo.Stage(relativeFilepath);
+ Commands.Stage(repo, relativeFilepath);
repo.Commit("Initial commit", Constants.Signature, Constants.Signature);
- Assert.Equal(1, repo.Head.Commits.Count());
+ Assert.Single(repo.Head.Commits);
}
}
@@ -1015,8 +1000,8 @@ public void CanCommitAnEmptyCommitWhenMerging()
Commit newMergedCommit = repo.Commit("Merge commit", Constants.Signature, Constants.Signature);
Assert.Equal(2, newMergedCommit.Parents.Count());
- Assert.Equal(newMergedCommit.Parents.First().Sha, "32eab9cb1f450b5fe7ab663462b77d7f4b703344");
- Assert.Equal(newMergedCommit.Parents.Skip(1).First().Sha, "f705abffe7015f2beacf2abe7a36583ebee3487e");
+ Assert.Equal("32eab9cb1f450b5fe7ab663462b77d7f4b703344", newMergedCommit.Parents.First().Sha);
+ Assert.Equal("f705abffe7015f2beacf2abe7a36583ebee3487e", newMergedCommit.Parents.Skip(1).First().Sha);
}
}
@@ -1046,20 +1031,143 @@ public void CanNotAmendACommitInAWayThatWouldLeadTheNewCommitToBecomeEmpty()
using (var repo = new Repository(repoPath))
{
Touch(repo.Info.WorkingDirectory, "test.txt", "test\n");
- repo.Stage("test.txt");
+ Commands.Stage(repo, "test.txt");
repo.Commit("Initial commit", Constants.Signature, Constants.Signature);
Touch(repo.Info.WorkingDirectory, "new.txt", "content\n");
- repo.Stage("new.txt");
+ Commands.Stage(repo, "new.txt");
repo.Commit("One commit", Constants.Signature, Constants.Signature);
- repo.Remove("new.txt");
+ Commands.Remove(repo, "new.txt");
Assert.Throws(() => repo.Commit("Oops", Constants.Signature, Constants.Signature,
new CommitOptions { AmendPreviousCommit = true }));
}
}
+
+ [Fact]
+ public void CanPrettifyAMessage()
+ {
+ string input = "# Comment\nA line that will remain\n# And another character\n\n\n";
+ string expected = "A line that will remain\n";
+
+ Assert.Equal(expected, Commit.PrettifyMessage(input, '#'));
+ Assert.Equal(expected, Commit.PrettifyMessage(input.Replace('#', ';'), ';'));
+ }
+
+ private readonly string signedCommit =
+ "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n" +
+ "parent 8496071c1b46c854b31185ea97743be6a8774479\n" +
+ "author Ben Burkert 1358451456 -0800\n" +
+ "committer Ben Burkert 1358451456 -0800\n" +
+ "gpgsig -----BEGIN PGP SIGNATURE-----\n" +
+ " Version: GnuPG v1.4.12 (Darwin)\n" +
+ " \n" +
+ " iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al\n" +
+ " o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8\n" +
+ " JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq\n" +
+ " AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq\n" +
+ " SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW\n" +
+ " who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok\n" +
+ " 6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG\n" +
+ " cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu\n" +
+ " c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9\n" +
+ " ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J\n" +
+ " 7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc\n" +
+ " cpxtDQQMGYFpXK/71stq\n" +
+ " =ozeK\n" +
+ " -----END PGP SIGNATURE-----\n" +
+ "\n" +
+ "a simple commit which works\n";
+
+ private readonly string signatureData =
+ "-----BEGIN PGP SIGNATURE-----\n" +
+ "Version: GnuPG v1.4.12 (Darwin)\n" +
+ "\n" +
+ "iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al\n" +
+ "o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8\n" +
+ "JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq\n" +
+ "AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq\n" +
+ "SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW\n" +
+ "who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok\n" +
+ "6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG\n" +
+ "cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu\n" +
+ "c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9\n" +
+ "ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J\n" +
+ "7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc\n" +
+ "cpxtDQQMGYFpXK/71stq\n" +
+ "=ozeK\n" +
+ "-----END PGP SIGNATURE-----";
+
+ private readonly string signedData =
+ "tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n" +
+ "parent 8496071c1b46c854b31185ea97743be6a8774479\n" +
+ "author Ben Burkert 1358451456 -0800\n" +
+ "committer Ben Burkert 1358451456 -0800\n" +
+ "\n" +
+ "a simple commit which works\n";
+
+ [Fact]
+ public void CanExtractSignatureFromCommit()
+ {
+ string repoPath = InitNewRepository();
+ using (var repo = new Repository(repoPath))
+ {
+ var odb = repo.ObjectDatabase;
+ var signedId = odb.Write(Encoding.UTF8.GetBytes(signedCommit));
+
+ // Look up the commit to make sure we wrote something valid
+ var commit = repo.Lookup(signedId);
+ Assert.Equal("a simple commit which works\n", commit.Message);
+
+ var signatureInfo = Commit.ExtractSignature(repo, signedId, "gpgsig");
+ Assert.Equal(signedData, signatureInfo.SignedData);
+ Assert.Equal(signatureData, signatureInfo.Signature);
+
+ signatureInfo = Commit.ExtractSignature(repo, signedId);
+ Assert.Equal(signedData, signatureInfo.SignedData);
+ Assert.Equal(signatureData, signatureInfo.Signature);
+ }
+ }
+
+ [Fact]
+ public void CanCreateACommitString()
+ {
+ string repoPath = SandboxStandardTestRepo();
+ using (var repo = new Repository(repoPath))
+ {
+ var tipCommit = repo.Head.Tip;
+ var recreatedCommit = Commit.CreateBuffer(
+ tipCommit.Author,
+ tipCommit.Committer,
+ tipCommit.Message,
+ tipCommit.Tree,
+ tipCommit.Parents,
+ false, null);
+
+ var recreatedId = repo.ObjectDatabase.Write(Encoding.UTF8.GetBytes(recreatedCommit));
+ Assert.Equal(tipCommit.Id, recreatedId);
+ }
+ }
+
+ [Fact]
+ public void CanCreateASignedCommit()
+ {
+ string repoPath = SandboxStandardTestRepo();
+ using (var repo = new Repository(repoPath))
+ {
+ var odb = repo.ObjectDatabase;
+ var signedId = odb.Write(Encoding.UTF8.GetBytes(signedCommit));
+ var signedId2 = odb.CreateCommitWithSignature(signedData, signatureData);
+
+ Assert.Equal(signedId, signedId2);
+
+ var signatureInfo = Commit.ExtractSignature(repo, signedId2);
+ Assert.Equal(signedData, signatureInfo.SignedData);
+ Assert.Equal(signatureData, signatureInfo.Signature);
+ }
+ }
}
}
diff --git a/LibGit2Sharp.Tests/ConfigurationFixture.cs b/LibGit2Sharp.Tests/ConfigurationFixture.cs
index 78cb71c0b..999aa0336 100644
--- a/LibGit2Sharp.Tests/ConfigurationFixture.cs
+++ b/LibGit2Sharp.Tests/ConfigurationFixture.cs
@@ -1,8 +1,10 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
+using Xunit.Extensions;
namespace LibGit2Sharp.Tests
{
@@ -14,35 +16,6 @@ private static void AssertValueInLocalConfigFile(string repoPath, string regex)
AssertValueInConfigFile(configFilePath, regex);
}
- private static string RetrieveGlobalConfigLocation()
- {
- string[] variables = { "HOME", "USERPROFILE", };
-
- foreach (string variable in variables)
- {
- string potentialLocation = Environment.GetEnvironmentVariable(variable);
- if (string.IsNullOrEmpty(potentialLocation))
- {
- continue;
- }
-
- string potentialPath = Path.Combine(potentialLocation, ".gitconfig");
-
- if (File.Exists(potentialPath))
- {
- return potentialPath;
- }
- }
-
- throw new InvalidOperationException("Unable to determine the location of '.gitconfig' file.");
- }
-
- private static void AssertValueInGlobalConfigFile(string regex)
- {
- string configFilePath = RetrieveGlobalConfigLocation();
- AssertValueInConfigFile(configFilePath, regex);
- }
-
[Fact]
public void CanUnsetAnEntryFromTheLocalConfiguration()
{
@@ -63,12 +36,8 @@ public void CanUnsetAnEntryFromTheLocalConfiguration()
[Fact]
public void CanUnsetAnEntryFromTheGlobalConfiguration()
{
- SelfCleaningDirectory scd = BuildSelfCleaningDirectory();
-
- var options = BuildFakeConfigs(scd);
-
string path = SandboxBareTestRepo();
- using (var repo = new Repository(path, options))
+ using (var repo = new Repository(path))
{
Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global));
Assert.Equal(42, repo.Config.Get("Wow.Man-I-am-totally-global").Value);
@@ -81,6 +50,119 @@ public void CanUnsetAnEntryFromTheGlobalConfiguration()
}
}
+ [Fact]
+ public void CanAddAndReadMultivarFromTheLocalConfiguration()
+ {
+ string path = SandboxStandardTestRepo();
+ using (var repo = new Repository(path))
+ {
+ Assert.Empty(repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin"));
+
+ repo.Config.Add("unittests.plugin", "value1", ConfigurationLevel.Local);
+ repo.Config.Add("unittests.plugin", "value2", ConfigurationLevel.Local);
+
+ Assert.Equal(new[] { "value1", "value2" }, repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin" && x.Level == ConfigurationLevel.Local)
+ .Select(x => x.Value)
+ .ToArray());
+ }
+ }
+
+ [Fact]
+ public void CanAddAndReadMultivarFromTheGlobalConfiguration()
+ {
+ string path = SandboxBareTestRepo();
+ using (var repo = new Repository(path))
+ {
+ Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global));
+ Assert.Empty(repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin"));
+
+ repo.Config.Add("unittests.plugin", "value1", ConfigurationLevel.Global);
+ repo.Config.Add("unittests.plugin", "value2", ConfigurationLevel.Global);
+
+ Assert.Equal(new[] { "value1", "value2" }, repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin")
+ .Select(x => x.Value)
+ .ToArray());
+ }
+ }
+
+ [Fact]
+ public void CanUnsetAllFromTheGlobalConfiguration()
+ {
+ string path = SandboxBareTestRepo();
+ using (var repo = new Repository(path))
+ {
+ Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global));
+ Assert.Empty(repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin")
+ .Select(x => x.Value)
+ .ToArray());
+
+ repo.Config.Add("unittests.plugin", "value1", ConfigurationLevel.Global);
+ repo.Config.Add("unittests.plugin", "value2", ConfigurationLevel.Global);
+
+ Assert.Equal(2, repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin" && x.Level == ConfigurationLevel.Global)
+ .Select(x => x.Value)
+ .Count());
+
+ repo.Config.UnsetAll("unittests.plugin");
+
+ Assert.Equal(2, repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin" && x.Level == ConfigurationLevel.Global)
+ .Select(x => x.Value)
+ .Count());
+
+ repo.Config.UnsetAll("unittests.plugin", ConfigurationLevel.Global);
+
+ Assert.Empty(repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin")
+ .Select(x => x.Value)
+ .ToArray());
+ }
+ }
+
+ [Fact]
+ public void CanUnsetAllFromTheLocalConfiguration()
+ {
+ string path = SandboxStandardTestRepo();
+ using (var repo = new Repository(path))
+ {
+ Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global));
+ Assert.Empty(repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin")
+ .Select(x => x.Value)
+ .ToArray());
+
+ repo.Config.Add("unittests.plugin", "value1");
+ repo.Config.Add("unittests.plugin", "value2");
+
+ Assert.Equal(2, repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin" && x.Level == ConfigurationLevel.Local)
+ .Select(x => x.Value)
+ .Count());
+
+ repo.Config.UnsetAll("unittests.plugin");
+
+ Assert.Empty(repo.Config
+ .OfType>()
+ .Where(x => x.Key == "unittests.plugin"));
+ }
+ }
+
[Fact]
public void CanReadBooleanValue()
{
@@ -90,9 +172,9 @@ public void CanReadBooleanValue()
Assert.True(repo.Config.Get("core.ignorecase").Value);
Assert.True(repo.Config.GetValueOrDefault("core.ignorecase"));
- Assert.Equal(false, repo.Config.GetValueOrDefault("missing.key"));
- Assert.Equal(true, repo.Config.GetValueOrDefault("missing.key", true));
- Assert.Equal(true, repo.Config.GetValueOrDefault("missing.key", () => true));
+ Assert.False(repo.Config.GetValueOrDefault("missing.key"));
+ Assert.True(repo.Config.GetValueOrDefault("missing.key", true));
+ Assert.True(repo.Config.GetValueOrDefault("missing.key", () => true));
}
}
@@ -141,26 +223,26 @@ public void CanReadStringValue()
Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault("remote", "origin", "fetch"));
Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault(new[] { "remote", "origin", "fetch" }));
- Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key"));
- Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key", default(string)));
+ Assert.Null(repo.Config.GetValueOrDefault("missing.key"));
+ Assert.Null(repo.Config.GetValueOrDefault("missing.key", default(string)));
Assert.Throws(() => repo.Config.GetValueOrDefault("missing.key", default(Func)));
Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", "value"));
Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", () => "value"));
- Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local));
- Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, default(string)));
+ Assert.Null(repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local));
+ Assert.Null(repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, default(string)));
Assert.Throws(() => repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, default(Func)));
Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, "value"));
Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, () => "value"));
- Assert.Equal(null, repo.Config.GetValueOrDefault("missing", "config", "key"));
- Assert.Equal(null, repo.Config.GetValueOrDefault("missing", "config", "key", default(string)));
+ Assert.Null(repo.Config.GetValueOrDefault("missing", "config", "key"));
+ Assert.Null(repo.Config.GetValueOrDefault("missing", "config", "key", default(string)));
Assert.Throws(() => repo.Config.GetValueOrDefault("missing", "config", "key", default(Func)));
Assert.Equal("value", repo.Config.GetValueOrDefault("missing", "config", "key", "value"));
Assert.Equal("value", repo.Config.GetValueOrDefault("missing", "config", "key", () => "value"));
- Assert.Equal(null, repo.Config.GetValueOrDefault(new[] { "missing", "key" }));
- Assert.Equal(null, repo.Config.GetValueOrDefault(new[] { "missing", "key" }, default(string)));
+ Assert.Null(repo.Config.GetValueOrDefault(new[] { "missing", "key" }));
+ Assert.Null(repo.Config.GetValueOrDefault(new[] { "missing", "key" }, default(string)));
Assert.Throws(() => repo.Config.GetValueOrDefault(new[] { "missing", "key" }, default(Func)));
Assert.Equal("value", repo.Config.GetValueOrDefault(new[] { "missing", "key" }, "value"));
Assert.Equal("value", repo.Config.GetValueOrDefault(new[] { "missing", "key" }, () => "value"));
@@ -170,12 +252,10 @@ public void CanReadStringValue()
[Fact]
public void CanEnumerateGlobalConfig()
{
- string configPath = CreateConfigurationWithDummyUser(Constants.Signature);
- var options = new RepositoryOptions { GlobalConfigurationLocation = configPath };
-
var path = SandboxStandardTestRepoGitDir();
- using (var repo = new Repository(path, options))
+ using (var repo = new Repository(path))
{
+ CreateConfigurationWithDummyUser(repo, Constants.Identity);
var entry = repo.Config.FirstOrDefault>(e => e.Key == "user.name");
Assert.NotNull(entry);
Assert.Equal(Constants.Signature.Name, entry.Value);
@@ -227,16 +307,14 @@ public void CanFindInLocalConfig()
[Fact]
public void CanFindInGlobalConfig()
{
- string configPath = CreateConfigurationWithDummyUser(Constants.Signature);
- var options = new RepositoryOptions { GlobalConfigurationLocation = configPath };
var path = SandboxStandardTestRepoGitDir();
- using (var repo = new Repository(path, options))
+ using (var repo = new Repository(path))
{
- var matches = repo.Config.Find(@"\.name", ConfigurationLevel.Global);
+ var matches = repo.Config.Find("-rocks", ConfigurationLevel.Global);
Assert.NotNull(matches);
- Assert.Equal(new[] { "user.name" },
+ Assert.Equal(new[] { "woot.this-rocks" },
matches.Select(m => m.Key).ToArray());
}
}
@@ -256,7 +334,7 @@ public void CanSetBooleanValue()
[Fact]
public void SettingLocalConfigurationOutsideAReposThrows()
{
- using (var config = new Configuration(null, null, null))
+ using (var config = Configuration.BuildFrom(null, null, null, null))
{
Assert.Throws(() => config.Set("unittests.intsetting", 3));
}
@@ -358,12 +436,8 @@ public void SettingUnsupportedTypeThrows()
[Fact]
public void CanGetAnEntryFromASpecificStore()
{
- SelfCleaningDirectory scd = BuildSelfCleaningDirectory();
-
- var options = BuildFakeConfigs(scd);
-
string path = SandboxStandardTestRepo();
- using (var repo = new Repository(path, options))
+ using (var repo = new Repository(path))
{
Assert.True(repo.Config.HasConfig(ConfigurationLevel.Local));
Assert.True(repo.Config.HasConfig(ConfigurationLevel.Global));
@@ -383,17 +457,180 @@ public void CanGetAnEntryFromASpecificStore()
[Fact]
public void CanTellIfASpecificStoreContainsAKey()
{
- SelfCleaningDirectory scd = BuildSelfCleaningDirectory();
-
- var options = BuildFakeConfigs(scd);
-
string path = SandboxBareTestRepo();
- using (var repo = new Repository(path, options))
+ using (var repo = new Repository(path))
{
Assert.True(repo.Config.HasConfig(ConfigurationLevel.System));
Assert.Null(repo.Config.Get("MCHammer.You-cant-touch-this", ConfigurationLevel.System));
}
}
+
+ public static IEnumerable