mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 20:42:23 +00:00
merge_file should use more aggressive levels
The default merge_file level was XDL_MERGE_MINIMAL, which will produce conflicts where there should not be in the case where both sides were changed identically. Change the defaults to be more aggressive (XDL_MERGE_ZEALOUS) which will more aggressively compress non-conflicts. This matches git.git's defaults. Increase testing around reverting a previously reverted commit to illustrate this problem.
This commit is contained in:
parent
e49c98e6ef
commit
c1d648c5c6
@ -32,14 +32,21 @@ typedef enum {
|
|||||||
} git_merge_tree_flag_t;
|
} git_merge_tree_flag_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automerge options for `git_merge_trees_opts`.
|
* Merge file options for `git_merge_trees_opts`.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GIT_MERGE_AUTOMERGE_NORMAL = 0,
|
/* Produce a conflict in a file when two similar regions are changed. */
|
||||||
GIT_MERGE_AUTOMERGE_NONE = 1,
|
GIT_MERGE_FILE_FAVOR_NORMAL = 0,
|
||||||
GIT_MERGE_AUTOMERGE_FAVOR_OURS = 2,
|
|
||||||
GIT_MERGE_AUTOMERGE_FAVOR_THEIRS = 3,
|
/* Do not attempt to produce an automerged file during tree merge. */
|
||||||
} git_merge_automerge_flags;
|
GIT_MERGE_FILE_FAVOR_NO_MERGE = 1,
|
||||||
|
|
||||||
|
/* Produce a file containing the "ours" side of conflicting regions. */
|
||||||
|
GIT_MERGE_FILE_FAVOR_OURS = 2,
|
||||||
|
|
||||||
|
/* Produce a file containing the "theirs" side of conflicting regions. */
|
||||||
|
GIT_MERGE_FILE_FAVOR_THEIRS = 3,
|
||||||
|
} git_merge_file_favor_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -58,7 +65,7 @@ typedef struct {
|
|||||||
git_diff_similarity_metric *metric;
|
git_diff_similarity_metric *metric;
|
||||||
|
|
||||||
/** Flags for automerging content. */
|
/** Flags for automerging content. */
|
||||||
git_merge_automerge_flags automerge_flags;
|
git_merge_file_favor_t file_favor;
|
||||||
} git_merge_tree_opts;
|
} git_merge_tree_opts;
|
||||||
|
|
||||||
#define GIT_MERGE_TREE_OPTS_VERSION 1
|
#define GIT_MERGE_TREE_OPTS_VERSION 1
|
||||||
|
@ -1626,6 +1626,7 @@ static int checkout_write_merge(
|
|||||||
{
|
{
|
||||||
git_buf our_label = GIT_BUF_INIT, their_label = GIT_BUF_INIT,
|
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;
|
||||||
|
git_merge_file_options merge_file_opts = GIT_MERGE_FILE_OPTIONS_INIT;
|
||||||
git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
|
git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
|
||||||
ours = GIT_MERGE_FILE_INPUT_INIT,
|
ours = GIT_MERGE_FILE_INPUT_INIT,
|
||||||
theirs = GIT_MERGE_FILE_INPUT_INIT;
|
theirs = GIT_MERGE_FILE_INPUT_INIT;
|
||||||
@ -1662,7 +1663,7 @@ static int checkout_write_merge(
|
|||||||
theirs.label = git_buf_cstr(&their_label);
|
theirs.label = git_buf_cstr(&their_label);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((error = git_merge_files(&result, &ancestor, &ours, &theirs, 0)) < 0)
|
if ((error = git_merge_files(&result, &ancestor, &ours, &theirs, &merge_file_opts)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (result.path == NULL || result.mode == 0) {
|
if (result.path == NULL || result.mode == 0) {
|
||||||
|
17
src/merge.c
17
src/merge.c
@ -511,8 +511,9 @@ static int merge_conflict_resolve_automerge(
|
|||||||
int *resolved,
|
int *resolved,
|
||||||
git_merge_diff_list *diff_list,
|
git_merge_diff_list *diff_list,
|
||||||
const git_merge_diff *conflict,
|
const git_merge_diff *conflict,
|
||||||
unsigned int automerge_flags)
|
unsigned int merge_file_favor)
|
||||||
{
|
{
|
||||||
|
git_merge_file_options merge_file_opts = GIT_MERGE_FILE_OPTIONS_INIT;
|
||||||
git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
|
git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
|
||||||
ours = GIT_MERGE_FILE_INPUT_INIT,
|
ours = GIT_MERGE_FILE_INPUT_INIT,
|
||||||
theirs = GIT_MERGE_FILE_INPUT_INIT;
|
theirs = GIT_MERGE_FILE_INPUT_INIT;
|
||||||
@ -526,9 +527,11 @@ static int merge_conflict_resolve_automerge(
|
|||||||
|
|
||||||
*resolved = 0;
|
*resolved = 0;
|
||||||
|
|
||||||
if (automerge_flags == GIT_MERGE_AUTOMERGE_NONE)
|
if (merge_file_favor == GIT_MERGE_FILE_FAVOR_NO_MERGE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
merge_file_opts.favor = merge_file_favor;
|
||||||
|
|
||||||
/* Reject D/F conflicts */
|
/* Reject D/F conflicts */
|
||||||
if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE)
|
if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE)
|
||||||
return 0;
|
return 0;
|
||||||
@ -552,7 +555,7 @@ static int merge_conflict_resolve_automerge(
|
|||||||
(error = git_merge_file_input_from_index_entry(&ancestor, diff_list->repo, &conflict->ancestor_entry)) < 0 ||
|
(error = git_merge_file_input_from_index_entry(&ancestor, diff_list->repo, &conflict->ancestor_entry)) < 0 ||
|
||||||
(error = git_merge_file_input_from_index_entry(&ours, diff_list->repo, &conflict->our_entry)) < 0 ||
|
(error = git_merge_file_input_from_index_entry(&ours, diff_list->repo, &conflict->our_entry)) < 0 ||
|
||||||
(error = git_merge_file_input_from_index_entry(&theirs, diff_list->repo, &conflict->their_entry)) < 0 ||
|
(error = git_merge_file_input_from_index_entry(&theirs, diff_list->repo, &conflict->their_entry)) < 0 ||
|
||||||
(error = git_merge_files(&result, &ancestor, &ours, &theirs, automerge_flags)) < 0 ||
|
(error = git_merge_files(&result, &ancestor, &ours, &theirs, &merge_file_opts)) < 0 ||
|
||||||
!result.automergeable ||
|
!result.automergeable ||
|
||||||
(error = git_odb_write(&automerge_oid, odb, result.data, result.len, GIT_OBJ_BLOB)) < 0)
|
(error = git_odb_write(&automerge_oid, odb, result.data, result.len, GIT_OBJ_BLOB)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
@ -586,7 +589,7 @@ static int merge_conflict_resolve(
|
|||||||
int *out,
|
int *out,
|
||||||
git_merge_diff_list *diff_list,
|
git_merge_diff_list *diff_list,
|
||||||
const git_merge_diff *conflict,
|
const git_merge_diff *conflict,
|
||||||
unsigned int automerge_flags)
|
unsigned int merge_file_favor)
|
||||||
{
|
{
|
||||||
int resolved = 0;
|
int resolved = 0;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
@ -596,14 +599,14 @@ static int merge_conflict_resolve(
|
|||||||
if ((error = merge_conflict_resolve_trivial(&resolved, diff_list, conflict)) < 0)
|
if ((error = merge_conflict_resolve_trivial(&resolved, diff_list, conflict)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (automerge_flags != GIT_MERGE_AUTOMERGE_NONE) {
|
if (merge_file_favor != GIT_MERGE_FILE_FAVOR_NO_MERGE) {
|
||||||
if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0)
|
if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0)
|
if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, automerge_flags)) < 0)
|
if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, merge_file_favor)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1589,7 +1592,7 @@ int git_merge_trees(
|
|||||||
git_vector_foreach(&changes, i, conflict) {
|
git_vector_foreach(&changes, i, conflict) {
|
||||||
int resolved = 0;
|
int resolved = 0;
|
||||||
|
|
||||||
if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.automerge_flags)) < 0)
|
if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.file_favor)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!resolved)
|
if (!resolved)
|
||||||
|
@ -130,7 +130,7 @@ int git_merge_files(
|
|||||||
git_merge_file_input *ancestor,
|
git_merge_file_input *ancestor,
|
||||||
git_merge_file_input *ours,
|
git_merge_file_input *ours,
|
||||||
git_merge_file_input *theirs,
|
git_merge_file_input *theirs,
|
||||||
git_merge_automerge_flags flags)
|
git_merge_file_options *opts)
|
||||||
{
|
{
|
||||||
xmparam_t xmparam;
|
xmparam_t xmparam;
|
||||||
mmbuffer_t mmbuffer;
|
mmbuffer_t mmbuffer;
|
||||||
@ -152,12 +152,15 @@ int git_merge_files(
|
|||||||
out->path = merge_file_best_path(ancestor, ours, theirs);
|
out->path = merge_file_best_path(ancestor, ours, theirs);
|
||||||
out->mode = merge_file_best_mode(ancestor, ours, theirs);
|
out->mode = merge_file_best_mode(ancestor, ours, theirs);
|
||||||
|
|
||||||
if (flags == GIT_MERGE_AUTOMERGE_FAVOR_OURS)
|
if (opts && opts->favor == GIT_MERGE_FILE_FAVOR_OURS)
|
||||||
xmparam.favor = XDL_MERGE_FAVOR_OURS;
|
xmparam.favor = XDL_MERGE_FAVOR_OURS;
|
||||||
|
else if (opts && opts->favor == GIT_MERGE_FILE_FAVOR_THEIRS)
|
||||||
if (flags == GIT_MERGE_AUTOMERGE_FAVOR_THEIRS)
|
|
||||||
xmparam.favor = XDL_MERGE_FAVOR_THEIRS;
|
xmparam.favor = XDL_MERGE_FAVOR_THEIRS;
|
||||||
|
|
||||||
|
xmparam.level =
|
||||||
|
(opts && (opts->flags & GIT_MERGE_FILE_SIMPLIFY_ALNUM)) ?
|
||||||
|
XDL_MERGE_ZEALOUS_ALNUM : XDL_MERGE_ZEALOUS;
|
||||||
|
|
||||||
if ((xdl_result = xdl_merge(&ancestor->mmfile, &ours->mmfile,
|
if ((xdl_result = xdl_merge(&ancestor->mmfile, &ours->mmfile,
|
||||||
&theirs->mmfile, &xmparam, &mmbuffer)) < 0) {
|
&theirs->mmfile, &xmparam, &mmbuffer)) < 0) {
|
||||||
giterr_set(GITERR_MERGE, "Failed to merge files.");
|
giterr_set(GITERR_MERGE, "Failed to merge files.");
|
||||||
|
@ -34,6 +34,18 @@ typedef struct {
|
|||||||
|
|
||||||
#define GIT_MERGE_FILE_RESULT_INIT {0}
|
#define GIT_MERGE_FILE_RESULT_INIT {0}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* Condense non-alphanumeric regions for simplified diff file */
|
||||||
|
GIT_MERGE_FILE_SIMPLIFY_ALNUM = (1 << 0),
|
||||||
|
} git_merge_file_flags_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
git_merge_file_favor_t favor;
|
||||||
|
git_merge_file_flags_t flags;
|
||||||
|
} git_merge_file_options;
|
||||||
|
|
||||||
|
#define GIT_MERGE_FILE_OPTIONS_INIT {0}
|
||||||
|
|
||||||
int git_merge_file_input_from_index_entry(
|
int git_merge_file_input_from_index_entry(
|
||||||
git_merge_file_input *input,
|
git_merge_file_input *input,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
@ -49,7 +61,7 @@ int git_merge_files(
|
|||||||
git_merge_file_input *ancestor,
|
git_merge_file_input *ancestor,
|
||||||
git_merge_file_input *ours,
|
git_merge_file_input *ours,
|
||||||
git_merge_file_input *theirs,
|
git_merge_file_input *theirs,
|
||||||
git_merge_automerge_flags flags);
|
git_merge_file_options *opts);
|
||||||
|
|
||||||
GIT_INLINE(void) git_merge_file_input_free(git_merge_file_input *input)
|
GIT_INLINE(void) git_merge_file_input_free(git_merge_file_input *input)
|
||||||
{
|
{
|
||||||
|
@ -149,7 +149,7 @@ void test_merge_trees_automerge__favor_ours(void)
|
|||||||
REMOVED_IN_MASTER_REUC_ENTRY,
|
REMOVED_IN_MASTER_REUC_ENTRY,
|
||||||
};
|
};
|
||||||
|
|
||||||
opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_OURS;
|
opts.file_favor = GIT_MERGE_FILE_FAVOR_OURS;
|
||||||
|
|
||||||
cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts));
|
cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts));
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ void test_merge_trees_automerge__favor_theirs(void)
|
|||||||
REMOVED_IN_MASTER_REUC_ENTRY,
|
REMOVED_IN_MASTER_REUC_ENTRY,
|
||||||
};
|
};
|
||||||
|
|
||||||
opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_THEIRS;
|
opts.file_favor = GIT_MERGE_FILE_FAVOR_THEIRS;
|
||||||
|
|
||||||
cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts));
|
cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts));
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ static int merge_trivial(git_index **index, const char *ours, const char *theirs
|
|||||||
git_buf branch_buf = GIT_BUF_INIT;
|
git_buf branch_buf = GIT_BUF_INIT;
|
||||||
git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT;
|
git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT;
|
||||||
|
|
||||||
opts.automerge_flags |= automerge ? 0 : GIT_MERGE_AUTOMERGE_NONE;
|
opts.file_favor |= automerge ? 0 : GIT_MERGE_FILE_FAVOR_NO_MERGE;
|
||||||
|
|
||||||
git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours);
|
git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours);
|
||||||
cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr));
|
cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr));
|
||||||
|
@ -113,7 +113,7 @@ void test_merge_workdir_simple__cleanup(void)
|
|||||||
cl_git_sandbox_cleanup();
|
cl_git_sandbox_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
static git_merge_result *merge_simple_branch(int automerge_flags, int checkout_strategy)
|
static git_merge_result *merge_simple_branch(int merge_file_favor, int checkout_strategy)
|
||||||
{
|
{
|
||||||
git_oid their_oids[1];
|
git_oid their_oids[1];
|
||||||
git_merge_head *their_heads[1];
|
git_merge_head *their_heads[1];
|
||||||
@ -123,7 +123,7 @@ static git_merge_result *merge_simple_branch(int automerge_flags, int checkout_s
|
|||||||
cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_SIMPLE_OID));
|
cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_SIMPLE_OID));
|
||||||
cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0]));
|
cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0]));
|
||||||
|
|
||||||
opts.merge_tree_opts.automerge_flags = automerge_flags;
|
opts.merge_tree_opts.file_favor = merge_file_favor;
|
||||||
opts.checkout_opts.checkout_strategy = checkout_strategy;
|
opts.checkout_opts.checkout_strategy = checkout_strategy;
|
||||||
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts));
|
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts));
|
||||||
|
|
||||||
@ -336,7 +336,7 @@ void test_merge_workdir_simple__favor_ours(void)
|
|||||||
REMOVED_IN_MASTER_REUC_ENTRY,
|
REMOVED_IN_MASTER_REUC_ENTRY,
|
||||||
};
|
};
|
||||||
|
|
||||||
cl_assert(result = merge_simple_branch(GIT_MERGE_AUTOMERGE_FAVOR_OURS, 0));
|
cl_assert(result = merge_simple_branch(GIT_MERGE_FILE_FAVOR_OURS, 0));
|
||||||
cl_assert(!git_merge_result_is_fastforward(result));
|
cl_assert(!git_merge_result_is_fastforward(result));
|
||||||
|
|
||||||
cl_assert(merge_test_index(repo_index, merge_index_entries, 6));
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 6));
|
||||||
@ -365,7 +365,7 @@ void test_merge_workdir_simple__favor_theirs(void)
|
|||||||
REMOVED_IN_MASTER_REUC_ENTRY,
|
REMOVED_IN_MASTER_REUC_ENTRY,
|
||||||
};
|
};
|
||||||
|
|
||||||
cl_assert(result = merge_simple_branch(GIT_MERGE_AUTOMERGE_FAVOR_THEIRS, 0));
|
cl_assert(result = merge_simple_branch(GIT_MERGE_FILE_FAVOR_THEIRS, 0));
|
||||||
cl_assert(!git_merge_result_is_fastforward(result));
|
cl_assert(!git_merge_result_is_fastforward(result));
|
||||||
|
|
||||||
cl_assert(merge_test_index(repo_index, merge_index_entries, 6));
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 6));
|
||||||
@ -414,7 +414,7 @@ void test_merge_workdir_simple__directory_file(void)
|
|||||||
cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_DIRECTORY_FILE));
|
cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_DIRECTORY_FILE));
|
||||||
cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0]));
|
cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0]));
|
||||||
|
|
||||||
opts.merge_tree_opts.automerge_flags = 0;
|
opts.merge_tree_opts.file_favor = 0;
|
||||||
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts));
|
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts));
|
||||||
|
|
||||||
cl_assert(merge_test_index(repo_index, merge_index_entries, 20));
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 20));
|
||||||
@ -447,7 +447,7 @@ void test_merge_workdir_simple__unrelated(void)
|
|||||||
cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_PARENT));
|
cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_PARENT));
|
||||||
cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0]));
|
cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0]));
|
||||||
|
|
||||||
opts.merge_tree_opts.automerge_flags = 0;
|
opts.merge_tree_opts.file_favor = 0;
|
||||||
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts));
|
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts));
|
||||||
|
|
||||||
cl_assert(merge_test_index(repo_index, merge_index_entries, 9));
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 9));
|
||||||
@ -480,7 +480,7 @@ void test_merge_workdir_simple__unrelated_with_conflicts(void)
|
|||||||
cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_OID));
|
cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_OID));
|
||||||
cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0]));
|
cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0]));
|
||||||
|
|
||||||
opts.merge_tree_opts.automerge_flags = 0;
|
opts.merge_tree_opts.file_favor = 0;
|
||||||
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts));
|
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts));
|
||||||
|
|
||||||
cl_assert(merge_test_index(repo_index, merge_index_entries, 11));
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 11));
|
||||||
|
@ -39,7 +39,7 @@ static int merge_trivial(const char *ours, const char *theirs, bool automerge)
|
|||||||
|
|
||||||
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||||
|
|
||||||
opts.merge_tree_opts.automerge_flags |= automerge ? 0 : GIT_MERGE_AUTOMERGE_NONE;
|
opts.merge_tree_opts.file_favor |= automerge ? 0 : GIT_MERGE_FILE_FAVOR_NO_MERGE;
|
||||||
|
|
||||||
git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours);
|
git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours);
|
||||||
cl_git_pass(git_reference_symbolic_create(&our_ref, repo, "HEAD", branch_buf.ptr, 1, NULL, NULL));
|
cl_git_pass(git_reference_symbolic_create(&our_ref, repo, "HEAD", branch_buf.ptr, 1, NULL, NULL));
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tests/resources/revert/.gitted/refs/heads/two
Normal file
BIN
tests/resources/revert/.gitted/refs/heads/two
Normal file
Binary file not shown.
@ -137,6 +137,203 @@ void test_revert_workdir__orphan(void)
|
|||||||
git_commit_free(head);
|
git_commit_free(head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* revert the same commit twice (when the first reverts cleanly):
|
||||||
|
*
|
||||||
|
* git revert 2d440f2
|
||||||
|
* git revert 2d440f2
|
||||||
|
*/
|
||||||
|
void test_revert_workdir__again(void)
|
||||||
|
{
|
||||||
|
git_reference *head_ref;
|
||||||
|
git_commit *orig_head;
|
||||||
|
git_tree *reverted_tree;
|
||||||
|
git_oid reverted_tree_oid, reverted_commit_oid;
|
||||||
|
git_signature *signature;
|
||||||
|
|
||||||
|
struct merge_index_entry merge_index_entries[] = {
|
||||||
|
{ 0100644, "7731926a337c4eaba1e2187d90ebfa0a93659382", 0, "file1.txt" },
|
||||||
|
{ 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" },
|
||||||
|
{ 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" },
|
||||||
|
{ 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" },
|
||||||
|
};
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_head(&head_ref, repo));
|
||||||
|
cl_git_pass(git_reference_peel((git_object **)&orig_head, head_ref, GIT_OBJ_COMMIT));
|
||||||
|
cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD));
|
||||||
|
|
||||||
|
cl_git_pass(git_revert(repo, orig_head, NULL));
|
||||||
|
|
||||||
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 4));
|
||||||
|
|
||||||
|
cl_git_pass(git_index_write_tree(&reverted_tree_oid, repo_index));
|
||||||
|
cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid));
|
||||||
|
|
||||||
|
cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0));
|
||||||
|
cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&orig_head));
|
||||||
|
|
||||||
|
cl_git_pass(git_revert(repo, orig_head, NULL));
|
||||||
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 4));
|
||||||
|
|
||||||
|
git_signature_free(signature);
|
||||||
|
git_tree_free(reverted_tree);
|
||||||
|
git_commit_free(orig_head);
|
||||||
|
git_reference_free(head_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* git reset --hard 72333f47d4e83616630ff3b0ffe4c0faebcc3c45
|
||||||
|
* git revert --no-commit d1d403d22cbe24592d725f442835cf46fe60c8ac */
|
||||||
|
void test_revert_workdir__again_after_automerge(void)
|
||||||
|
{
|
||||||
|
git_commit *head, *commit;
|
||||||
|
git_tree *reverted_tree;
|
||||||
|
git_oid head_oid, revert_oid, reverted_tree_oid, reverted_commit_oid;
|
||||||
|
git_signature *signature;
|
||||||
|
|
||||||
|
struct merge_index_entry merge_index_entries[] = {
|
||||||
|
{ 0100644, "caf99de3a49827117bb66721010eac461b06a80c", 0, "file1.txt" },
|
||||||
|
{ 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" },
|
||||||
|
{ 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" },
|
||||||
|
{ 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct merge_index_entry second_revert_entries[] = {
|
||||||
|
{ 0100644, "3a3ef367eaf3fe79effbfb0a56b269c04c2b59fe", 1, "file1.txt" },
|
||||||
|
{ 0100644, "caf99de3a49827117bb66721010eac461b06a80c", 2, "file1.txt" },
|
||||||
|
{ 0100644, "747726e021bc5f44b86de60e3032fd6f9f1b8383", 3, "file1.txt" },
|
||||||
|
{ 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" },
|
||||||
|
{ 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" },
|
||||||
|
{ 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" },
|
||||||
|
};
|
||||||
|
|
||||||
|
git_oid_fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45");
|
||||||
|
cl_git_pass(git_commit_lookup(&head, repo, &head_oid));
|
||||||
|
cl_git_pass(git_reset(repo, (git_object *)head, GIT_RESET_HARD));
|
||||||
|
|
||||||
|
git_oid_fromstr(&revert_oid, "d1d403d22cbe24592d725f442835cf46fe60c8ac");
|
||||||
|
cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid));
|
||||||
|
cl_git_pass(git_revert(repo, commit, NULL));
|
||||||
|
|
||||||
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 4));
|
||||||
|
|
||||||
|
cl_git_pass(git_index_write_tree(&reverted_tree_oid, repo_index));
|
||||||
|
cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid));
|
||||||
|
|
||||||
|
cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0));
|
||||||
|
cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&head));
|
||||||
|
|
||||||
|
cl_git_pass(git_revert(repo, commit, NULL));
|
||||||
|
cl_assert(merge_test_index(repo_index, second_revert_entries, 6));
|
||||||
|
|
||||||
|
git_signature_free(signature);
|
||||||
|
git_tree_free(reverted_tree);
|
||||||
|
git_commit_free(commit);
|
||||||
|
git_commit_free(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* revert the same commit twice (when the first reverts cleanly):
|
||||||
|
*
|
||||||
|
* git revert 2d440f2
|
||||||
|
* git revert 2d440f2
|
||||||
|
*/
|
||||||
|
void test_revert_workdir__again_after_edit(void)
|
||||||
|
{
|
||||||
|
git_reference *head_ref;
|
||||||
|
git_commit *orig_head, *commit;
|
||||||
|
git_tree *reverted_tree;
|
||||||
|
git_oid orig_head_oid, revert_oid, reverted_tree_oid, reverted_commit_oid;
|
||||||
|
git_signature *signature;
|
||||||
|
|
||||||
|
struct merge_index_entry merge_index_entries[] = {
|
||||||
|
{ 0100644, "3721552e06c4bdc7d478e0674e6304888545d5fd", 0, "file1.txt" },
|
||||||
|
{ 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" },
|
||||||
|
{ 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" },
|
||||||
|
{ 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" },
|
||||||
|
};
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_head(&head_ref, repo));
|
||||||
|
|
||||||
|
cl_git_pass(git_oid_fromstr(&orig_head_oid, "399fb3aba3d9d13f7d40a9254ce4402067ef3149"));
|
||||||
|
cl_git_pass(git_commit_lookup(&orig_head, repo, &orig_head_oid));
|
||||||
|
cl_git_pass(git_reset(repo, (git_object *)orig_head, GIT_RESET_HARD));
|
||||||
|
|
||||||
|
cl_git_pass(git_oid_fromstr(&revert_oid, "2d440f2b3147d3dc7ad1085813478d6d869d5a4d"));
|
||||||
|
cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid));
|
||||||
|
|
||||||
|
cl_git_pass(git_revert(repo, commit, NULL));
|
||||||
|
|
||||||
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 4));
|
||||||
|
|
||||||
|
cl_git_pass(git_index_write_tree(&reverted_tree_oid, repo_index));
|
||||||
|
cl_git_pass(git_tree_lookup(&reverted_tree, repo, &reverted_tree_oid));
|
||||||
|
|
||||||
|
cl_git_pass(git_signature_new(&signature, "Reverter", "reverter@example.org", time(NULL), 0));
|
||||||
|
cl_git_pass(git_commit_create(&reverted_commit_oid, repo, "HEAD", signature, signature, NULL, "Reverted!", reverted_tree, 1, (const git_commit **)&orig_head));
|
||||||
|
|
||||||
|
cl_git_pass(git_revert(repo, commit, NULL));
|
||||||
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 4));
|
||||||
|
|
||||||
|
git_signature_free(signature);
|
||||||
|
git_tree_free(reverted_tree);
|
||||||
|
git_commit_free(commit);
|
||||||
|
git_commit_free(orig_head);
|
||||||
|
git_reference_free(head_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* revert the same commit twice (when the first reverts cleanly):
|
||||||
|
*
|
||||||
|
* git reset --hard e34ef1a
|
||||||
|
* git revert 71eb9c2
|
||||||
|
*/
|
||||||
|
void test_revert_workdir__again_after_edit_two(void)
|
||||||
|
{
|
||||||
|
git_buf diff_buf = GIT_BUF_INIT;
|
||||||
|
git_config *config;
|
||||||
|
git_oid head_commit_oid, revert_commit_oid;
|
||||||
|
git_commit *head_commit, *revert_commit;
|
||||||
|
|
||||||
|
struct merge_index_entry merge_index_entries[] = {
|
||||||
|
{ 0100644, "1ff0c423042b46cb1d617b81efb715defbe8054d", 0, ".gitattributes" },
|
||||||
|
{ 0100644, "1bc915c5cb7185a9438de28a7b1a7dfe8c01ee7f", 0, ".gitignore" },
|
||||||
|
{ 0100644, "a8c86221b400b836010567cc3593db6e96c1a83a", 1, "file.txt" },
|
||||||
|
{ 0100644, "46ff0854663aeb2182b9838c8da68e33ac23bc1e", 2, "file.txt" },
|
||||||
|
{ 0100644, "21a96a98ed84d45866e1de6e266fd3a61a4ae9dc", 3, "file.txt" },
|
||||||
|
};
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_config(&config, repo));
|
||||||
|
cl_git_pass(git_config_set_bool(config, "core.autocrlf", 0));
|
||||||
|
|
||||||
|
cl_git_pass(git_oid_fromstr(&head_commit_oid, "e34ef1afe54eb526fd92eec66084125f340f1d65"));
|
||||||
|
cl_git_pass(git_commit_lookup(&head_commit, repo, &head_commit_oid));
|
||||||
|
cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD));
|
||||||
|
|
||||||
|
cl_git_pass(git_oid_fromstr(&revert_commit_oid, "71eb9c2b53dbbf3c45fb28b27c850db4b7fb8011"));
|
||||||
|
cl_git_pass(git_commit_lookup(&revert_commit, repo, &revert_commit_oid));
|
||||||
|
|
||||||
|
cl_git_pass(git_revert(repo, revert_commit, NULL));
|
||||||
|
|
||||||
|
cl_assert(merge_test_index(repo_index, merge_index_entries, 5));
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_readbuffer(&diff_buf, "revert/file.txt"));
|
||||||
|
cl_assert(strcmp(diff_buf.ptr, "a\n" \
|
||||||
|
"<<<<<<< HEAD\n" \
|
||||||
|
"=======\n" \
|
||||||
|
"a\n" \
|
||||||
|
">>>>>>> parent of 71eb9c2... revert me\n" \
|
||||||
|
"a\n" \
|
||||||
|
"a\n" \
|
||||||
|
"a\n" \
|
||||||
|
"a\n" \
|
||||||
|
"ab\n") == 0);
|
||||||
|
|
||||||
|
git_commit_free(revert_commit);
|
||||||
|
git_commit_free(head_commit);
|
||||||
|
git_config_free(config);
|
||||||
|
git_buf_free(&diff_buf);
|
||||||
|
}
|
||||||
|
|
||||||
/* git reset --hard 72333f47d4e83616630ff3b0ffe4c0faebcc3c45
|
/* git reset --hard 72333f47d4e83616630ff3b0ffe4c0faebcc3c45
|
||||||
* git revert --no-commit d1d403d22cbe24592d725f442835cf46fe60c8ac */
|
* git revert --no-commit d1d403d22cbe24592d725f442835cf46fe60c8ac */
|
||||||
void test_revert_workdir__conflict_use_ours(void)
|
void test_revert_workdir__conflict_use_ours(void)
|
||||||
@ -161,7 +358,7 @@ void test_revert_workdir__conflict_use_ours(void)
|
|||||||
{ 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" },
|
{ 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" },
|
||||||
};
|
};
|
||||||
|
|
||||||
opts.merge_tree_opts.automerge_flags = GIT_MERGE_AUTOMERGE_NONE;
|
opts.merge_tree_opts.file_favor = GIT_MERGE_FILE_FAVOR_NO_MERGE;
|
||||||
opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS;
|
opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS;
|
||||||
|
|
||||||
git_oid_fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45");
|
git_oid_fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45");
|
||||||
|
Loading…
Reference in New Issue
Block a user