diff options
| -rw-r--r-- | include/git2/diff.h | 88 | ||||
| -rw-r--r-- | src/diff.c | 204 | ||||
| -rw-r--r-- | src/diff.h | 3 | ||||
| -rw-r--r-- | tests/diff/format_email.c | 445 | 
4 files changed, 740 insertions, 0 deletions
diff --git a/include/git2/diff.h b/include/git2/diff.h index 571f0c887..a0cfbc918 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -1158,6 +1158,94 @@ GIT_EXTERN(int) git_diff_stats_to_buf(   */  GIT_EXTERN(void) git_diff_stats_free(git_diff_stats *stats); +/** + * Formatting options for diff e-mail generation + */ +typedef enum { +	/** Normal patch, the default */ +	GIT_DIFF_FORMAT_EMAIL_NONE = 0, + +	/** Don't insert "[PATCH]" in the subject header*/ +	GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER = (1 << 0), + +} git_diff_format_email_flags_t; + +/** + * Options for controlling the formatting of the generated e-mail. + */ +typedef struct { +	unsigned int version; + +	git_diff_format_email_flags_t flags; + +	/** This patch number */ +	size_t patch_no; + +	/** Total number of patches in this series */ +	size_t total_patches; + +	/** id to use for the commit */ +	const git_oid *id; + +	/** Summary of the change */ +	const char *summary; + +	/** Author of the change */ +	const git_signature *author; +} git_diff_format_email_options; + +#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION 1 +#define GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT {GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, 0, 1, 1, NULL, NULL, NULL} + +/** + * Create an e-mail ready patch from a diff. + * + * @param out buffer to store the e-mail patch in + * @param diff containing the commit + * @param opts structure with options to influence content and formatting. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_diff_format_email( +	git_buf *out, +	git_diff *diff, +	const git_diff_format_email_options *opts); + +/** + * Create an e-mail ready patch for a commit. + * + * Does not support creating patches for merge commits (yet). + * + * @param out buffer to store the e-mail patch in + * @param repo containing the commit + * @param commit pointer to up commit + * @param patch_no patch number of the commit + * @param total_patches total number of patches in the patch set + * @param flags determines the formatting of the e-mail + * @param diff_opts structure with options to influence diff or NULL for defaults. + * @return 0 or an error code + */ +GIT_EXTERN(int) git_diff_commit_as_email( +	git_buf *out, +	git_repository *repo, +	git_commit *commit, +	size_t patch_no, +	size_t total_patches, +	git_diff_format_email_flags_t flags, +	const git_diff_options *diff_opts); + +/** +* Initializes a `git_diff_format_email_options` with default values. Equivalent to +* creating an instance with GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT. +* +* @param opts the `git_diff_format_email_options` instance to initialize. +* @param version the version of the struct; you should pass +* `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION` here. +* @return Zero on success; -1 on failure. +*/ +GIT_EXTERN(int) git_diff_format_email_init_options( +	git_diff_format_email_options *opts, +	int version); +  GIT_END_DECL  /** @} */ diff --git a/src/diff.c b/src/diff.c index e62f45c22..ba3cd26b5 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1427,6 +1427,198 @@ int git_diff__paired_foreach(  	return error;  } +int git_diff__commit( +	git_diff **diff, +	git_repository *repo, +	const git_commit *commit, +	const git_diff_options *opts) +{ +	git_commit *parent = NULL; +	git_diff *commit_diff = NULL; +	git_tree *old_tree = NULL, *new_tree = NULL; +	size_t parents; +	int error = 0; + +	if ((parents = git_commit_parentcount(commit)) > 1) { +		char commit_oidstr[GIT_OID_HEXSZ + 1]; + +		error = -1; +		giterr_set(GITERR_INVALID, "Commit %s is a merge commit", +			git_oid_tostr(commit_oidstr, GIT_OID_HEXSZ + 1, git_commit_id(commit))); +		goto on_error; +	} + +	if (parents > 0) +		if ((error = git_commit_parent(&parent, commit, 0)) < 0 || +			(error = git_commit_tree(&old_tree, parent)) < 0) +				goto on_error; + +	if ((error = git_commit_tree(&new_tree, commit)) < 0 || +		(error = git_diff_tree_to_tree(&commit_diff, repo, old_tree, new_tree, opts)) < 0) +			goto on_error; + +	*diff = commit_diff; + +on_error: +	git_tree_free(new_tree); +	git_tree_free(old_tree); +	git_commit_free(parent); + +	return error; +} + +int git_diff_format_email__append_header_tobuf( +	git_buf *out, +	const git_oid *id, +	const git_signature *author, +	const char *summary, +	size_t patch_no, +	size_t total_patches, +	bool exclude_patchno_marker) +{ +	char idstr[GIT_OID_HEXSZ + 1]; +	char date_str[GIT_DATE_RFC2822_SZ]; +	int error = 0; + +	git_oid_fmt(idstr, id); +	idstr[GIT_OID_HEXSZ] = '\0'; + +	if ((error = git__date_rfc2822_fmt(date_str, sizeof(date_str), &author->when)) < 0) +		return error; + +	error = git_buf_printf(out, +				"From %s Mon Sep 17 00:00:00 2001\n" \ +				"From: %s <%s>\n" \ +				"Date: %s\n" \ +				"Subject: ", +				idstr, +				author->name, author->email, +				date_str); + +	if (error < 0) +		return error; + +	if (!exclude_patchno_marker) { +		if (total_patches == 1) { +			error = git_buf_puts(out, "[PATCH] "); +		} else { +			error = git_buf_printf(out, "[PATCH %"PRIuZ"/%"PRIuZ"] ", patch_no, total_patches); +		} + +		if (error < 0) +			return error; +	} + +	error = git_buf_printf(out, "%s\n\n", summary); + +	return error; +} + +int git_diff_format_email__append_patches_tobuf( +	git_buf *out, +	git_diff *diff) +{ +	size_t i, deltas; +	int error = 0; + +	deltas = git_diff_num_deltas(diff); + +	for (i = 0; i < deltas; ++i) { +		git_patch *patch = NULL; + +		if ((error = git_patch_from_diff(&patch, diff, i)) >= 0) +			error = git_patch_to_buf(out, patch); + +		git_patch_free(patch); + +		if (error < 0) +			break; +	} + +	return error; +} + +int git_diff_format_email( +	git_buf *out, +	git_diff *diff, +	const git_diff_format_email_options *opts) +{ +	git_diff_stats *stats = NULL; +	bool ignore_marker; +	unsigned int format_flags = 0; +	int error; + +	assert(out && diff && opts); +	assert(opts->summary && opts->id && opts->author); + +	GITERR_CHECK_VERSION(opts, GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION, "git_format_email_options"); + +	if ((ignore_marker = opts->flags & GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER) == false) { +		if (opts->patch_no > opts->total_patches) { +			giterr_set(GITERR_INVALID, "patch %"PRIuZ" out of range. max %"PRIuZ, opts->patch_no, opts->total_patches); +			return -1; +		} + +		if (opts->patch_no == 0) { +			giterr_set(GITERR_INVALID, "invalid patch no %"PRIuZ". should be >0", opts->patch_no); +			return -1; +		} +	} + +	error = git_diff_format_email__append_header_tobuf(out, +				opts->id, opts->author, opts->summary, +				opts->patch_no, opts->total_patches, ignore_marker); + +	if (error < 0) +		goto on_error; + +	format_flags = GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_INCLUDE_SUMMARY; + +	if ((error = git_buf_puts(out, "---\n")) < 0 || +		(error = git_diff_get_stats(&stats, diff)) < 0 || +		(error = git_diff_stats_to_buf(out, stats, format_flags)) < 0 || +		(error = git_diff_format_email__append_patches_tobuf(out, diff)) < 0) +			goto on_error; + +	error = git_buf_puts(out, "--\nlibgit2 " LIBGIT2_VERSION "\n\n"); + +on_error: +	git_diff_stats_free(stats); + +	return error; +} + +int git_diff_commit_as_email( +	git_buf *out, +	git_repository *repo, +	git_commit *commit, +	size_t patch_no, +	size_t total_patches, +	git_diff_format_email_flags_t flags, +	const git_diff_options *diff_opts) +{ +	git_diff *diff = NULL; +	git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; +	int error; + +	assert (out && repo && commit); + +	opts.flags = flags; +	opts.patch_no = patch_no; +	opts.total_patches = total_patches; +	opts.id = git_commit_id(commit); +	opts.summary = git_commit_summary(commit); +	opts.author = git_commit_author(commit); + +	if ((error = git_diff__commit(&diff, repo, commit, diff_opts)) < 0) +		return error; + +	error = git_diff_format_email(out, diff, &opts); + +	git_diff_free(diff); +	return error; +} +  int git_diff_init_options(git_diff_options* opts, int version)  {  	if (version != GIT_DIFF_OPTIONS_VERSION) { @@ -1450,3 +1642,15 @@ int git_diff_find_init_options(git_diff_find_options* opts, int version)  		return 0;  	}  } + +int git_diff_format_email_init_options(git_diff_format_email_options* opts, int version) +{ +	if (version != GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION) { +		giterr_set(GITERR_INVALID, "Invalid version %d for git_diff_format_email_options", version); +		return -1; +	} else { +		git_diff_format_email_options o = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; +		memcpy(opts, &o, sizeof(o)); +		return 0; +	} +} diff --git a/src/diff.h b/src/diff.h index c588f6301..aae8fbff1 100644 --- a/src/diff.h +++ b/src/diff.h @@ -116,6 +116,9 @@ extern void git_diff_find_similar__hashsig_free(void *sig, void *payload);  extern int git_diff_find_similar__calc_similarity(  	int *score, void *siga, void *sigb, void *payload); +extern int git_diff__commit( +	git_diff **diff, git_repository *repo, const git_commit *commit, const git_diff_options *opts); +  /*   * Sometimes a git_diff_file will have a zero size; this attempts to   * fill in the size without loading the blob if possible.  If that is diff --git a/tests/diff/format_email.c b/tests/diff/format_email.c new file mode 100644 index 000000000..ff0209e6f --- /dev/null +++ b/tests/diff/format_email.c @@ -0,0 +1,445 @@ +#include "clar.h" +#include "clar_libgit2.h" + +#include "buffer.h" +#include "commit.h" +#include "diff.h" + +static git_repository *repo; + +void test_diff_format_email__initialize(void) +{ +	repo = cl_git_sandbox_init("diff_format_email"); +} + +void test_diff_format_email__cleanup(void) +{ +	cl_git_sandbox_cleanup(); +} + +void test_diff_format_email__simple(void) +{ +	git_oid oid; +	git_commit *commit = NULL; +	git_diff *diff = NULL; +	git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; +	git_buf buf = GIT_BUF_INIT; + +	const char *email =  +	"From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \ +	"From: Jacques Germishuys <jacquesg@striata.com>\n" \ +	"Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \ +	"Subject: [PATCH] Modify some content\n" \ +	"\n" \ +	"---\n" \ +	" file1.txt | 8 +++++---\n" \ +	" 1 file changed, 5 insertions(+), 3 deletions(-)\n" \ +	"\n" \ +	"diff --git a/file1.txt b/file1.txt\n" \ +	"index 94aaae8..af8f41d 100644\n" \ +	"--- a/file1.txt\n" \ +	"+++ b/file1.txt\n" \ +	"@@ -1,15 +1,17 @@\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	"+_file1.txt_\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	"+\n" \ +	"+\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"+_file1.txt_\n" \ +	"+_file1.txt_\n" \ +	" file1.txt\n" \ +	"--\n" \ +	"libgit2 " LIBGIT2_VERSION "\n" \ +	"\n"; + +	git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); + +	cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + +	opts.id = git_commit_id(commit); +	opts.author = git_commit_author(commit); +	opts.summary = git_commit_summary(commit); + +	cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); +	cl_git_pass(git_diff_format_email(&buf, diff, &opts)); +	cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + +	git_buf_clear(&buf); +	cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, 0, NULL)); +	cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + +	git_diff_free(diff); +	git_commit_free(commit); +	git_buf_free(&buf); +} + +void test_diff_format_email__multiple(void) +{ +	git_oid oid; +	git_commit *commit = NULL; +	git_diff *diff = NULL; +	git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; +	git_buf buf = GIT_BUF_INIT; + +	const char *email =  +	"From 10808fe9c9be5a190c0ba68d1a002233fb363508 Mon Sep 17 00:00:00 2001\n" \ +	"From: Jacques Germishuys <jacquesg@striata.com>\n" \ +	"Date: Thu, 10 Apr 2014 19:37:05 +0200\n" \ +	"Subject: [PATCH 1/2] Added file2.txt file3.txt\n" \ +	"\n" \ +	"---\n" \ +	" file2.txt | 5 +++++\n" \ +	" file3.txt | 5 +++++\n" \ +	" 2 files changed, 10 insertions(+), 0 deletions(-)\n" \ +	" create mode 100644 file2.txt\n" \ +	" create mode 100644 file3.txt\n" \ +	"\n" \ +	"diff --git a/file2.txt b/file2.txt\n" \ +	"new file mode 100644\n" \ +	"index 0000000..e909123\n" \ +	"--- /dev/null\n" \ +	"+++ b/file2.txt\n" \ +	"@@ -0,0 +1,5 @@\n" \ +	"+file2\n" \ +	"+file2\n" \ +	"+file2\n" \ +	"+file2\n" \ +	"+file2\n" \ +	"diff --git a/file3.txt b/file3.txt\n" \ +	"new file mode 100644\n" \ +	"index 0000000..9435022\n" \ +	"--- /dev/null\n" \ +	"+++ b/file3.txt\n" \ +	"@@ -0,0 +1,5 @@\n" \ +	"+file3\n" \ +	"+file3\n" \ +	"+file3\n" \ +	"+file3\n" \ +	"+file3\n" \ +	"--\n" \ +	"libgit2 " LIBGIT2_VERSION "\n" \ +	"\n" \ +	"From 873806f6f27e631eb0b23e4b56bea2bfac14a373 Mon Sep 17 00:00:00 2001\n" \ +	"From: Jacques Germishuys <jacquesg@striata.com>\n" \ +	"Date: Thu, 10 Apr 2014 19:37:36 +0200\n" \ +	"Subject: [PATCH 2/2] Modified file2.txt, file3.txt\n" \ +	"\n" \ +	"---\n" \ +	" file2.txt | 2 +-\n" \ +	" file3.txt | 2 +-\n" \ +	" 2 files changed, 2 insertions(+), 2 deletions(-)\n" \ +	"\n" \ +	"diff --git a/file2.txt b/file2.txt\n" \ +	"index e909123..7aff11d 100644\n" \ +	"--- a/file2.txt\n" \ +	"+++ b/file2.txt\n" \ +	"@@ -1,5 +1,5 @@\n" \ +	" file2\n" \ +	" file2\n" \ +	" file2\n" \ +	"-file2\n" \ +	"+file2!\n" \ +	" file2\n" \ +	"diff --git a/file3.txt b/file3.txt\n" \ +	"index 9435022..9a2d780 100644\n" \ +	"--- a/file3.txt\n" \ +	"+++ b/file3.txt\n" \ +	"@@ -1,5 +1,5 @@\n" \ +	" file3\n" \ +	"-file3\n" \ +	"+file3!\n" \ +	" file3\n" \ +	" file3\n" \ +	" file3\n" \ +	"--\n" \ +	"libgit2 " LIBGIT2_VERSION "\n" \ +	"\n"; + +	git_oid_fromstr(&oid, "10808fe9c9be5a190c0ba68d1a002233fb363508"); +	cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + +	opts.id = git_commit_id(commit); +	opts.author = git_commit_author(commit); +	opts.summary = git_commit_summary(commit); +	opts.patch_no = 1; +	opts.total_patches = 2; + +	cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); +	cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + +	git_diff_free(diff); +	git_commit_free(commit); +	diff = NULL; +	commit = NULL; + +	git_oid_fromstr(&oid, "873806f6f27e631eb0b23e4b56bea2bfac14a373"); +	cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + +	opts.id = git_commit_id(commit); +	opts.author = git_commit_author(commit); +	opts.summary = git_commit_summary(commit); +	opts.patch_no = 2; +	opts.total_patches = 2; + +	cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); +	cl_git_pass(git_diff_format_email(&buf, diff, &opts)); + +	cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + +	git_diff_free(diff); +	git_commit_free(commit); +	git_buf_free(&buf); +} + +void test_diff_format_email__exclude_marker(void) +{ +	git_oid oid; +	git_commit *commit = NULL; +	git_diff *diff = NULL; +	git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; +	git_buf buf = GIT_BUF_INIT; + +	const char *email =  +	"From 9264b96c6d104d0e07ae33d3007b6a48246c6f92 Mon Sep 17 00:00:00 2001\n" \ +	"From: Jacques Germishuys <jacquesg@striata.com>\n" \ +	"Date: Wed, 9 Apr 2014 20:57:01 +0200\n" \ +	"Subject: Modify some content\n" \ +	"\n" \ +	"---\n" \ +	" file1.txt | 8 +++++---\n" \ +	" 1 file changed, 5 insertions(+), 3 deletions(-)\n" \ +	"\n" \ +	"diff --git a/file1.txt b/file1.txt\n" \ +	"index 94aaae8..af8f41d 100644\n" \ +	"--- a/file1.txt\n" \ +	"+++ b/file1.txt\n" \ +	"@@ -1,15 +1,17 @@\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	"+_file1.txt_\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	"+\n" \ +	"+\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	" file1.txt\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"+_file1.txt_\n" \ +	"+_file1.txt_\n" \ +	" file1.txt\n" \ +	"--\n" \ +	"libgit2 " LIBGIT2_VERSION "\n" \ +	"\n"; + +	git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); +	cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + +	opts.id = git_commit_id(commit); +	opts.author = git_commit_author(commit); +	opts.summary = git_commit_summary(commit); + +	opts.flags |= GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER; + +	cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); +	cl_git_pass(git_diff_format_email(&buf, diff, &opts)); +	cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + +	git_buf_clear(&buf); +	cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, +		GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER, NULL)); +	cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + +	git_diff_free(diff); +	git_commit_free(commit); +	git_buf_free(&buf); +} + +void test_diff_format_email__invalid_no(void) +{ +	git_oid oid; +	git_commit *commit = NULL; +	git_diff *diff = NULL; +	git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; +	git_buf buf = GIT_BUF_INIT; + +	git_oid_fromstr(&oid, "9264b96c6d104d0e07ae33d3007b6a48246c6f92"); + +	cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + +	opts.id = git_commit_id(commit); +	opts.author = git_commit_author(commit); +	opts.summary = git_commit_summary(commit); +	opts.patch_no = 2; +	opts.total_patches = 1; + +	cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); +	cl_git_fail(git_diff_format_email(&buf, diff, &opts)); +	cl_git_fail(git_diff_commit_as_email(&buf, repo, commit, 2, 1, 0, NULL)); +	cl_git_fail(git_diff_commit_as_email(&buf, repo, commit, 0, 0, 0, NULL)); + +	git_diff_free(diff); +	git_commit_free(commit); +	git_buf_free(&buf); +} + +void test_diff_format_email__mode_change(void) +{ +	git_oid oid; +	git_commit *commit = NULL; +	git_diff *diff = NULL; +	git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; +	git_buf buf = GIT_BUF_INIT; + +	const char *email =  +	"From 7ade76dd34bba4733cf9878079f9fd4a456a9189 Mon Sep 17 00:00:00 2001\n" \ +	"From: Jacques Germishuys <jacquesg@striata.com>\n" \ +	"Date: Thu, 10 Apr 2014 10:05:03 +0200\n" \ +	"Subject: [PATCH] Update permissions\n" \ +	"\n" \ +	"---\n" \ +	" file1.txt.renamed | 0\n" \ +	" 1 file changed, 0 insertions(+), 0 deletions(-)\n" \ +	" mode change 100644 => 100755 file1.txt.renamed\n" \ +	"\n" \ +	"diff --git a/file1.txt.renamed b/file1.txt.renamed\n" \ +	"old mode 100644\n" \ +	"new mode 100755\n" \ +	"index a97157a..a97157a\n" \ +	"--- a/file1.txt.renamed\n" \ +	"+++ b/file1.txt.renamed\n" \ +	"--\n" \ +	"libgit2 " LIBGIT2_VERSION "\n" \ +	"\n"; + +	git_oid_fromstr(&oid, "7ade76dd34bba4733cf9878079f9fd4a456a9189"); + +	cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + +	opts.id = git_commit_id(commit); +	opts.author = git_commit_author(commit); +	opts.summary = git_commit_summary(commit); + +	cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); +	cl_git_pass(git_diff_format_email(&buf, diff, &opts)); +	cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + +	git_buf_clear(&buf); +	cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, 0, NULL)); +	cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + +	git_diff_free(diff); +	git_commit_free(commit); +	git_buf_free(&buf); +} + +void test_diff_format_email__rename_add_remove(void) +{ +	git_oid oid; +	git_commit *commit = NULL; +	git_diff *diff = NULL; +	git_diff_format_email_options opts = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT; +	git_buf buf = GIT_BUF_INIT; + +	const char *email =  +	"From 6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d Mon Sep 17 00:00:00 2001\n" \ +	"From: Jacques Germishuys <jacquesg@striata.com>\n" \ +	"Date: Wed, 9 Apr 2014 21:15:56 +0200\n" \ +	"Subject: [PATCH] Renamed file1.txt -> file1.txt.renamed\n" \ +	"\n" \ +	"---\n" \ +	" file1.txt         | 17 -----------------\n" \ +	" file1.txt.renamed | 17 +++++++++++++++++\n" \ +	" 2 files changed, 17 insertions(+), 17 deletions(-)\n" \ +	" delete mode 100644 file1.txt\n" \ +	" create mode 100644 file1.txt.renamed\n" \ +	"\n" \ +	"diff --git a/file1.txt b/file1.txt\n" \ +	"deleted file mode 100644\n" \ +	"index af8f41d..0000000\n" \ +	"--- a/file1.txt\n" \ +	"+++ /dev/null\n" \ +	"@@ -1,17 +0,0 @@\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-_file1.txt_\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-\n" \ +	"-\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-file1.txt\n" \ +	"-_file1.txt_\n" \ +	"-_file1.txt_\n" \ +	"-file1.txt\n" \ +	"diff --git a/file1.txt.renamed b/file1.txt.renamed\n" \ +	"new file mode 100644\n" \ +	"index 0000000..a97157a\n" \ +	"--- /dev/null\n" \ +	"+++ b/file1.txt.renamed\n" \ +	"@@ -0,0 +1,17 @@\n" \ +	"+file1.txt\n" \ +	"+file1.txt\n" \ +	"+_file1.txt_\n" \ +	"+file1.txt\n" \ +	"+file1.txt\n" \ +	"+file1.txt_renamed\n" \ +	"+file1.txt\n" \ +	"+\n" \ +	"+\n" \ +	"+file1.txt\n" \ +	"+file1.txt\n" \ +	"+file1.txt_renamed\n" \ +	"+file1.txt\n" \ +	"+file1.txt\n" \ +	"+_file1.txt_\n" \ +	"+_file1.txt_\n" \ +	"+file1.txt\n" \ +	"--\n" \ +	"libgit2 " LIBGIT2_VERSION "\n" \ +	"\n"; + +	git_oid_fromstr(&oid, "6e05acc5a5dab507d91a0a0cc0fb05a3dd98892d"); + +	cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + +	opts.id = git_commit_id(commit); +	opts.author = git_commit_author(commit); +	opts.summary = git_commit_summary(commit); + +	cl_git_pass(git_diff__commit(&diff, repo, commit, NULL)); +	cl_git_pass(git_diff_format_email(&buf, diff, &opts)); +	cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + +	git_buf_clear(&buf); +	cl_git_pass(git_diff_commit_as_email(&buf, repo, commit, 1, 1, 0, NULL)); +	cl_assert(strcmp(git_buf_cstr(&buf), email) == 0); + +	git_diff_free(diff); +	git_commit_free(commit); +	git_buf_free(&buf); +} +  | 
