Commit c0c8570c5104a3047564fd5a1cfe1cacb0ed935d

Edward Thomson 2014-10-13T16:51:40

Merge pull request #2616 from ethomson/index_crlf Apply filters when writing index

diff --git a/src/checkout.c b/src/checkout.c
index f25a6ef..8aaf8c5 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -1761,10 +1761,12 @@ static int checkout_write_merge(
 	checkout_conflictdata *conflict)
 {
 	git_buf our_label = GIT_BUF_INIT, their_label = GIT_BUF_INIT,
-		path_suffixed = GIT_BUF_INIT, path_workdir = GIT_BUF_INIT;
+		path_suffixed = GIT_BUF_INIT, path_workdir = GIT_BUF_INIT,
+		in_data = GIT_BUF_INIT, out_data = GIT_BUF_INIT;
 	git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
 	git_merge_file_result result = {0};
 	git_filebuf output = GIT_FILEBUF_INIT;
+	git_filter_list *fl = NULL;
 	int error = 0;
 
 	if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)
@@ -1810,13 +1812,29 @@ static int checkout_write_merge(
 		(error = checkout_safe_for_update_only(git_buf_cstr(&path_workdir), result.mode)) <= 0)
 		goto done;
 
+	if (!data->opts.disable_filters) {
+		in_data.ptr = (char *)result.ptr;
+		in_data.size = result.len;
+
+		if ((error = git_filter_list_load(&fl, data->repo, NULL, git_buf_cstr(&path_workdir),
+				GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT)) < 0 ||
+			(error = git_filter_list_apply_to_data(&out_data, fl, &in_data)) < 0)
+			goto done;
+	} else {
+		out_data.ptr = (char *)result.ptr;
+		out_data.size = result.len;
+	}
+
 	if ((error = git_futils_mkpath2file(path_workdir.ptr, 0755)) < 0 ||
-		(error = git_filebuf_open(&output, path_workdir.ptr, GIT_FILEBUF_DO_NOT_BUFFER, result.mode)) < 0 ||
-		(error = git_filebuf_write(&output, result.ptr, result.len)) < 0 ||
+		(error = git_filebuf_open(&output, git_buf_cstr(&path_workdir), GIT_FILEBUF_DO_NOT_BUFFER, result.mode)) < 0 ||
+		(error = git_filebuf_write(&output, out_data.ptr, out_data.size)) < 0 ||
 		(error = git_filebuf_commit(&output)) < 0)
 		goto done;
 
 done:
+	git_filter_list_free(fl);
+
+	git_buf_free(&out_data);
 	git_buf_free(&our_label);
 	git_buf_free(&their_label);
 
diff --git a/tests/checkout/index.c b/tests/checkout/index.c
index 7f641b3..3c01e24 100644
--- a/tests/checkout/index.c
+++ b/tests/checkout/index.c
@@ -618,3 +618,72 @@ void test_checkout_index__can_get_repo_from_index(void)
 
 	git_index_free(index);
 }
+
+static void add_conflict(void)
+{
+	git_index *index;
+	git_index_entry entry;
+
+	memset(&entry, 0, sizeof(git_index_entry));
+
+	cl_git_pass(git_repository_index(&index, g_repo));
+
+	entry.mode = 0100644;
+	entry.path = "conflicting.txt";
+
+	git_oid_fromstr(&entry.id, "d427e0b2e138501a3d15cc376077a3631e15bd46");
+	entry.flags = (1 << GIT_IDXENTRY_STAGESHIFT);
+	cl_git_pass(git_index_add(index, &entry));
+
+	git_oid_fromstr(&entry.id, "4e886e602529caa9ab11d71f86634bd1b6e0de10");
+	entry.flags = (2 << GIT_IDXENTRY_STAGESHIFT);
+	cl_git_pass(git_index_add(index, &entry));
+
+	git_oid_fromstr(&entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863");
+	entry.flags = (3 << GIT_IDXENTRY_STAGESHIFT);
+	cl_git_pass(git_index_add(index, &entry));
+
+	cl_git_pass(git_index_write(index));
+	git_index_free(index);
+}
+
+void test_checkout_index__writes_conflict_file(void)
+{
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_buf conflicting_buf = GIT_BUF_INIT;
+
+	add_conflict();
+	cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
+
+	cl_git_pass(git_futils_readbuffer(&conflicting_buf, "testrepo/conflicting.txt"));
+	cl_assert(strcmp(conflicting_buf.ptr,
+		"<<<<<<< ours\n"
+		"this file is changed in master and branch\n"
+		"=======\n"
+		"this file is changed in branch and master\n"
+		">>>>>>> theirs\n") == 0);
+	git_buf_free(&conflicting_buf);
+}
+
+void test_checkout_index__conflicts_honor_coreautocrlf(void)
+{
+#ifdef GIT_WIN32
+	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
+	git_buf conflicting_buf = GIT_BUF_INIT;
+
+	cl_git_pass(p_unlink("./testrepo/.gitattributes"));
+	cl_repo_set_bool(g_repo, "core.autocrlf", true);
+
+	add_conflict();
+	cl_git_pass(git_checkout_index(g_repo, NULL, &opts));
+
+	cl_git_pass(git_futils_readbuffer(&conflicting_buf, "testrepo/conflicting.txt"));
+	cl_assert(strcmp(conflicting_buf.ptr,
+		"<<<<<<< ours\r\n"
+		"this file is changed in master and branch\r\n"
+		"=======\r\n"
+		"this file is changed in branch and master\r\n"
+		">>>>>>> theirs\r\n") == 0);
+	git_buf_free(&conflicting_buf);
+#endif
+}
diff --git a/tests/resources/testrepo/.gitted/objects/2b/d0a343aeef7a2cf0d158478966a6e587ff3863 b/tests/resources/testrepo/.gitted/objects/2b/d0a343aeef7a2cf0d158478966a6e587ff3863
new file mode 100644
index 0000000..d10ca63
Binary files /dev/null and b/tests/resources/testrepo/.gitted/objects/2b/d0a343aeef7a2cf0d158478966a6e587ff3863 differ
diff --git a/tests/resources/testrepo/.gitted/objects/4e/886e602529caa9ab11d71f86634bd1b6e0de10 b/tests/resources/testrepo/.gitted/objects/4e/886e602529caa9ab11d71f86634bd1b6e0de10
new file mode 100644
index 0000000..53168a0
Binary files /dev/null and b/tests/resources/testrepo/.gitted/objects/4e/886e602529caa9ab11d71f86634bd1b6e0de10 differ
diff --git a/tests/resources/testrepo/.gitted/objects/d4/27e0b2e138501a3d15cc376077a3631e15bd46 b/tests/resources/testrepo/.gitted/objects/d4/27e0b2e138501a3d15cc376077a3631e15bd46
new file mode 100644
index 0000000..0b3611a
Binary files /dev/null and b/tests/resources/testrepo/.gitted/objects/d4/27e0b2e138501a3d15cc376077a3631e15bd46 differ