mirror of
https://github.com/libgit2/libgit2.git
synced 2026-01-25 11:06:32 +00:00
merge: support zdiff3 conflict styles
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user