git2dart 0.2.2 copy "git2dart: ^0.2.2" to clipboard
git2dart: ^0.2.2 copied to clipboard

Dart bindings to libgit2, provides ability to use libgit2 library in Dart and Flutter.

git2dart #

Dart bindings to libgit2 #

git2dart package provides ability to use libgit2 in Dart/Flutter.

This is a hardfork of libgit2dart

Currently supported platforms are 64-bit Windows, Linux, MacOS on both Flutter and Dart VM.

Getting Started #

  1. Add package as a dependency in your pubspec.yaml
  2. Import:
import 'package:git2dart/git2dart.dart';
  1. Verify installation (should return string with version of libgit2 shipped with package):
...
print(Libgit2.version);
...

Note: The following steps only required if you are using package in Dart application (Flutter application will have libgit2 library bundled automatically when you build for release).

System Dependencies #

To use git2dart, you need to have the following system dependencies installed:

Linux #

sudo apt-get install libssl-dev libpcre3

macOS #

brew install openssl

Windows #

choco install openssl -y

Usage #

git2dart provides you ability to manage Git repository. You can read and write objects (commit, tag, tree and blob), walk a tree, access the staging area, manage config and lots more.

Let's look at some of the classes and methods (you can also check example).

Repository #

Instantiation

You can instantiate a Repository class with a path to open an existing repository:

final repo = Repository.open('path/to/repository'); // => Repository

You can create new repository with provided path and optional bare argument if you want it to be bare:

final repo = Repository.init(path: 'path/to/folder', bare: true); // => Repository

You can clone the existing repository at provided url into local path:

final repo = Repository.clone(
  url: 'https://some.url/',
  localPath: 'path/to/clone/into',
); // => Repository

Also you can discover the path to the '.git' directory of repository if you provide a path to subdirectory:

Repository.discover(startPath: '/repository/lib/src'); // => '/repository/.git/'

Once the repository object is instantiated (repo in the following examples) you can perform various operations on it.

Accessing repository

// Boolean repository state values
repo.isBare; // => false
repo.isEmpty; // => true
repo.isHeadDetached; // => false
repo.isBranchUnborn; // => false
repo.isWorktree; // => false

// Path getters
repo.path; // => 'path/to/repository/.git/'
repo.workdir; // => 'path/to/repository/

// The HEAD of the repository
final ref = repo.head; // => Reference

// From returned ref you can get the 'name', 'target', target 'sha' and much more
ref.name; // => 'refs/heads/master'
ref.target; // => Oid
ref.target.sha; // => '821ed6e80627b8769d170a293862f9fc60825226'

// Looking up object with oid
final oid = repo['821ed6e80627b8769d170a293862f9fc60825226']; // => Oid
final commit = Commit.lookup(repo: repo, oid: oid); // => Commit
commit.message; // => 'initial commit'

Writing to repository

// Suppose you created a new file named 'new.txt' in your freshly initialized
// repository and you want to commit it.

final index = repo.index; // => Index
index.add('new.txt');
index.write();
final tree = Tree.lookup(repo: repo, oid: index.writeTree()); // => Tree

Commit.create(
  repo: repo,
  updateRef: 'refs/heads/master',
  message: 'initial commit\n',
  author: repo.defaultSignature,
  committer: repo.defaultSignature,
  tree: tree,
  parents: [], // empty list for initial commit, 1 parent for regular and 2+ for merge commits
); // => Oid

Git Objects #

There are four kinds of base object types in Git: commits, trees, tags, and blobs. git2dart have a corresponding class for each of these object types.

Lookups of these objects requires Oid object, which can be instantiated from provided SHA-1 string in two ways:

// Using alias on repository object with SHA-1 string that can be any length
// between 4 and 40 characters
final oid = repo['821ed6e'];

// Using named constructor from Oid class (rules for SHA-1 string length is
// the same)
final oid = Oid.fromSHA(repo, '821ed6e');

Commit #

Commit lookup and some of the getters of the object:

final commit = Commit.lookup(repo: repo, oid: repo['821ed6e']); // => Commit

commit.message; // => 'initial commit\n'
commit.time; // => 1635869993 (seconds since epoch)
commit.author; // => Signature
commit.tree; // => Tree

Tree and TreeEntry #

Tree and TreeEntry lookup and some of their getters and methods:

final tree = Tree.lookup(repo: repo, oid: repo['a8ae3dd']); // => Tree

tree.entries; // => [TreeEntry, TreeEntry, ...]
tree.length; // => 3
tree.oid; // => Oid

// You can lookup single tree entry in the tree with index
final entry = tree[0]; // => TreeEntry

// You can lookup single tree entry in the tree with path to file
final entry = tree['some/file.txt']; // => TreeEntry

// Or you can lookup single tree entry in the tree with filename
final entry = tree['file.txt']; // => TreeEntry

entry.oid; // => Oid
entry.name // => 'file.txt'
entry.filemode // => GitFilemode.blob

You can also write trees with TreeBuilder:

final builder = TreeBuilder(repo: repo); // => TreeBuilder
builder.add(
  filename: 'file.txt',
  oid: index['file.txt'].oid,
  filemode: GitFilemode.blob,
);
final treeOid = builder.write(); // => Oid

// Perform commit using that tree in arguments
...

Tag #

Tag create and lookup methods and some of the object getters:

// Create annotated tag
final annotated = Tag.createAnnotated(
  repo: repo,
  tagName: 'v0.1',
  target: repo['821ed6e'],
  targetType: GitObject.commit,
  tagger: repo.defaultSignature,
  message: 'tag message',
); // => Oid

// Create lightweight tag
final lightweight = Tag.createLightweight(
  repo: repo,
  tagName: 'v0.1',
  target: repo['821ed6e'],
  targetType: GitObject.commit,
); // => Oid

// Lookup tag
final tag = Tag.lookup(repo: repo, oid: repo['f0fdbf5']); // => Tag

// Get list of all the tags names in repository
repo.tags; // => ['v0.1', 'v0.2']

tag.oid; // => Oid
tag.name; // => 'v0.1'

Blob #

Blob create and lookup methods and some of the object getters:

// Create a new blob from the file at provided path
final oid = Blob.createFromDisk(repo: repo, path: 'path/to/file.txt'); // => Oid

// Lookup blob
final blob = Blob.lookup(repo: repo, oid: repo['e69de29']); // => Blob

blob.oid; // => Oid
blob.content; // => 'content of the file'
blob.size; // => 19

Commit Walker #

There's two ways to traverse a set of commits. Through Repository object alias or by using RevWalk class for finer control:

// Traverse a set of commits starting at provided oid
final commits = repo.log(oid: repo['821ed6e']); // => [Commit, Commit, ...]

// Use RevWalk object to fine tune traversal
final walker = RevWalk(repo); // => RevWalk

// Set desired sorting (optional)
walker.sorting({GitSort.topological, GitSort.time});

// Push Oid for the starting point
walker.push(repo['821ed6e']);

// Hide commits if you are not interested in anything beneath them
walker.hide(repo['c68ff54']);

// Perform traversal
final commits = walker.walk(); // => [Commit, Commit, ...]

Index and IndexEntry #

Some methods and getters to inspect and manipulate the Git index ("staging area"):

// Initialize Index object
final index = repo.index; // => Index

// Get number of entries in index
index.length; // => 69

// Re-read the index from disk
index.read();

// Write an existing index object to disk
index.write();

// Iterate over index entries
for (final entry in index) {
  print(entry.path); // => 'path/to/file.txt'
}

// Get a specific entry
final entry = index['file.txt']; // => IndexEntry

// Stage using path to file or IndexEntry (updates existing entry if there is one)
index.add('new.txt');

// Unstage entry from index
index.remove('new.txt');

References and RefLog #

// Get names of all of the references that can be found in repository
final refs = repo.references; // => ['refs/heads/master', 'refs/tags/v0.1', ...]

// Lookup reference
final ref = Reference.lookup(repo: repo, name: 'refs/heads/master'); // => Reference

ref.type; // => ReferenceType.direct
ref.target; // => Oid
ref.name; // => 'refs/heads/master'

// Create reference
final ref = Reference.create(
  repo: repo,
  name: 'refs/heads/feature',
  target: repo['821ed6e'],
); // => Reference

// Update reference
ref.setTarget(repo['c68ff54']);

// Rename reference
Reference.rename(repo: repo, oldName: 'refs/heads/feature', newName: 'refs/heads/feature2');

// Delete reference
Reference.delete(repo: repo, name: 'refs/heads/feature2');

// Access the reflog
final reflog = ref.log; // => RefLog
final entry = reflog.first; // RefLogEntry

entry.message; // => 'commit (initial): init'
entry.committer; // => Signature

Branches #

// Get all the branches that can be found in repository
final branches = repo.branches; // => [Branch, Branch, ...]

// Get only local/remote branches
final local = repo.branchesLocal; // => [Branch, Branch, ...]
final remote = repo.branchesRemote; // => [Branch, Branch, ...]

// Lookup branch (lookups in local branches if no value for argument `type`
// is provided)
final branch = Branch.lookup(repo: repo, name: 'master'); // => Branch

branch.target; // => Oid
branch.isHead; // => true
branch.name; // => 'master'

// Create branch
Branch.create(repo: repo, name: 'feature', target: commit); // => Branch

// Rename branch
Branch.rename(repo: repo, oldName: 'feature', newName: 'feature2');

// Delete branch
Branch.delete(repo: repo, name: 'feature2');

Diff #

There is multiple ways to get the diff:

// Diff between index (staging area) and current working directory
final diff = Diff.indexToWorkdir(repo: repo, index: repo.index); // => Diff

// Diff between tree and index (staging area)
final diff = Diff.treeToIndex(repo: repo, tree: tree, index: repo.index); // => Diff

// Diff between tree and current working directory
final diff = Diff.treeToWorkdir(repo: repo, tree: tree); // => Diff

// Diff between tree and current working directory with index
final diff = Diff.treeToWorkdirWithIndex(repo: repo, tree: tree); // => Diff

// Diff between two tree objects
final diff = Diff.treeToTree(repo: repo, oldTree: tree1, newTree: tree2); // => Diff

// Diff between two index objects
final diff = Diff.indexToIndex(repo: repo, oldIndex: repo.index, newIndex: index); // => Diff

// Read the contents of a git patch file
final diff = Diff.parse(patch.text); // => Diff

Some methods for inspecting Diff object:

// Get the number of diff records
diff.length; // => 3

// Get the patch
diff.patch; // => 'diff --git a/modified_file b/modified_file ...'

// Get the DiffStats object of the diff
final stats = diff.stats; // => DiffStats
stats.insertions; // => 69
stats.deletions; // => 420
stats.filesChanged; // => 1

// Get the list of DiffDelta's containing file pairs with and old and new revisions
final deltas = diff.deltas; // => [DiffDelta, DiffDelta, ...]
final delta = deltas.first; // => DiffDelta
delta.status; // => GitDelta.modified
delta.oldFile; // => DiffFile
delta.newFile; // => DiffFile

Patch #

Some API methods to generate patch:

// Patch from difference between two blobs
final patch = Patch.fromBlobs(
  oldBlob: null, // empty blob
  newBlob: blob,
  newBlobPath: 'file.txt',
); // => Patch

// Patch from entry in the diff list at provided index position
final patch = Patch.fromDiff(diff: diff, index: 0); // => Patch

Some methods for inspecting Patch object:

// Get the content of a patch as a single diff text
patch.text; // => 'diff --git a/modified_file b/modified_file ...'

// Get the size of a patch diff data in bytes
patch.size(); // => 1337

// Get the list of hunks in a patch
patch.hunks; // => [DiffHunk, DiffHunk, ...]

Config files #

Some methods and getters of Config object:

// Open config file at provided path
final config = Config.open('path/to/config'); // => Config

// Open configuration file for repository
final config = repo.config; // => Config

// Get value of config variable
config['user.name'].value; // => 'Some Name'

// Set value of config variable
config['user.name'] = 'Another Name';

// Delete variable from the config
config.delete('user.name');

Checkout #

Perform different types of checkout:

// Update files in the index and the working directory to match the
// content of the commit pointed at by HEAD
Checkout.head(repo: repo);

// Update files in the working directory to match the content of the index
Checkout.index(repo: repo);

// Update files in the working directory to match the content of the tree
// pointed at by the reference target
Checkout.reference(repo: repo, name: 'refs/heads/master');

// Update files in the working directory to match the content of the tree
// pointed at by the commit
Checkout.commit(repo: repo, commit: commit);

// Perform checkout using various strategies
Checkout.head(repo: repo, strategy: {GitCheckout.force});

// Checkout only required files
Checkout.head(repo: repo, paths: ['some/file.txt']);

Merge #

Some API methods:

// Find a merge base between commits
final oid = Merge.base(
  repo: repo,
  commits: [commit1.oid, commit2.oid],
); // => Oid

// Merge commit into HEAD writing the results into the working directory
Merge.commit(repo: repo, commit: annotatedCommit);

// Cherry-pick the provided commit, producing changes in the index and
// working directory.
Merge.cherryPick(repo: repo, commit: commit);

Stashes #

// Get the list of all stashed states (first being the most recent)
repo.stashes; // => [Stash, Stash, ...]

// Save local modifications to a new stash
Stash.create(repo: repo, stasher: signature, message: 'WIP'); // => Oid

// Apply stash (defaults to last saved if index is not provided)
Stash.apply(repo: repo);

// Apply only specific paths from stash
Stash.apply(repo: repo, paths: ['file.txt']);

// Drop stash (defaults to last saved if index is not provided)
Stash.drop(repo: repo);

// Pop stash (apply and drop if successful, defaults to last saved
// if index is not provided)
Stash.pop(repo: repo);

Worktrees #

// Get list of names of linked worktrees
repo.worktrees; // => ['worktree1', 'worktree2'];

// Lookup existing worktree
Worktree.lookup(repo: repo, name: 'worktree1'); // => Worktree

// Create new worktree
final worktree = Worktree.create(
  repo: repo,
  name: 'worktree3',
  path: '/worktree3/path/',
); // => Worktree

// Get name of worktree
worktree.name; // => 'worktree3'

// Get path for the worktree
worktree.path; // => '/worktree3/path/';

// Lock and unlock worktree
worktree.lock();
worktree.unlock();

// Prune the worktree (remove the git data structures on disk)
worktree.prune();

Submodules #

Some API methods for submodule management:

// Get list with all tracked submodules paths
repo.submodules; // => ['Submodule1', 'Submodule2'];

// Lookup submodule
Submodule.lookup(repo: repo, name: 'Submodule'); // => Submodule

// Init and update
Submodule.init(repo: repo, name: 'Submodule');
Submodule.update(repo: repo, name: 'Submodule');

// Add submodule
Submodule.add(repo: repo, url: 'https://some.url', path: 'submodule'); // => Submodule

Some methods for inspecting Submodule object:

// Get name of the submodule
submodule.name; // => 'Submodule'

// Get path to the submodule
submodule.path; // => 'Submodule'

// Get URL for the submodule
submodule.url; // => 'https://some.url'

// Set URL for the submodule in the configuration
submodule.url = 'https://updated.url';
submodule.sync();

Remote #

Some API methods for remote management:

// Get list of all remotes
Remote.list(repo); // => ['origin', 'upstream', ...]

// Lookup remote
final remote = Remote.lookup(repo: repo, name: 'origin'); // => Remote
remote.name; // => 'origin'
remote.url; // => 'https://github.com/user/repo.git'

// Create remote
final remote = Remote.create(
  repo: repo,
  name: 'upstream',
  url: 'https://github.com/upstream/repo.git',
); // => Remote

// Delete remote
Remote.delete(repo: repo, name: 'upstream');

// Rename remote
Remote.rename(repo: repo, oldName: 'origin', newName: 'github');

// Fetch from remote
final remote = Remote.lookup(repo: repo, name: 'origin');
final stats = remote.fetch(
  callbacks: Callbacks(transferProgress: (stats) {
    print('Progress: ${stats.receivedObjects}/${stats.totalObjects}');
  }),
); // => TransferProgress

// Get remote references
final refs = remote.ls(); // => [RemoteReference, RemoteReference, ...]

Reset #

Some API methods for reset operations:

// Reset repository to specific commit with different reset types
// Hard reset - updates index and working directory
repo.reset(oid: repo['821ed6e'], resetType: GitReset.hard);

// Soft reset - only moves HEAD
repo.reset(oid: repo['821ed6e'], resetType: GitReset.soft);

// Mixed reset - updates index but not working directory
repo.reset(oid: repo['821ed6e'], resetType: GitReset.mixed);

// Reset specific paths in index to match commit
repo.resetDefault(oid: repo.head.target, pathspec: ['file.txt']);

Blame #

Show what revision and author last modified each line of a file:

// Get blame for file
final blame = Blame.file(
  repo: repo,
  path: 'path/to/file.txt',
); // => Blame

// Get blame hunk for specific line
final hunk = blame.forLine(5); // => BlameHunk
hunk.finalCommitOid; // => Oid
hunk.finalCommitter; // => Signature
hunk.originalPath; // => 'path/to/file.txt'

// Get blame with options
final blame = Blame.file(
  repo: repo,
  path: 'file.txt',
  newestCommit: repo['fc38877'],
  oldestCommit: repo['f17d0d4'],
  minLine: 1,
  maxLine: 10,
);

// Get blame for buffer
final blame = Blame.buffer(
  reference: existingBlame,
  buffer: 'new content',
);

Describe #

Generate human-readable name for any commit:

// Describe current working tree state
repo.describe(); // => 'v0.2-10-g821ed6e'

// Describe specific commit
repo.describe(
  commit: Commit.lookup(repo: repo, oid: repo['821ed6e']),
); // => 'v0.1-1-g821ed6e'

// Describe with options
repo.describe(
  describeStrategy: GitDescribeStrategy.tags, // only consider tags
  abbreviatedSize: 7, // length of abbreviated commit id
  alwaysUseLongFormat: true,
  dirtySuffix: '-dirty',
); // => 'v0.1-1-g821ed6e-dirty'

Note #

Add, remove and read notes attached to objects:

// Get list of all notes
final notes = Note.list(repo); // => [Note, Note, ...]

// Lookup note for object
final note = Note.lookup(
  repo: repo,
  annotatedOid: repo.head.target,
); // => Note
note.message; // => 'Note content\n'
note.oid; // => Oid

// Create note
final noteOid = Note.create(
  repo: repo,
  author: signature,
  committer: signature,
  annotatedOid: repo.head.target,
  note: 'New note content',
  force: true, // overwrite existing note
); // => Oid

// Delete note
Note.delete(
  repo: repo,
  annotatedOid: repo.head.target,
  author: signature,
  committer: signature,
);

Rebase #

Reapply commits on top of another base commit:

// Initialize rebase
final rebase = Rebase.init(
  repo: repo,
  branch: AnnotatedCommit.fromReference(repo: repo, reference: branchRef),
  onto: AnnotatedCommit.fromReference(repo: repo, reference: ontoRef),
);

// Get operations to be performed
final operations = rebase.operations; // => [RebaseOperation, ...]

// Perform rebase operations
for (final operation in operations) {
  // Apply next operation
  rebase.next();
  
  // Commit the changes
  rebase.commit(
    committer: signature,
    message: 'Rebased commit',
  );
}

// Finish rebase
rebase.finish();

// Or abort rebase
rebase.abort();

// Open existing rebase
final rebase = Rebase.open(repo);

Mailmap #

Map author/committer names and emails:

// Create empty mailmap
final mailmap = Mailmap.empty();

// Create from buffer
final mailmap = Mailmap.fromBuffer('''
Joe Developer <joe@example.com> <joe@old.com>
Jane Doe <jane@example.com> <jane.doe@old.com>
''');

// Create from repository
final mailmap = Mailmap.fromRepository(repo);

// Add entry
mailmap.addEntry(
  realName: 'Joe Developer',
  realEmail: 'joe@example.com',
  replaceName: 'joe',
  replaceEmail: 'joe@old.com',
);

// Resolve name and email
final resolved = mailmap.resolve(
  name: 'joe',
  email: 'joe@old.com',
); // => ['Joe Developer', 'joe@example.com']

// Resolve signature
final resolvedSig = mailmap.resolveSignature(signature);

Credentials #

Handle authentication for remote operations:

// Username/password credentials
const credentials = UserPass(
  username: 'user',
  password: 'password',
);

// SSH key from files
const credentials = Keypair(
  username: 'git',
  pubKey: 'path/to/id_rsa.pub',
  privateKey: 'path/to/id_rsa',
  passPhrase: 'key passphrase',
);

// SSH key from memory
final credentials = KeypairFromMemory(
  username: 'git',
  pubKey: publicKeyContent,
  privateKey: privateKeyContent,
  passPhrase: 'key passphrase',
);

// SSH key from agent
const credentials = KeypairFromAgent('git');

// Use credentials with clone/fetch/push
final repo = Repository.clone(
  url: 'ssh://git@github.com/user/repo.git',
  localPath: 'path/to/clone',
  callbacks: Callbacks(credentials: credentials),
);

ODB (Object Database) #

Direct access to Git object database:

// Get ODB from repository
final odb = repo.odb; // => Odb

// Check if object exists
odb.contains(oid); // => true/false

// Read object
final obj = odb.read(oid); // => OdbObject
obj.type; // => GitObject.blob
obj.data; // => 'content'
obj.size; // => 7

// Write object
final oid = odb.write(
  type: GitObject.blob,
  data: 'new content',
); // => Oid

// Get all objects
final objects = odb.objects; // => [Oid, Oid, ...]

// Add alternate ODB
odb.addDiskAlternate('path/to/alternate/objects');

Packbuilder #

Build pack files:

// Create packbuilder
final packbuilder = PackBuilder(repo);

// Add objects
packbuilder.add(oid);
packbuilder.addRecursively(commitOid);
packbuilder.addCommit(commitOid);
packbuilder.addTree(treeOid);

// Add objects from revwalk
final walker = RevWalk(repo);
walker.push(repo.head.target);
packbuilder.addWalk(walker);

// Write pack file
packbuilder.write('path/to/pack');

// Pack all objects in repository
final written = repo.pack(); // => number of objects written

// Pack with options
repo.pack(
  path: 'path/to/packdir',
  threads: 4,
  packDelegate: (builder) {
    // custom logic to add objects
    builder.addCommit(someOid);
  },
);

Signature #

Create and manage signatures for commits and tags:

// Create signature with current time
final sig = Signature.create(
  name: 'Author Name',
  email: 'author@example.com',
);

// Create signature with specific time
final sig = Signature.create(
  name: 'Author Name',
  email: 'author@example.com',
  time: 1234567890, // seconds since epoch
  offset: 120, // timezone offset in minutes
);

// Access signature properties
sig.name; // => 'Author Name'
sig.email; // => 'author@example.com'
sig.time; // => 1234567890
sig.offset; // => 120
sig.sign; // => '+0200'

RevParse #

Parse revision specifications:

// Parse single revision spec
final commit = RevParse.single(repo: repo, spec: 'HEAD') as Commit;
final tree = RevParse.single(repo: repo, spec: 'HEAD^{tree}') as Tree;
final blob = RevParse.single(repo: repo, spec: 'HEAD:README.md') as Blob;

// Parse extended revision spec (returns object and reference)
final result = RevParse.ext(repo: repo, spec: 'master');
result.object; // => Commit
result.reference; // => Reference

// Parse revision range
final range = RevParse.range(repo: repo, spec: 'HEAD~10..HEAD');
range.from; // => Commit
range.to; // => Commit
range.flags; // => {GitRevSpec.range}

// Parse merge base
final range = RevParse.range(repo: repo, spec: 'HEAD...feature');
range.flags; // => {GitRevSpec.range, GitRevSpec.mergeBase}

AnnotatedCommit #

Annotated commits carry additional information for merge/rebase operations:

// Create from oid
final annotated = AnnotatedCommit.lookup(repo: repo, oid: commitOid);

// Create from reference
final annotated = AnnotatedCommit.fromReference(
  repo: repo,
  reference: branchRef,
);

// Create from revision spec
final annotated = AnnotatedCommit.fromRevSpec(
  repo: repo,
  spec: '@{-1}', // previous branch
);

// Create from fetch head
final annotated = AnnotatedCommit.fromFetchHead(
  repo: repo,
  branchName: 'master',
  remoteUrl: 'https://github.com/user/repo.git',
  oid: commitOid,
);

// Access properties
annotated.oid; // => Oid
annotated.refName; // => 'refs/heads/master'

Contributing #

Fork git2dart, improve git2dart, send a pull request.


Development #

Troubleshooting #

Linux

If you are developing on Linux using non-Debian based distrib you might encounter these errors:

  • Failed to load dynamic library: libpcre.so.3: cannot open shared object file: No such file or directory
  • Failed to load dynamic library: libpcreposix.so.3: cannot open shared object file: No such file or directory

That happens because dynamic library is precompiled on Ubuntu and Arch/Fedora/RedHat names for those libraries are libpcre.so and libpcreposix.so.

To fix these errors create symlinks:

sudo ln -s /usr/lib64/libpcre.so /usr/lib64/libpcre.so.3
sudo ln -s /usr/lib64/libpcreposix.so /usr/lib64/libpcreposix.so.3

Running Tests #

To run all tests and generate coverage report make sure to have activated packages and lcov installed:

dart pub global activate coverage

And run:

./coverage.sh
open coverage/index.html

Licence #

MIT. See LICENSE file for more information.

9
likes
160
points
40
downloads

Publisher

verified publisherdartgit.dev

Weekly Downloads

Dart bindings to libgit2, provides ability to use libgit2 library in Dart and Flutter.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

equatable, ffi, flutter, git2dart_binaries, meta, path

More

Packages that depend on git2dart