diff --git a/lib/src/bindings/reset.dart b/lib/src/bindings/reset.dart new file mode 100644 index 0000000..b5eb458 --- /dev/null +++ b/lib/src/bindings/reset.dart @@ -0,0 +1,29 @@ +import 'dart:ffi'; +import '../error.dart'; +import 'libgit2_bindings.dart'; +import '../util.dart'; + +/// Sets the current head to the specified commit oid and optionally resets the index +/// and working tree to match. +/// +/// SOFT reset means the Head will be moved to the commit. +/// +/// MIXED reset will trigger a SOFT reset, plus the index will be replaced with the +/// content of the commit tree. +/// +/// HARD reset will trigger a MIXED reset and the working directory will be replaced +/// with the content of the index. (Untracked and ignored files will be left alone, however.) +/// +/// Throws a [LibGit2Error] if error occured. +void reset( + Pointer repo, + Pointer target, + int resetType, + Pointer checkoutOpts, +) { + final error = libgit2.git_reset(repo, target, resetType, checkoutOpts); + + if (error < 0) { + throw LibGit2Error(libgit2.git_error_last()); + } +} diff --git a/lib/src/git_types.dart b/lib/src/git_types.dart index 5b78de3..d80604c 100644 --- a/lib/src/git_types.dart +++ b/lib/src/git_types.dart @@ -578,3 +578,26 @@ class GitCheckout { @override String toString() => 'GitCheckout.$_name'; } + +/// Kinds of reset operation. +class GitReset { + const GitReset._(this._value, this._name); + final int _value; + final String _name; + + /// Move the head to the given commit. + static const soft = GitReset._(1, 'soft'); + + /// [GitReset.soft] plus reset index to the commit. + static const mixed = GitReset._(2, 'mixed'); + + /// [GitReset.mixed] plus changes in working tree discarded. + static const hard = GitReset._(3, 'hard'); + + static const List values = [soft, mixed, hard]; + + int get value => _value; + + @override + String toString() => 'GitReset.$_name'; +} diff --git a/lib/src/repository.dart b/lib/src/repository.dart index 38c8ae6..07294b6 100644 --- a/lib/src/repository.dart +++ b/lib/src/repository.dart @@ -8,6 +8,7 @@ import 'bindings/object.dart' as object_bindings; import 'bindings/status.dart' as status_bindings; import 'bindings/commit.dart' as commit_bindings; import 'bindings/checkout.dart' as checkout_bindings; +import 'bindings/reset.dart' as reset_bindings; import 'branch.dart'; import 'commit.dart'; import 'config.dart'; @@ -705,4 +706,21 @@ class Repository { ref.free(); } } + + /// Sets the current head to the specified commit and optionally resets the index + /// and working tree to match. + /// + /// Throws a [LibGit2Error] if error occured. + void reset(String target, GitReset resetType) { + final oid = Oid.fromSHA(this, target); + final object = object_bindings.lookup( + _repoPointer, + oid.pointer, + GitObject.any.value, + ); + + reset_bindings.reset(_repoPointer, object, resetType.value, nullptr); + + object_bindings.free(object); + } } diff --git a/test/reset_test.dart b/test/reset_test.dart new file mode 100644 index 0000000..78422b2 --- /dev/null +++ b/test/reset_test.dart @@ -0,0 +1,57 @@ +import 'dart:io'; +import 'package:libgit2dart/src/git_types.dart'; +import 'package:test/test.dart'; +import 'package:libgit2dart/libgit2dart.dart'; +import 'helpers/util.dart'; + +void main() { + late Repository repo; + final tmpDir = '${Directory.systemTemp.path}/reset_testrepo/'; + const sha = '6cbc22e509d72758ab4c8d9f287ea846b90c448b'; + final file = File('${tmpDir}feature_file'); + + setUp(() async { + if (await Directory(tmpDir).exists()) { + await Directory(tmpDir).delete(recursive: true); + } + await copyRepo( + from: Directory('test/assets/testrepo/'), + to: await Directory(tmpDir).create(), + ); + repo = Repository.open(tmpDir); + }); + + tearDown(() async { + repo.free(); + await Directory(tmpDir).delete(recursive: true); + }); + + group('Reset', () { + test('successfully resets with hard', () { + var contents = file.readAsStringSync(); + expect(contents, 'Feature edit\n'); + + repo.reset(sha, GitReset.hard); + contents = file.readAsStringSync(); + expect(contents, isEmpty); + }); + + test('successfully resets with soft', () { + var contents = file.readAsStringSync(); + expect(contents, 'Feature edit\n'); + + repo.reset(sha, GitReset.soft); + contents = file.readAsStringSync(); + expect(contents, 'Feature edit\n'); + }); + + test('successfully resets with soft', () { + var contents = file.readAsStringSync(); + expect(contents, 'Feature edit\n'); + + repo.reset(sha, GitReset.mixed); + contents = file.readAsStringSync(); + expect(contents, 'Feature edit\n'); + }); + }); +}