Commit ccef5adb63bdba7f5182aec9f0bdc83a2887d9d1

Pierre-Olivier Latour 2015-06-30T09:30:20

Added git_diff_index_to_index()

diff --git a/include/git2/diff.h b/include/git2/diff.h
index b3ab539..0abbc7f 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -836,6 +836,25 @@ GIT_EXTERN(int) git_diff_tree_to_workdir_with_index(
 	const git_diff_options *opts); /**< can be NULL for defaults */
 
 /**
+ * Create a diff with the difference between two index objects.
+ *
+ * The first index will be used for the "old_file" side of the delta and the
+ * second index will be used for the "new_file" side of the delta.
+ *
+ * @param diff Output pointer to a git_diff pointer to be allocated.
+ * @param repo The repository containing the indexes.
+ * @param old_index A git_index object to diff from.
+ * @param new_index A git_index object to diff to.
+ * @param opts Structure with options to influence diff or NULL for defaults.
+ */
+GIT_EXTERN(int) git_diff_index_to_index(
+	git_diff **diff,
+	git_repository *repo,
+	git_index *old_index,
+	git_index *new_index,
+	const git_diff_options *opts); /**< can be NULL for defaults */
+
+/**
  * Merge one diff into another.
  *
  * This merges items from the "from" list into the "onto" list.  The
diff --git a/src/diff.c b/src/diff.c
index c1adcc6..44f6278 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1421,6 +1421,31 @@ int git_diff_tree_to_workdir_with_index(
 	return error;
 }
 
+int git_diff_index_to_index(
+	git_diff **diff,
+	git_repository *repo,
+	git_index *old_index,
+	git_index *new_index,
+	const git_diff_options *opts)
+{
+	int error = 0;
+
+	assert(diff && old_index && new_index);
+
+	DIFF_FROM_ITERATORS(
+		git_iterator_for_index(
+			&a, old_index, GIT_ITERATOR_DONT_IGNORE_CASE, pfx, pfx),
+		git_iterator_for_index(
+			&b, new_index, GIT_ITERATOR_DONT_IGNORE_CASE, pfx, pfx)
+	);
+
+	/* if index is in case-insensitive order, re-sort deltas to match */
+	if (!error && (old_index->ignore_case || new_index->ignore_case))
+		diff_set_ignore_case(*diff, true);
+
+	return error;
+}
+
 size_t git_diff_num_deltas(const git_diff *diff)
 {
 	assert(diff);
diff --git a/tests/diff/index.c b/tests/diff/index.c
index f702568..df45ad2 100644
--- a/tests/diff/index.c
+++ b/tests/diff/index.c
@@ -268,3 +268,35 @@ void test_diff_index__not_in_head_conflicted(void)
 	git_index_free(index);
 	git_tree_free(a);
 }
+
+void test_diff_index__to_index(void)
+{
+	const char *a_commit = "26a125ee1bf"; /* the current HEAD */
+	git_tree *old_tree;
+	git_index *old_index;
+	git_index *new_index;
+	git_diff *diff;
+	diff_expects exp;
+
+	cl_git_pass(git_index_new(&old_index));
+	old_tree = resolve_commit_oid_to_tree(g_repo, a_commit);
+	cl_git_pass(git_index_read_tree(old_index, old_tree));
+
+	cl_git_pass(git_repository_index(&new_index, g_repo));
+
+	cl_git_pass(git_diff_index_to_index(&diff, g_repo, old_index, new_index, NULL));
+
+	memset(&exp, 0, sizeof(diff_expects));
+	cl_git_pass(git_diff_foreach(
+		diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp));
+	cl_assert_equal_i(8, exp.files);
+	cl_assert_equal_i(3, exp.file_status[GIT_DELTA_ADDED]);
+	cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]);
+	cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]);
+	cl_assert_equal_i(0, exp.file_status[GIT_DELTA_CONFLICTED]);
+
+	git_diff_free(diff);
+	git_index_free(new_index);
+	git_index_free(old_index);
+	git_tree_free(old_tree);
+}