summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2022-01-29 21:02:15 -0500
committerEdward Thomson <ethomson@edwardthomson.com>2022-01-30 09:27:29 -0500
commitc629d2a11cbc5863c4a68eaafa8bf6a99b263f26 (patch)
tree9d1bb823eb679ab9ce49eff5ed6b47764de46ff6
parent1458fb56efad36a5d231793b63b466d5a07a5488 (diff)
downloadlibgit2-c629d2a11cbc5863c4a68eaafa8bf6a99b263f26.tar.gz
merge: support zdiff3 conflict styles
-rw-r--r--include/git2/checkout.h5
-rw-r--r--include/git2/merge.h5
-rw-r--r--src/checkout.c5
-rw-r--r--src/merge_file.c2
-rw-r--r--tests/merge/conflict_data.h9
-rw-r--r--tests/merge/files.c39
-rw-r--r--tests/merge/workdir/simple.c78
7 files changed, 141 insertions, 2 deletions
diff --git a/include/git2/checkout.h b/include/git2/checkout.h
index f026d5bc2..9f834111a 100644
--- a/include/git2/checkout.h
+++ b/include/git2/checkout.h
@@ -182,7 +182,10 @@ typedef enum {
* notifications; don't update the working directory or index.
*/
GIT_CHECKOUT_DRY_RUN = (1u << 24),
-
+
+ /** Include common ancestor data in zdiff3 format for conflicts */
+ GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3 = (1u << 25),
+
/**
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
*/
diff --git a/include/git2/merge.h b/include/git2/merge.h
index 3b3132f26..edd090cff 100644
--- a/include/git2/merge.h
+++ b/include/git2/merge.h
@@ -159,7 +159,10 @@ typedef enum {
GIT_MERGE_FILE_DIFF_PATIENCE = (1 << 6),
/** Take extra time to find minimal diff */
- GIT_MERGE_FILE_DIFF_MINIMAL = (1 << 7)
+ GIT_MERGE_FILE_DIFF_MINIMAL = (1 << 7),
+
+ /** Create zdiff3 ("zealous diff3")-style files */
+ GIT_MERGE_FILE_STYLE_ZDIFF3 = (1 << 8)
} git_merge_file_flag_t;
#define GIT_MERGE_CONFLICT_MARKER_SIZE 7
diff --git a/src/checkout.c b/src/checkout.c
index bc3048cc8..6a4643196 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -2070,6 +2070,9 @@ static int checkout_write_merge(
if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)
opts.flags |= GIT_MERGE_FILE_STYLE_DIFF3;
+ if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3)
+ opts.flags |= GIT_MERGE_FILE_STYLE_ZDIFF3;
+
opts.ancestor_label = data->opts.ancestor_label ?
data->opts.ancestor_label : "ancestor";
opts.our_label = data->opts.our_label ?
@@ -2493,6 +2496,8 @@ static int checkout_data_init(
data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_MERGE;
else if (strcmp(conflict_style->value, "diff3") == 0)
data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3;
+ else if (strcmp(conflict_style->value, "zdiff3") == 0)
+ data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3;
else {
git_error_set(GIT_ERROR_CHECKOUT, "unknown style '%s' given for 'merge.conflictstyle'",
conflict_style->value);
diff --git a/src/merge_file.c b/src/merge_file.c
index 7285884b4..732a047b1 100644
--- a/src/merge_file.c
+++ b/src/merge_file.c
@@ -123,6 +123,8 @@ static int merge_file__xdiff(
if (options.flags & GIT_MERGE_FILE_STYLE_DIFF3)
xmparam.style = XDL_MERGE_DIFF3;
+ if (options.flags & GIT_MERGE_FILE_STYLE_ZDIFF3)
+ xmparam.style = XDL_MERGE_ZEALOUS_DIFF3;
if (options.flags & GIT_MERGE_FILE_IGNORE_WHITESPACE)
xmparam.xpp.flags |= XDF_IGNORE_WHITESPACE;
diff --git a/tests/merge/conflict_data.h b/tests/merge/conflict_data.h
index 27f19c1b0..0b1e7ee03 100644
--- a/tests/merge/conflict_data.h
+++ b/tests/merge/conflict_data.h
@@ -36,6 +36,15 @@
"this file is changed in branch and master\n" \
">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n"
+#define CONFLICTING_ZDIFF3_FILE \
+ "<<<<<<< HEAD\n" \
+ "this file is changed in master and branch\n" \
+ "||||||| initial\n" \
+ "this file is a conflict\n" \
+ "=======\n" \
+ "this file is changed in branch and master\n" \
+ ">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n"
+
#define CONFLICTING_UNION_FILE \
"this file is changed in master and branch\n" \
"this file is changed in branch and master\n"
diff --git a/tests/merge/files.c b/tests/merge/files.c
index fbc54e11e..6296f3b7b 100644
--- a/tests/merge/files.c
+++ b/tests/merge/files.c
@@ -424,3 +424,42 @@ void test_merge_files__crlf_conflict_markers_for_crlf_files(void)
cl_assert(memcmp(expected_diff3, result.ptr, expected_len) == 0);
git_merge_file_result_free(&result);
}
+
+void test_merge_files__conflicts_in_zdiff3(void)
+{
+ git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
+ ours = GIT_MERGE_FILE_INPUT_INIT,
+ theirs = GIT_MERGE_FILE_INPUT_INIT;
+ git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
+ git_merge_file_result result = {0};
+
+ const char *expected_zdiff3 =
+ "1,\nfoo,\nbar,\n" \
+ "<<<<<<< file.txt\n" \
+ "||||||| file.txt\n# add more here\n" \
+ "=======\nquux,\nwoot,\n" \
+ ">>>>>>> file.txt\nbaz,\n3,\n";
+ size_t expected_zdiff3_len = strlen(expected_zdiff3);
+
+ ancestor.ptr = "1,\n# add more here\n3,\n";
+ ancestor.size = strlen(ancestor.ptr);
+ ancestor.path = "file.txt";
+ ancestor.mode = 0100644;
+
+ ours.ptr = "1,\nfoo,\nbar,\nbaz,\n3,\n";
+ ours.size = strlen(ours.ptr);
+ ours.path = "file.txt";
+ ours.mode = 0100644;
+
+ theirs.ptr = "1,\nfoo,\nbar,\nquux,\nwoot,\nbaz,\n3,\n";
+ theirs.size = strlen(theirs.ptr);
+ theirs.path = "file.txt";
+ theirs.mode = 0100644;
+
+ opts.flags |= GIT_MERGE_FILE_STYLE_ZDIFF3;
+ cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, &opts));
+ cl_assert_equal_i(0, result.automergeable);
+ cl_assert_equal_i(expected_zdiff3_len, result.len);
+ cl_assert(memcmp(expected_zdiff3, result.ptr, expected_zdiff3_len) == 0);
+ git_merge_file_result_free(&result);
+}
diff --git a/tests/merge/workdir/simple.c b/tests/merge/workdir/simple.c
index f51ff09a7..0b672d6a0 100644
--- a/tests/merge/workdir/simple.c
+++ b/tests/merge/workdir/simple.c
@@ -323,6 +323,42 @@ void test_merge_workdir_simple__diff3(void)
cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 3));
}
+void test_merge_workdir_simple__zdiff3(void)
+{
+ git_str conflicting_buf = GIT_STR_INIT;
+
+ struct merge_index_entry merge_index_entries[] = {
+ ADDED_IN_MASTER_INDEX_ENTRY,
+ AUTOMERGEABLE_INDEX_ENTRY,
+ CHANGED_IN_BRANCH_INDEX_ENTRY,
+ CHANGED_IN_MASTER_INDEX_ENTRY,
+
+ { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 1, "conflicting.txt" },
+ { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 2, "conflicting.txt" },
+ { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 3, "conflicting.txt" },
+
+ UNCHANGED_INDEX_ENTRY,
+ };
+
+ struct merge_reuc_entry merge_reuc_entries[] = {
+ AUTOMERGEABLE_REUC_ENTRY,
+ REMOVED_IN_BRANCH_REUC_ENTRY,
+ REMOVED_IN_MASTER_REUC_ENTRY
+ };
+
+ set_core_autocrlf_to(repo, false);
+
+ merge_simple_branch(0, GIT_CHECKOUT_CONFLICT_STYLE_ZDIFF3);
+
+ cl_git_pass(git_futils_readbuffer(&conflicting_buf,
+ TEST_REPO_PATH "/conflicting.txt"));
+ cl_assert_equal_s(CONFLICTING_ZDIFF3_FILE, conflicting_buf.ptr);
+ git_str_dispose(&conflicting_buf);
+
+ cl_assert(merge_test_index(repo_index, merge_index_entries, 8));
+ cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 3));
+}
+
void test_merge_workdir_simple__union(void)
{
git_str conflicting_buf = GIT_STR_INIT;
@@ -436,6 +472,48 @@ void test_merge_workdir_simple__diff3_from_config(void)
git_config_free(config);
}
+void test_merge_workdir_simple__zdiff3_from_config(void)
+{
+ git_config *config;
+ git_str conflicting_buf = GIT_STR_INIT;
+
+ struct merge_index_entry merge_index_entries[] = {
+ ADDED_IN_MASTER_INDEX_ENTRY,
+ AUTOMERGEABLE_INDEX_ENTRY,
+ CHANGED_IN_BRANCH_INDEX_ENTRY,
+ CHANGED_IN_MASTER_INDEX_ENTRY,
+
+ { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 1, "conflicting.txt" },
+ { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 2, "conflicting.txt" },
+ { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 3, "conflicting.txt" },
+
+ UNCHANGED_INDEX_ENTRY,
+ };
+
+ struct merge_reuc_entry merge_reuc_entries[] = {
+ AUTOMERGEABLE_REUC_ENTRY,
+ REMOVED_IN_BRANCH_REUC_ENTRY,
+ REMOVED_IN_MASTER_REUC_ENTRY
+ };
+
+ cl_git_pass(git_repository_config(&config, repo));
+ cl_git_pass(git_config_set_string(config, "merge.conflictstyle", "zdiff3"));
+
+ set_core_autocrlf_to(repo, false);
+
+ merge_simple_branch(0, 0);
+
+ cl_git_pass(git_futils_readbuffer(&conflicting_buf,
+ TEST_REPO_PATH "/conflicting.txt"));
+ cl_assert(strcmp(conflicting_buf.ptr, CONFLICTING_ZDIFF3_FILE) == 0);
+ git_str_dispose(&conflicting_buf);
+
+ cl_assert(merge_test_index(repo_index, merge_index_entries, 8));
+ cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 3));
+
+ git_config_free(config);
+}
+
void test_merge_workdir_simple__merge_overrides_config(void)
{
git_config *config;