From 25203c7f9f6a7eb39fa557cbf5c913cc902fa756 Mon Sep 17 00:00:00 2001 From: Aleksey Kulikov Date: Tue, 21 Dec 2021 12:27:45 +0300 Subject: [PATCH] feat(diff): add binding and API method for git_diff_tree_to_workdir_with_index --- lib/src/bindings/diff.dart | 38 ++++++++++++++++++++++++++++++++++++++ lib/src/diff.dart | 38 ++++++++++++++++++++++++++++++++++++++ test/diff_test.dart | 31 +++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/lib/src/bindings/diff.dart b/lib/src/bindings/diff.dart index 1bd3bbe..282be76 100644 --- a/lib/src/bindings/diff.dart +++ b/lib/src/bindings/diff.dart @@ -89,6 +89,44 @@ Pointer treeToWorkdir({ return out.value; } +/// Create a diff between a tree and the working directory using index data to +/// account for staged deletes, tracked files, etc. +/// +/// This emulates `git diff ` by diffing the tree to the index and the +/// index to the working directory and blending the results into a single diff +/// that includes staged deleted, etc. +/// +/// Throws a [LibGit2Error] if error occured. +Pointer treeToWorkdirWithIndex({ + required Pointer repoPointer, + required Pointer? treePointer, + required int flags, + required int contextLines, + required int interhunkLines, +}) { + final out = calloc>(); + final opts = _diffOptionsInit( + flags: flags, + contextLines: contextLines, + interhunkLines: interhunkLines, + ); + + final error = libgit2.git_diff_tree_to_workdir_with_index( + out, + repoPointer, + treePointer ?? nullptr, + opts, + ); + + if (error < 0) { + throw LibGit2Error(libgit2.git_error_last()); + } + + calloc.free(opts); + + return out.value; +} + /// Create a diff with the difference between two tree objects. /// /// Throws a [LibGit2Error] if error occured. diff --git a/lib/src/diff.dart b/lib/src/diff.dart index 7ddf1be..ea23180 100644 --- a/lib/src/diff.dart +++ b/lib/src/diff.dart @@ -14,6 +14,44 @@ class Diff { /// **IMPORTANT**: Should be freed to release allocated memory. Diff(this._diffPointer); + /// Creates a diff between a [tree] and the working directory using index + /// data to account for staged deletes, tracked files, etc. + /// + /// This emulates `git diff ` by diffing the tree to the index and the + /// index to the working directory and blending the results into a single diff + /// that includes staged deleted, etc. + /// + /// [repo] is the repository containing the tree. + /// + /// [tree] is a [Tree] object to diff from, or null for empty tree. + /// + /// [flags] is a combination of [GitDiff] flags. Defaults to [GitDiff.normal]. + /// + /// [contextLines] is the number of unchanged lines that define the boundary + /// of a hunk (and to display before and after). Defaults to 3. + /// + /// [interhunkLines] is the maximum number of unchanged lines between hunk + /// boundaries before the hunks will be merged into one. Defaults to 0. + /// + /// **IMPORTANT**: Should be freed to release allocated memory. + /// + /// Throws a [LibGit2Error] if error occured. + Diff.treeToWorkdirWithIndex({ + required Repository repo, + required Tree? tree, + Set flags = const {GitDiff.normal}, + int contextLines = 3, + int interhunkLines = 0, + }) { + _diffPointer = bindings.treeToWorkdirWithIndex( + repoPointer: repo.pointer, + treePointer: tree?.pointer, + flags: flags.fold(0, (acc, e) => acc | e.value), + contextLines: contextLines, + interhunkLines: interhunkLines, + ); + } + /// Reads the [content]s of a git patch file into a git diff object. /// /// The diff object produced is similar to the one that would be produced if diff --git a/test/diff_test.dart b/test/diff_test.dart index 24eadcb..2e2e004 100644 --- a/test/diff_test.dart +++ b/test/diff_test.dart @@ -56,6 +56,20 @@ void main() { 'subdir/modified_file', ]; + const treeToWorkdirWithIndex = [ + 'file_deleted', + 'modified_file', + 'staged_changes', + 'staged_changes_file_deleted', + 'staged_changes_file_modified', + 'staged_delete', + 'staged_delete_file_modified', + 'staged_new', + 'staged_new_file_modified', + 'subdir/deleted_file', + 'subdir/modified_file', + ]; + const patchText = """ diff --git a/subdir/modified_file b/subdir/modified_file index e69de29..c217c63 100644 @@ -205,6 +219,23 @@ index e69de29..c217c63 100644 tree.free(); }); + test('returns diff between tree and workdir with index', () { + final head = repo.head; + final commit = repo.lookupCommit(head.target); + final tree = commit.tree; + + final diff = Diff.treeToWorkdirWithIndex(repo: repo, tree: tree); + expect(diff.length, 11); + for (var i = 0; i < diff.deltas.length; i++) { + expect(diff.deltas[i].newFile.path, treeToWorkdirWithIndex[i]); + } + + diff.free(); + tree.free(); + commit.free(); + head.free(); + }); + test('successfully merges diffs', () { final head = repo.head; final commit = repo.lookupCommit(head.target);