Giter Site home page Giter Site logo

kekyo / gitreader Goto Github PK

View Code? Open in Web Editor NEW
58.0 3.0 5.0 5.62 MB

Lightweight Git local repository traversal library for .NET/.NET Core/.NET Framework.

License: Apache License 2.0

C# 90.72% Batchfile 0.12% F# 8.45% Shell 0.71%
dotnet git managed repository fsharp csharp

gitreader's Introduction

GitReader

Lightweight Git local repository traversal library.

GitReader

Status

Project Status: Active โ€“ The project has reached a stable, usable state and is being actively developed.

Target Pakcage
Any NuGet GitReader
F# binding NuGet FSharp.GitReader

Japanese language

What is this?

Have you ever wanted to access information about your local Git repository in .NET? Explore and tag branches, get commit dates and contributor information, and read commit directory structures and files.

GitReader is written only managed code Git local repository traversal library for a wide range of .NET environments. It is lightweight, has a concise, easy-to-use interface, does not depend any other libraries, and does not contain native libraries, making it suitable for any environment.

Example:

using GitReader;
using GitReader.Structures;

// Open repository (With high-level interface)
using var repository =
    await Repository.Factory.OpenStructureAsync(
        "/home/kekyo/Projects/YourOwnLocalGitRepo");

// Found current head.
if (repository.Head is { } head)
{
    Console.WriteLine($"Name: {head.Name}");

    // Get head commit.
    var commit = await head.GetHeadCommitAsync();

    Console.WriteLine($"Hash: {commit.Hash}");
    Console.WriteLine($"Author: {commit.Author}");
    Console.WriteLine($"Committer: {commit.Committer}");
    Console.WriteLine($"Subject: {commit.Subject}");
    Console.WriteLine($"Body: {commit.Body}");
}

It has the following features:

  • It provides information on Git branches, tags, and commits.
  • Branch tree traversal.
  • Read only interface makes immutability.
  • Both high-level and primitive interfaces ready.
  • Fully asynchronous operation without any sync-over-async implementation.
  • Only contains 100% managed code. Independent of any external libraries other than the BCL and its compliant libraries.
  • Reliable zlib decompression using the .NET standard deflate implementation.

This library was designed from the ground up to replace libgit2sharp, on which RelaxVersioner depended. It primarily fits the purpose of easily extracting commit information from a Git repository.

Target .NET platforms

  • .NET 8.0 to 5.0
  • .NET Core 3.1 to 2.0
  • .NET Standard 2.1 to 1.6
  • .NET Framework 4.8.1 to 3.5

F# specialized binding

F# 5.0 or upper, it contains F# friendly signature definition. (Asynchronous operations with Async type, elimination of null values with Option, etc.)

  • .NET 8.0 to 5.0
  • .NET Core 3.1 to 2.0
  • .NET Standard 2.1, 2.0
  • .NET Framework 4.8.1 to 4.6.1

Note: All target framework variations are tested only newest it.


How to use

Install GitReader from NuGet.

  • Install FSharp.GitReader when you need to use with F#. It has F# friendly signature definition. You can freely use the same version of a package to switch back and forth between C# and F#, as long as the runtime instances are compatible.

GitReader has high-level interfaces and primitive interfaces.

  • The high-level interface is an interface that abstracts the Git repository. Easy to handle without knowing the internal structure of Git. It is possible to retrieve branch, tag, and commit information, and to read files (Blobs) at a glance.
  • The primitive interface is an interface that exposes the internal structure of the Git repository as it is, It is simple to handle if you know the internal structure of Git, and it offers high performance in asynchronous processing.

Sample Code

Comprehensive sample code can be found in the samples directory. The following things are minimal code fragments.


Samples (High-level interfaces)

The high-level interface is easily referenced by automatically reading much of the information tied to a commit.

Get current head commit

using GitReader;
using GitReader.Structures;

using StructuredRepository repository =
    await Repository.Factory.OpenStructureAsync(
        "/home/kekyo/Projects/YourOwnLocalGitRepo");

// Found current head
if (repository.Head is Branch head)
{
    Console.WriteLine($"Name: {head.Name}");

    // Get the commit that this HEAD points to:
    Commit commit = await head.GetHeadCommitAsync();

    Console.WriteLine($"Hash: {commit.Hash}");
    Console.WriteLine($"Author: {commit.Author}");
    Console.WriteLine($"Committer: {commit.Committer}");
    Console.WriteLine($"Subject: {commit.Subject}");
    Console.WriteLine($"Body: {commit.Body}");
}

Get a commit directly

if (await repository.GetCommitAsync(
    "1205dc34ce48bda28fc543daaf9525a9bb6e6d10") is Commit commit)
{
    Console.WriteLine($"Hash: {commit.Hash}");
    Console.WriteLine($"Author: {commit.Author}");
    Console.WriteLine($"Committer: {commit.Committer}");
    Console.WriteLine($"Subject: {commit.Subject}");
    Console.WriteLine($"Body: {commit.Body}");
}

Get a branch head commit

Branch branch = repository.Branches["develop"];

Console.WriteLine($"Name: {branch.Name}");
Console.WriteLine($"IsRemote: {branch.IsRemote}");

Commit commit = await branch.GetHeadCommitAsync();

Console.WriteLine($"Hash: {commit.Hash}");
Console.WriteLine($"Author: {commit.Author}");
Console.WriteLine($"Committer: {commit.Committer}");
Console.WriteLine($"Subject: {commit.Subject}");
Console.WriteLine($"Body: {commit.Body}");

Get a tag

Tag tag = repository.Tags["1.2.3"];

Console.WriteLine($"Name: {tag.Name}");
Console.WriteLine($"Type: {tag.Type}");
Console.WriteLine($"ObjectHash: {tag.ObjectHash}");

// If present the annotation?
if (tag.HasAnnotation)
{
    // Get tag annotation.
    Annotation annotation = await tag.GetAnnotationAsync();

    Console.WriteLine($"Tagger: {annotation.Tagger}");
    Console.WriteLine($"Message: {annotation.Message}");
}

// If tag is a commit tag?
if (tag.Type == ObjectTypes.Commit)
{
    // Get the commit indicated by the tag.
    Commit commit = await tag.GetCommitAsync();

    // ...
}

Get related branches and tags from a commit

if (await repository.GetCommitAsync(
    "1205dc34ce48bda28fc543daaf9525a9bb6e6d10") is Commit commit)
{
    // The ReadOnlyArray<T> class is used to protect the inner array.
    // Usage is the same as for general collections such as List<T>.
    ReadOnlyArray<Branch> branches = commit.Branches;
    ReadOnlyArray<Tag> tags = commit.Tags;

    // ...
}

Enumerate branches

foreach (Branch branch in repository.Branches.Values)
{
    Console.WriteLine($"Name: {branch.Name}");
    Console.WriteLine($"IsRemote: {branch.IsRemote}");

    Commit commit = await branch.GetHeadCommitAsync();

    Console.WriteLine($"Hash: {commit.Hash}");
    Console.WriteLine($"Author: {commit.Author}");
    Console.WriteLine($"Committer: {commit.Committer}");
    Console.WriteLine($"Subject: {commit.Subject}");
    Console.WriteLine($"Body: {commit.Body}");
}

Enumerate tags

foreach (Tag tag in repository.Tags.Values)
{
    Console.WriteLine($"Name: {tag.Name}");
    Console.WriteLine($"Type: {tag.Type}");
    Console.WriteLine($"ObjectHash: {tag.ObjectHash}");
}

Enumerate stashes

foreach (Stash stash in repository.Stashes)
{
    Console.WriteLine($"Commit: {stash.Commit.Hash}");
    Console.WriteLine($"Committer: {stash.Committer}");
    Console.WriteLine($"Message: {stash.Message}");
}

Get parent commits

if (await repository.GetCommitAsync(
    "6961a50ef3ad4e43ed9774daffd8457d32cf5e75") is Commit commit)
{
    Commit[] parents = await commit.GetParentCommitsAsync();

    foreach (Commit parent in parents)
    {
        Console.WriteLine($"Hash: {parent.Hash}");
        Console.WriteLine($"Author: {parent.Author}");
        Console.WriteLine($"Committer: {parent.Committer}");
        Console.WriteLine($"Subject: {parent.Subject}");
        Console.WriteLine($"Body: {parent.Body}");
    }
}

Get commit tree information

Tree information is the tree structure of directories and files that are placed when a commit is checked out. The code shown here does not actually 'check out', but reads these structures as information.

if (await repository.GetCommitAsync(
    "6961a50ef3ad4e43ed9774daffd8457d32cf5e75") is Commit commit)
{
    TreeRoot treeRoot = await commit.GetTreeRootAsync();

    foreach (TreeEntry entry in treeRoot.Children)
    {
        Console.WriteLine($"Hash: {entry.Hash}");
        Console.WriteLine($"Name: {entry.Name}");
        Console.WriteLine($"Modes: {entry.Modes}");
    }
}

Read blob by stream

if (await repository.GetCommitAsync(
    "6961a50ef3ad4e43ed9774daffd8457d32cf5e75") is Commit commit)
{
    TreeRoot treeRoot = await commit.GetTreeRootAsync();

    foreach (TreeEntry entry in treeRoot.Children)
    {
        // For Blob, the instance type is `TreeBlobEntry`.
        if (entry is TreeBlobEntry blob)
        {
            using Stream stream = await blob.OpenBlobAsync();

            // (You can access the blob...)
        }
    }
}

Reading a submodule in commit tree.

You can also identify references to submodules. However, if you want to reference information in a submodule, you must open a new repository. This is accomplished with OpenSubModuleAsync().

if (await repository.GetCommitAsync(
    "6961a50ef3ad4e43ed9774daffd8457d32cf5e75") is Commit commit)
{
    TreeRoot treeRoot = await commit.GetTreeRootAsync();

    foreach (TreeEntry entry in treeRoot.Children)
    {
        // For a submodule, the instance type is `TreeSubModuleEntry`.
        if (entry is TreeSubModuleEntry subModule)
        {
            // Open this submodule repository.
            using var subModuleRepository = await subModule.OpenSubModuleAsync();

            // Retreive the commit hash specified in the original repository.
            if (await subModuleRepository.GetCommitAsync(
                subModule.Hash) is Commit subModuleCommit)
            {
                // ...
            }
        }
    }
}

Traverse a branch through primary commits

A commit in Git can have multiple parent commits. This occurs with merge commits, where there are links to all parent commits. The first parent commit is called the "primary commit" and is always present except for the first commit in the repository.

Use GetPrimaryParentCommitAsync() to retrieve the primary commit, and use GetParentCommitsAsync() to get links to all parent commits.

As a general thing about Git, it is important to note that the parent-child relationship of commits (caused by branching and merging), always expressed as one direction, from "child" to "parent".

This is also true for the high-level interface; there is no interface for referencing a child from its parent. Therefore, if you wish to perform such a search, you must construct the link in the reverse direction on your own.

The following example recursively searches for a parent commit from a child commit.

Branch branch = repository.Branches["develop"];

Console.WriteLine($"Name: {branch.Name}");
Console.WriteLine($"IsRemote: {branch.IsRemote}");

Commit? current = await branch.GetHeadCommitAsync();

// Continue as long as the parent commit exists.
while (current != null)
{
    Console.WriteLine($"Hash: {current.Hash}");
    Console.WriteLine($"Author: {current.Author}");
    Console.WriteLine($"Committer: {current.Committer}");
    Console.WriteLine($"Subject: {current.Subject}");
    Console.WriteLine($"Body: {current.Body}");

    // Get primary parent commit.
    current = await current.GetPrimaryParentCommitAsync();
}

Samples (Primitive interfaces)

The high-level interface is implemented internally using these primitive interfaces. We do not have a complete list of all examples, so we recommend referring to the GitReader code if you need information.

Read current head commit

using GitReader;
using GitReader.Primitive;

using PrimitiveRepository repository =
    await Repository.Factory.OpenPrimitiveAsync(
        "/home/kekyo/Projects/YourOwnLocalGitRepo");

if (await repository.GetCurrentHeadReferenceAsync() is PrimitiveReference head)
{
    if (await repository.GetCommitAsync(head) is PrimitiveCommit commit)
    {
        Console.WriteLine($"Hash: {commit.Hash}");
        Console.WriteLine($"Author: {commit.Author}");
        Console.WriteLine($"Committer: {commit.Committer}");
        Console.WriteLine($"Message: {commit.Message}");
    }
}

Read a commit directly

if (await repository.GetCommitAsync(
    "1205dc34ce48bda28fc543daaf9525a9bb6e6d10") is PrimitiveCommit commit)
{
    Console.WriteLine($"Hash: {commit.Hash}");
    Console.WriteLine($"Author: {commit.Author}");
    Console.WriteLine($"Committer: {commit.Committer}");
    Console.WriteLine($"Message: {commit.Message}");
}

Read a branch head commit

PrimitiveReference head = await repository.GetBranchHeadReferenceAsync("develop");

if (await repository.GetCommitAsync(head) is PrimitiveCommit commit)
{
    Console.WriteLine($"Hash: {commit.Hash}");
    Console.WriteLine($"Author: {commit.Author}");
    Console.WriteLine($"Committer: {commit.Committer}");
    Console.WriteLine($"Message: {commit.Message}");
}

Enumerate branches

PrimitiveReference[] branches = await repository.GetBranchHeadReferencesAsync();

foreach (PrimitiveReference branch in branches)
{
    Console.WriteLine($"Name: {branch.Name}");
    Console.WriteLine($"Commit: {branch.Commit}");
}

Enumerate remote branches

PrimitiveReference[] branches = await repository.GetRemoteBranchHeadReferencesAsync();

foreach (PrimitiveReference branch in branches)
{
    Console.WriteLine($"Name: {branch.Name}");
    Console.WriteLine($"Commit: {branch.Commit}");
}

Enumerate tags

PrimitiveTagReference[] tagReferences = await repository.GetTagReferencesAsync();

foreach (PrimitiveTagReference tagReference in tagReferences)
{
    PrimitiveTag tag = await repository.GetTagAsync(tagReference);

    Console.WriteLine($"Hash: {tag.Hash}");
    Console.WriteLine($"Type: {tag.Type}");
    Console.WriteLine($"Name: {tag.Name}");
    Console.WriteLine($"Tagger: {tag.Tagger}");
    Console.WriteLine($"Message: {tag.Message}");
}

Read commit tree information

if (await repository.GetCommitAsync(
    "1205dc34ce48bda28fc543daaf9525a9bb6e6d10") is PrimitiveCommit commit)
{
    PrimitiveTree tree = await repository.GetTreeAsync(commit.TreeRoot);

    foreach (Hash childHash in tree.Children)
    {
        PrimitiveTreeEntry child = await repository.GetTreeAsync(childHash);

        Console.WriteLine($"Hash: {child.Hash}");
        Console.WriteLine($"Name: {child.Name}");
        Console.WriteLine($"Modes: {child.Modes}");
    }
}

Read blob by stream

if (await repository.GetCommitAsync(
    "1205dc34ce48bda28fc543daaf9525a9bb6e6d10") is PrimitiveCommit commit)
{
    PrimitiveTree tree = await repository.GetTreeAsync(commit.TreeRoot);

    foreach (Hash childHash in tree.Children)
    {
        PrimitiveTreeEntry child = await repository.GetTreeAsync(childHash);
        if (child.Modes.HasFlag(PrimitiveModeFlags.File))
        {
            using Stream stream = await repository.OpenBlobAsync(child.Hash);

            // (You can access the blob...)
        }
    }
}

Reading a submodule in commit tree.

if (await repository.GetCommitAsync(
    "1205dc34ce48bda28fc543daaf9525a9bb6e6d10") is PrimitiveCommit commit)
{
    PrimitiveTree tree = await repository.GetTreeAsync(commit.TreeRoot);

    foreach (Hash childHash in tree.Children)
    {
        PrimitiveTreeEntry child = await repository.GetTreeAsync(childHash);

        // If this tree entry is a submodule.
        if (child.SpecialModes == PrimitiveSpecialModes.SubModule)
        {
            // The argument must be a "tree path".
            // It is the sequence of all paths from the repository root up to this entry.
            using var subModuleRepository = await repository.OpenSubModuleAsync(
                new[] { child });

            if (await repository.GetCommitAsync(
                child.Hash) is PrimitiveCommit subModuleCommit)
            {
                // ...
            }
        }
    }
}

Traverse a commit through primary commits

if (await repository.GetCommitAsync(
    "1205dc34ce48bda28fc543daaf9525a9bb6e6d10") is PrimitiveCommit commit)
{
    while (true)
    {
        Console.WriteLine($"Hash: {commit.Hash}");
        Console.WriteLine($"Author: {commit.Author}");
        Console.WriteLine($"Committer: {commit.Committer}");
        Console.WriteLine($"Message: {commit.Message}");

        // Bottom of branch.
        if (commit.Parents.Length == 0)
        {
            break;
        }

        // Get primary parent.
        Hash primary = commit.Parents[0];
        if (await repository.GetCommitAsync(primary) is not PrimitiveCommit parent)
        {
            throw new Exception();
        }

        current = parent;
    }
}

Samples (Others)

SHA1 hash operations

Hash hashFromString = "1205dc34ce48bda28fc543daaf9525a9bb6e6d10";
Hash hashFromArray = new byte[] { 0x12, 0x05, 0xdc, ... };

var hashFromStringConstructor =
    new Hash("1205dc34ce48bda28fc543daaf9525a9bb6e6d10");
var hashFromArrayConstructor =
    new Hash(new byte[] { 0x12, 0x05, 0xdc, ... });

if (Hash.TryParse("1205dc34ce48bda28fc543daaf9525a9bb6e6d10", out Hash hash))
{
    // ...
}

Commit commit = ...;
Hash targetHash = commit;

Enumerate remote urls

foreach (KeyValuePair<string, string> entry in repository.RemoteUrls)
{
    Console.WriteLine($"Remote: Name={entry.Key}, Url={entry.Value}");
}

Contributed (Thanks!)

License

Apache-v2

History

  • 1.7.0:
    • Rebuilt on .NET 8.0 SDK.
  • 1.6.0:
    • Added submodule accessor.
    • Fixed invalid remote url entries at multiple declaration. (#10)
  • 1.5.0:
    • Included .NET 8.0 RC2 assembly (net8.0).
  • 1.4.0:
    • Improved stability to open metadata files, avoids file sharing violation.
  • 1.3.0:
    • Fixed internal cached streams locked when disposed the repository. (#9)
  • 1.2.0:
    • Added Repository.getCurrentHead() function on F# interface.
    • Uses ArrayPool on both netcoreapp and netstandard2.1.
  • 1.1.0:
    • Fixed causing path not found exception when lack these directories.
    • Added debugger display attribute on some types.
  • 1.0.0:
    • Reached 1.0.0 ๐ŸŽ‰
    • Fixed broken decoded stream for deltified stream with derived large-base-stream.
  • 0.13.0:
    • Improved performance.
  • 0.12.0:
    • Reduced the time taken to open structured repository when peeled-tag is available from packed-refs.
    • The Tags interface has been rearranged.
    • Added raw stream opener interfaces.
    • Some bug fixed.
  • 0.11.0:
    • The structured interface no longer reads commit information when it opens. Instead, you must explicitly call Branch.GetHeadCommitAsync(), but the open will be processed much faster.
    • Improved performance.
  • 0.10.0:
    • Implemented stash interface.
    • Improved performance.
    • Fixed minor corruption on blob data when it arrives zero-sized deltified data.
  • 0.9.0:
    • Exposed remote urls.
    • Changed some type names avoid confliction.
  • 0.8.0:
    • Added tree/blob accessors.
    • Improved performance.
  • 0.7.0:
    • Switched primitive interface types with prefix Primitive.
    • Improved performance.
    • Tested large repositories.
  • 0.6.0:
    • Improved message handling on high-level interfaces.
    • Re-implemented delta compression decoder.
    • Supported both FETCH_HEAD and packed_refs parser.
    • Improved performance.
    • Removed index locker.
    • Fixed contains invalid hash on annotated commit tag.
    • Improved minor interface features.
  • 0.5.0:
    • Supported deconstructor by F# active patterns.
    • Downgraded at least F# version 5.
  • 0.4.0:
    • Added F# binding.
    • Fixed lack for head branch name.
  • 0.3.0:
    • Supported ability for not found detection.
  • 0.2.0:
    • The shape of the public interfaces are almost fixed.
    • Improved high-level interfaces.
    • Splitted core library (Preparation for F# binding)
  • 0.1.0:
    • Initial release.

gitreader's People

Contributors

jairbubbles avatar kekyo avatar trejjam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

gitreader's Issues

[Feature Request] Support git submodule repository

I want to get git submodule repository information with GitReader
Currency it fails to get information with Repository does not exist. exceptions occurred at following lines.

It's due to .git directory is not exist but only exists .git file on directory that are managed by git submodule.

Requested Features
Is is able to support for following repository types.

  • Repository that is maanaged by git submodule
  • Repository that is created with git init --separate-git-dir options

These repository contains .git file. and that file contains gitdir: directory path.

Additional context
As far as I've tested. It can get git submodule information with following code modifications.

        if (!Directory.Exists(repositoryPath))
        {
            if (!File.Exists(repositoryPath))
            {
                throw new ArgumentException("Repository does not exist.");
            }

            // Read `git` file's `gitdir:` information
            var gitDirLine = File.ReadAllLines(repositoryPath).FirstOrDefault() ?? "";
            if (gitDirLine.StartsWith("gitdir: ", StringComparison.Ordinal))
            {
                var gitDirPath = gitDirLine.Substring("gitdir: ".Length);

                // Resolve to full path (And normalize path directory separators)
                // TODO: Relative path that starts with "~/" should be resolved (Currently it's resolved as `~/` directory) 
                repositoryPath = Path.IsPathRooted(gitDirPath)
                    ? Path.GetFullPath(gitDirPath)
                    : Path.GetFullPath(Utilities.Combine(path, gitDirPath));
            }

            // Check specified `gitdir` exists
            if (!Directory.Exists(repositoryPath))
            {
                throw new ArgumentException("Repository does not exist. `.git` file exists. But failed to `gitdir` or specified directory is not exists.");
            }
        }

Wrong RemoteUrls data returned when git repository contains multiple remote sections

Describe the bug
I want to get RemoteUrls information with GitReader.
But it seems to return incorrect data if the `.git/config' file contains multiple remote sections.

To Reproduce
Run the following code on a git repository that contains multiple remote sections. (e.g. forked repository)

using var repository = await Repository.Factory.OpenPrimitiveAsync("[git repository path]");
foreach(var remoteUrl in repository.RemoteUrls)
{
    Console.WriteLine($"{remoteUrl.Key}:{remoteUrl.Value}");
}

Console outputs

origin: https://github.com/kekyo/GitReader.git

Excerpt of local .git/config file

[remote "origin"]
	url = https://github.com/my-forked-repo/GitReader.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[remote "upstream"]
	url = https://github.com/kekyo/GitReader.git
	fetch = +refs/heads/*:refs/remotes/upstream/*

Expected behavior
I'm expecting following RemoteUrls information returned that match with git remote -v command output..

origin: https://github.com/my-forked-repo/GitReader.git
upstrem: https://github.com/kekyo/GitReader.git

Additional context
The current RepositoryAccessor::ReadRemoteReferencesAsync' method returns the following information.

  • First remote name.
  • Last remote url

ToDo to 1.0.0

  • Reduces Task switching costs.
    • StreamReader
    • DeflateStream (optional, may not be implemented)
  • Completion for large repository tests. (Whether the data is corrupt or not)
    • Commit messages, metadatas.
    • Blob streams.
  • Makes configurable minor execution parameters.
  • Minor interface changing.

Other features will be considered after 1.0.0.

Awesome work! ๐Ÿ˜

Having a managed library to read .git repository is a plus for the .NET ecosystem.

I quickly looked at how libGit2Sharp is used in our application and I'm wondering if you have in mind to support more things in this library or keep it super minimalistic.

Here is the main struct that we fill when we inspect a repo:

internal struct GitInfos
    {
        public string RemoteUrl;
        public IGitCommit HeadCommit;
        public IGitBranch CurrentBranch;
        public IReadOnlyList<GitBranch> Branches;
        public IGitTag[] Tags;
        public IGitRemote[] Remotes;
        public IGitStash[] Stashes;
        public DateTimeOffset LastCommitDate;
        public int BehindDefaultBranch;
        public IGitBranch DefaultRemoteBranch;
        public IGitOperation CurrentOperation;
}

Your lib seems to support already the main things but is lacking things like remotes or stashes.

Let me know, I'd be much interested to contribute. Cheers!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.