| Archivers | ||
| Blame | ||
| Certificates | ||
| Commands | ||
| Core | ||
| Credentials | ||
| Diff | ||
| Exceptions | ||
| Filters | ||
| Handlers | ||
| Index | ||
| Logging | ||
| Notes | ||
| Options | ||
| Push | ||
| Rebase | ||
| References | ||
| Remotes | ||
| Results | ||
| Stash | ||
| Submodules | ||
| Tags | ||
| Targets | ||
| Transports | ||
| Worktrees | ||
| .gitignore | ||
| Blob.cs | ||
| Branch.cs | ||
| BranchCollection.cs | ||
| BranchTrackingDetails.cs | ||
| BranchUpdater.cs | ||
| BuiltInFeatures.cs | ||
| ChangeKind.cs | ||
| Commit.cs | ||
| CommitFilter.cs | ||
| CommitLog.cs | ||
| CommitRewriteInfo.cs | ||
| CommitSortStrategies.cs | ||
| Configuration.cs | ||
| ConfigurationEntry.cs | ||
| ConfigurationLevel.cs | ||
| Conflict.cs | ||
| ConflictCollection.cs | ||
| CurrentOperation.cs | ||
| DetachedHead.cs | ||
| FileStatus.cs | ||
| GitLink.cs | ||
| GitObject.cs | ||
| GitObjectMetadata.cs | ||
| GlobalSettings.cs | ||
| IBelongToARepository.cs | ||
| ICommitLog.cs | ||
| icon_lib.png | ||
| Identity.cs | ||
| IDiffResult.cs | ||
| Ignore.cs | ||
| IQueryableCommitLog.cs | ||
| IRepository.cs | ||
| MarketAlly.LibGit2Sharp.csproj | ||
| MatchedPathsAggregator.cs | ||
| MergeHead.cs | ||
| Mode.cs | ||
| Network.cs | ||
| ObjectDatabase.cs | ||
| ObjectId.cs | ||
| ObjectType.cs | ||
| OdbBackend.cs | ||
| OdbBackendStream.cs | ||
| PackBuilder.cs | ||
| README.md | ||
| Repository.cs | ||
| RepositoryExtensions.cs | ||
| RepositoryInformation.cs | ||
| RepositoryOperationContext.cs | ||
| RepositoryStatus.cs | ||
| ResetMode.cs | ||
| Signature.cs | ||
| SignatureInfo.cs | ||
| StatusEntry.cs | ||
| TransferProgress.cs | ||
| Tree.cs | ||
| TreeDefinition.cs | ||
| TreeEntry.cs | ||
| TreeEntryDefinition.cs | ||
| TreeEntryTargetType.cs | ||
| Version.cs | ||
MarketAlly.LibGit2Sharp
MarketAlly fork of LibGit2Sharp - a managed wrapper around the native libgit2 library providing full Git functionality in .NET.
Overview
This library provides programmatic access to Git repositories without requiring Git to be installed. It wraps the native libgit2 C library and exposes a clean, idiomatic .NET API.
Target Framework: .NET 9.0 License: MIT (original LibGit2Sharp license preserved)
Installation
Reference the project directly or via NuGet package dependency. Requires LibGit2Sharp.NativeBinaries for the native git binaries.
Quick Start
using MarketAlly.LibGit2Sharp;
// Open a repository (implements IDisposable)
using var repo = new Repository(@"C:\Projects\MyRepo");
// Read repository info
Console.WriteLine($"Current branch: {repo.Head.FriendlyName}");
Console.WriteLine($"Is bare: {repo.Info.IsBare}");
// Iterate recent commits
foreach (var commit in repo.Commits.Take(10))
{
Console.WriteLine($"{commit.Sha[..7]} - {commit.MessageShort}");
}
Core Classes
Repository
The primary entry point. Implements IRepository and IDisposable.
// Open existing repository
using var repo = new Repository(path);
// Check if path is a valid repo
bool isValid = Repository.IsValid(path);
// Discover repository from nested path (walks up to find .git)
string? repoPath = Repository.Discover(startingPath);
// Initialize new repository
string createdPath = Repository.Init(path);
string bareRepoPath = Repository.Init(path, isBare: true);
// Clone from remote
string clonedPath = Repository.Clone(sourceUrl, workdirPath, new CloneOptions
{
BranchName = "main",
RecurseSubmodules = true,
OnCheckoutProgress = (path, completed, total) => { }
});
Key Repository Properties
| Property | Type | Description |
|---|---|---|
Head |
Branch |
Current branch (or detached HEAD) |
Commits |
IQueryableCommitLog |
Queryable commit history |
Branches |
BranchCollection |
All local and remote branches |
Tags |
TagCollection |
All tags |
Refs |
ReferenceCollection |
All references |
Index |
Index |
Staging area |
Stashes |
StashCollection |
Stash entries |
Config |
Configuration |
Repository configuration |
Diff |
Diff |
Diff operations |
Network |
Network |
Remote operations |
ObjectDatabase |
ObjectDatabase |
Low-level object access |
Info |
RepositoryInformation |
Repo metadata |
Common Operations
Querying Commits
// Get HEAD commit
Commit head = repo.Head.Tip;
// Query with filters
var filter = new CommitFilter
{
IncludeReachableFrom = repo.Head,
ExcludeReachableFrom = repo.Tags["v1.0"],
SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Time
};
foreach (var commit in repo.Commits.QueryBy(filter))
{
Console.WriteLine($"{commit.Author.Name}: {commit.MessageShort}");
}
// Lookup by SHA
var commit = repo.Lookup<Commit>("abc1234");
Commit Properties
Commit commit = repo.Head.Tip;
string sha = commit.Sha; // Full SHA
string message = commit.Message; // Full message
string subject = commit.MessageShort; // First line only
Signature author = commit.Author; // Author name, email, timestamp
Signature committer = commit.Committer;
Tree tree = commit.Tree; // File tree at this commit
IEnumerable<Commit> parents = commit.Parents;
Branches
// List branches
foreach (var branch in repo.Branches)
{
Console.WriteLine($"{branch.FriendlyName} (Remote: {branch.IsRemote})");
}
// Get specific branch
Branch main = repo.Branches["main"];
Branch remote = repo.Branches["origin/main"];
// Create branch
Branch newBranch = repo.Branches.Add("feature/new", repo.Head.Tip);
// Delete branch
repo.Branches.Remove("feature/old");
// Tracking info
if (branch.IsTracking)
{
var tracking = branch.TrackingDetails;
Console.WriteLine($"Ahead: {tracking.AheadBy}, Behind: {tracking.BehindBy}");
}
Staging and Committing
// Stage files (using Commands helper)
Commands.Stage(repo, "file.txt");
Commands.Stage(repo, new[] { "src/*.cs" });
// Unstage
Commands.Unstage(repo, "file.txt");
// Check status
RepositoryStatus status = repo.RetrieveStatus(new StatusOptions());
foreach (var entry in status)
{
Console.WriteLine($"{entry.State}: {entry.FilePath}");
}
// Create commit
Signature author = new Signature("Name", "email@example.com", DateTimeOffset.Now);
Commit commit = repo.Commit("Commit message", author, author, new CommitOptions());
// Amend previous commit
Commit amended = repo.Commit("New message", author, author,
new CommitOptions { AmendPreviousCommit = true });
Diff Operations
// Compare trees (e.g., parent to commit)
Commit commit = repo.Head.Tip;
Commit parent = commit.Parents.FirstOrDefault();
// Get list of changed files
using var changes = repo.Diff.Compare<TreeChanges>(parent?.Tree, commit.Tree);
foreach (var change in changes)
{
Console.WriteLine($"{change.Status}: {change.Path}");
}
// Get full patch with line changes
using var patch = repo.Diff.Compare<Patch>(parent?.Tree, commit.Tree);
Console.WriteLine($"Lines added: {patch.LinesAdded}, deleted: {patch.LinesDeleted}");
foreach (var entry in patch)
{
Console.WriteLine($"--- {entry.Path} ---");
Console.WriteLine(entry.Patch);
}
// Compare working directory to index
using var workdirChanges = repo.Diff.Compare<TreeChanges>();
Network Operations
// List remotes
foreach (var remote in repo.Network.Remotes)
{
Console.WriteLine($"{remote.Name}: {remote.Url}");
}
// Fetch
Commands.Fetch(repo, "origin", new string[0], new FetchOptions
{
CredentialsProvider = (url, user, types) =>
new UsernamePasswordCredentials { Username = "user", Password = "token" }
}, "fetch log");
// Pull
Commands.Pull(repo, signature, new PullOptions());
// Push
repo.Network.Push(repo.Branches["main"], new PushOptions
{
CredentialsProvider = (url, user, types) => credentials
});
Reset and Checkout
// Reset HEAD (soft/mixed/hard)
repo.Reset(ResetMode.Hard, repo.Head.Tip);
// Checkout branch
Commands.Checkout(repo, repo.Branches["feature"]);
// Checkout specific commit (detached HEAD)
Commands.Checkout(repo, repo.Lookup<Commit>("abc1234"));
// Checkout specific files
repo.CheckoutPaths("HEAD~1", new[] { "file.txt" }, new CheckoutOptions());
History Rewriting
Rewrite commit messages or tree contents for multiple commits:
// Rewrite commit messages
var commitsToRewrite = repo.Commits.Take(5).ToArray();
repo.Refs.RewriteHistory(new RewriteHistoryOptions
{
BackupRefsNamespace = "refs/original/",
CommitHeaderRewriter = commit =>
{
if (commit.Message.StartsWith("WIP"))
{
return new CommitRewriteInfo
{
Message = commit.Message.Replace("WIP: ", ""),
Author = commit.Author,
Committer = commit.Committer
};
}
return null; // Keep original
},
PruneEmptyCommits = false
}, commitsToRewrite);
Low-Level Object Database
// Create commits directly (without updating refs)
var newCommit = repo.ObjectDatabase.CreateCommit(
author,
committer,
"Message",
tree,
parents,
prettifyMessage: false);
// Create tree from definition
var treeDefinition = TreeDefinition.From(repo.Head.Tip.Tree);
treeDefinition.Remove("old-file.txt");
var newTree = repo.ObjectDatabase.CreateTree(treeDefinition);
// Check if object exists
bool exists = repo.ObjectDatabase.Contains(objectId);
References
// Update reference target
repo.Refs.UpdateTarget("HEAD", newCommit.Sha);
repo.Refs.UpdateTarget(repo.Head, newCommit.Id, "reflog message");
// Create reference
repo.Refs.Add("refs/heads/new-branch", commit.Id, "created branch");
// Get references pointing to a commit
var refs = repo.Refs.ReachableFrom(new[] { commit });
Important Types
Signature
var sig = new Signature("Name", "email@example.com", DateTimeOffset.Now);
ObjectId
var id = new ObjectId("abc123def456...");
string sha = id.Sha;
ChangeKind
Added,Deleted,Modified,Renamed,Copied,Unmodified,TypeChanged,Untracked,Conflicted,Ignored
FileStatus
NewInIndex,ModifiedInIndex,DeletedFromIndex,NewInWorkdir,ModifiedInWorkdir,DeletedFromWorkdir,Conflicted, etc.
ResetMode
Soft- Move HEAD onlyMixed- Move HEAD and reset indexHard- Move HEAD, reset index and working directory
Thread Safety
- Repository instances are not thread-safe. Use separate instances per thread.
- For concurrent access, consider implementing a repository cache with TTL (see
GitOperationsServicein parent project for example).
Resource Management
Always dispose Repository instances:
// Using statement (recommended)
using var repo = new Repository(path);
// Or explicit disposal
var repo = new Repository(path);
try { /* work */ }
finally { repo.Dispose(); }
Global Settings
// Enable/disable object caching (useful during history rewriting)
GlobalSettings.SetEnableCaching(false);
// Get native library version
string version = GlobalSettings.Version.InformationalVersion;
Exceptions
| Exception | Cause |
|---|---|
RepositoryNotFoundException |
Path is not a git repository |
BareRepositoryException |
Operation not supported on bare repo |
LibGit2SharpException |
General git operation failure |
EmptyCommitException |
Commit would be empty |
MergeConflictException |
Unresolved conflicts |
NonFastForwardException |
Push rejected (not fast-forward) |
CheckoutConflictException |
Checkout blocked by local changes |
Differences from Original LibGit2Sharp
- Targets .NET 9.0 only (dropped older framework support)
- Namespace changed to
MarketAlly.LibGit2Sharp - Trimming support enabled for AOT scenarios
- Maintained by MarketAlly for internal projects
Dependencies
LibGit2Sharp.NativeBinaries(2.0.323) - Native libgit2 binaries