mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-08 19:51:31 +00:00
Merge pull request #2061 from ethomson/merge_improvements
Merge improvements
This commit is contained in:
commit
af2b969b6f
@ -152,6 +152,12 @@ typedef enum {
|
||||
/** Don't overwrite ignored files that exist in the checkout target */
|
||||
GIT_CHECKOUT_DONT_OVERWRITE_IGNORED = (1u << 19),
|
||||
|
||||
/** Write normal merge files for conflicts */
|
||||
GIT_CHECKOUT_CONFLICT_STYLE_MERGE = (1u << 20),
|
||||
|
||||
/** Include common ancestor data in diff3 format files for conflicts */
|
||||
GIT_CHECKOUT_CONFLICT_STYLE_DIFF3 = (1u << 21),
|
||||
|
||||
/**
|
||||
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
|
||||
*/
|
||||
@ -252,6 +258,7 @@ typedef struct git_checkout_opts {
|
||||
|
||||
const char *target_directory; /** alternative checkout path to workdir */
|
||||
|
||||
const char *ancestor_label; /** the name of the common ancestor side of conflicts */
|
||||
const char *our_label; /** the name of the "our" side of conflicts */
|
||||
const char *their_label; /** the name of the "their" side of conflicts */
|
||||
} git_checkout_opts;
|
||||
|
@ -32,14 +32,21 @@ typedef enum {
|
||||
} git_merge_tree_flag_t;
|
||||
|
||||
/**
|
||||
* Automerge options for `git_merge_trees_opts`.
|
||||
* Merge file options for `git_merge_trees_opts`.
|
||||
*/
|
||||
typedef enum {
|
||||
GIT_MERGE_AUTOMERGE_NORMAL = 0,
|
||||
GIT_MERGE_AUTOMERGE_NONE = 1,
|
||||
GIT_MERGE_AUTOMERGE_FAVOR_OURS = 2,
|
||||
GIT_MERGE_AUTOMERGE_FAVOR_THEIRS = 3,
|
||||
} git_merge_automerge_flags;
|
||||
/* Produce a conflict in a file when two similar regions are changed. */
|
||||
GIT_MERGE_FILE_FAVOR_NORMAL = 0,
|
||||
|
||||
/* Produce a file containing the "ours" side of conflicting regions. */
|
||||
GIT_MERGE_FILE_FAVOR_OURS = 1,
|
||||
|
||||
/* Produce a file containing the "theirs" side of conflicting regions. */
|
||||
GIT_MERGE_FILE_FAVOR_THEIRS = 2,
|
||||
|
||||
/* Produce a file blending the sides in a union of conflicting regions */
|
||||
GIT_MERGE_FILE_FAVOR_UNION = 3,
|
||||
} git_merge_file_favor_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
@ -58,7 +65,7 @@ typedef struct {
|
||||
git_diff_similarity_metric *metric;
|
||||
|
||||
/** Flags for automerging content. */
|
||||
git_merge_automerge_flags automerge_flags;
|
||||
git_merge_file_favor_t file_favor;
|
||||
} git_merge_tree_opts;
|
||||
|
||||
#define GIT_MERGE_TREE_OPTS_VERSION 1
|
||||
|
@ -70,7 +70,9 @@ typedef struct {
|
||||
|
||||
int name_collision:1,
|
||||
directoryfile:1,
|
||||
one_to_two:1;
|
||||
one_to_two:1,
|
||||
binary:1,
|
||||
submodule:1;
|
||||
} checkout_conflictdata;
|
||||
|
||||
static int checkout_notify(
|
||||
@ -681,6 +683,51 @@ GIT_INLINE(bool) conflict_pathspec_match(
|
||||
return false;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) checkout_conflict_detect_submodule(checkout_conflictdata *conflict)
|
||||
{
|
||||
conflict->submodule = ((conflict->ancestor && S_ISGITLINK(conflict->ancestor->mode)) ||
|
||||
(conflict->ours && S_ISGITLINK(conflict->ours->mode)) ||
|
||||
(conflict->theirs && S_ISGITLINK(conflict->theirs->mode)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) checkout_conflict_detect_binary(git_repository *repo, checkout_conflictdata *conflict)
|
||||
{
|
||||
git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
|
||||
int error = 0;
|
||||
|
||||
if (conflict->submodule)
|
||||
return 0;
|
||||
|
||||
if (conflict->ancestor) {
|
||||
if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor->oid)) < 0)
|
||||
goto done;
|
||||
|
||||
conflict->binary = git_blob_is_binary(ancestor_blob);
|
||||
}
|
||||
|
||||
if (!conflict->binary && conflict->ours) {
|
||||
if ((error = git_blob_lookup(&our_blob, repo, &conflict->ours->oid)) < 0)
|
||||
goto done;
|
||||
|
||||
conflict->binary = git_blob_is_binary(our_blob);
|
||||
}
|
||||
|
||||
if (!conflict->binary && conflict->theirs) {
|
||||
if ((error = git_blob_lookup(&their_blob, repo, &conflict->theirs->oid)) < 0)
|
||||
goto done;
|
||||
|
||||
conflict->binary = git_blob_is_binary(their_blob);
|
||||
}
|
||||
|
||||
done:
|
||||
git_blob_free(ancestor_blob);
|
||||
git_blob_free(our_blob);
|
||||
git_blob_free(their_blob);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec)
|
||||
{
|
||||
git_index_conflict_iterator *iterator = NULL;
|
||||
@ -705,6 +752,10 @@ static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, g
|
||||
conflict->ours = ours;
|
||||
conflict->theirs = theirs;
|
||||
|
||||
if ((error = checkout_conflict_detect_submodule(conflict)) < 0 ||
|
||||
(error = checkout_conflict_detect_binary(data->repo, conflict)) < 0)
|
||||
goto done;
|
||||
|
||||
git_vector_insert(&data->conflicts, conflict);
|
||||
}
|
||||
|
||||
@ -1626,6 +1677,7 @@ static int checkout_write_merge(
|
||||
{
|
||||
git_buf our_label = GIT_BUF_INIT, their_label = 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,
|
||||
ours = GIT_MERGE_FILE_INPUT_INIT,
|
||||
theirs = GIT_MERGE_FILE_INPUT_INIT;
|
||||
@ -1633,6 +1685,9 @@ static int checkout_write_merge(
|
||||
git_filebuf output = GIT_FILEBUF_INIT;
|
||||
int error = 0;
|
||||
|
||||
if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)
|
||||
merge_file_opts.style = GIT_MERGE_FILE_STYLE_DIFF3;
|
||||
|
||||
if ((conflict->ancestor &&
|
||||
(error = git_merge_file_input_from_index_entry(
|
||||
&ancestor, data->repo, conflict->ancestor)) < 0) ||
|
||||
@ -1642,7 +1697,7 @@ static int checkout_write_merge(
|
||||
&theirs, data->repo, conflict->theirs)) < 0)
|
||||
goto done;
|
||||
|
||||
ancestor.label = NULL;
|
||||
ancestor.label = data->opts.ancestor_label ? data->opts.ancestor_label : "ancestor";
|
||||
ours.label = data->opts.our_label ? data->opts.our_label : "ours";
|
||||
theirs.label = data->opts.their_label ? data->opts.their_label : "theirs";
|
||||
|
||||
@ -1662,7 +1717,7 @@ static int checkout_write_merge(
|
||||
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;
|
||||
|
||||
if (result.path == NULL || result.mode == 0) {
|
||||
@ -1705,6 +1760,7 @@ static int checkout_create_conflicts(checkout_data *data)
|
||||
int error = 0;
|
||||
|
||||
git_vector_foreach(&data->conflicts, i, conflict) {
|
||||
|
||||
/* Both deleted: nothing to do */
|
||||
if (conflict->ours == NULL && conflict->theirs == NULL)
|
||||
error = 0;
|
||||
@ -1748,7 +1804,15 @@ static int checkout_create_conflicts(checkout_data *data)
|
||||
else if (S_ISLNK(conflict->theirs->mode))
|
||||
error = checkout_write_entry(data, conflict, conflict->ours);
|
||||
|
||||
else
|
||||
/* If any side is a gitlink, do nothing. */
|
||||
else if (conflict->submodule)
|
||||
error = 0;
|
||||
|
||||
/* If any side is binary, write the ours side */
|
||||
else if (conflict->binary)
|
||||
error = checkout_write_entry(data, conflict, conflict->ours);
|
||||
|
||||
else if (!error)
|
||||
error = checkout_write_merge(data, conflict);
|
||||
|
||||
if (error)
|
||||
@ -1891,6 +1955,29 @@ static int checkout_data_init(
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((data->opts.checkout_strategy &
|
||||
(GIT_CHECKOUT_CONFLICT_STYLE_MERGE | GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)) == 0) {
|
||||
const char *conflict_style;
|
||||
git_config *cfg = NULL;
|
||||
|
||||
if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
|
||||
(error = git_config_get_string(&conflict_style, cfg, "merge.conflictstyle")) < 0 ||
|
||||
error == GIT_ENOTFOUND)
|
||||
;
|
||||
else if (error)
|
||||
goto cleanup;
|
||||
else if (strcmp(conflict_style, "merge") == 0)
|
||||
data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_MERGE;
|
||||
else if (strcmp(conflict_style, "diff3") == 0)
|
||||
data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3;
|
||||
else {
|
||||
giterr_set(GITERR_CHECKOUT, "unknown style '%s' given for 'merge.conflictstyle'",
|
||||
conflict_style);
|
||||
error = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
|
||||
(error = git_vector_init(&data->conflicts, 0, NULL)) < 0 ||
|
||||
(error = git_pool_init(&data->pool, 1, 0)) < 0 ||
|
||||
|
101
src/merge.c
101
src/merge.c
@ -42,6 +42,7 @@
|
||||
#include "git2/sys/index.h"
|
||||
|
||||
#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0)
|
||||
#define GIT_MERGE_INDEX_ENTRY_ISFILE(X) S_ISREG((X).mode)
|
||||
|
||||
typedef enum {
|
||||
TREE_IDX_ANCESTOR = 0,
|
||||
@ -447,7 +448,6 @@ static int merge_conflict_resolve_one_removed(
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int merge_conflict_resolve_one_renamed(
|
||||
int *resolved,
|
||||
git_merge_diff_list *diff_list,
|
||||
@ -511,8 +511,9 @@ static int merge_conflict_resolve_automerge(
|
||||
int *resolved,
|
||||
git_merge_diff_list *diff_list,
|
||||
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,
|
||||
ours = GIT_MERGE_FILE_INPUT_INIT,
|
||||
theirs = GIT_MERGE_FILE_INPUT_INIT;
|
||||
@ -526,13 +527,18 @@ static int merge_conflict_resolve_automerge(
|
||||
|
||||
*resolved = 0;
|
||||
|
||||
if (automerge_flags == GIT_MERGE_AUTOMERGE_NONE)
|
||||
return 0;
|
||||
merge_file_opts.favor = merge_file_favor;
|
||||
|
||||
/* Reject D/F conflicts */
|
||||
if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE)
|
||||
return 0;
|
||||
|
||||
/* Reject submodules. */
|
||||
if (S_ISGITLINK(conflict->ancestor_entry.mode) ||
|
||||
S_ISGITLINK(conflict->our_entry.mode) ||
|
||||
S_ISGITLINK(conflict->their_entry.mode))
|
||||
return 0;
|
||||
|
||||
/* Reject link/file conflicts. */
|
||||
if ((S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->our_entry.mode)) ||
|
||||
(S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->their_entry.mode)))
|
||||
@ -548,11 +554,15 @@ static int merge_conflict_resolve_automerge(
|
||||
strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0)
|
||||
return 0;
|
||||
|
||||
/* Reject binary conflicts */
|
||||
if (conflict->binary)
|
||||
return 0;
|
||||
|
||||
if ((error = git_repository_odb(&odb, diff_list->repo)) < 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(&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 ||
|
||||
(error = git_odb_write(&automerge_oid, odb, result.data, result.len, GIT_OBJ_BLOB)) < 0)
|
||||
goto done;
|
||||
@ -586,7 +596,7 @@ static int merge_conflict_resolve(
|
||||
int *out,
|
||||
git_merge_diff_list *diff_list,
|
||||
const git_merge_diff *conflict,
|
||||
unsigned int automerge_flags)
|
||||
unsigned int merge_file_favor)
|
||||
{
|
||||
int resolved = 0;
|
||||
int error = 0;
|
||||
@ -596,16 +606,14 @@ static int merge_conflict_resolve(
|
||||
if ((error = merge_conflict_resolve_trivial(&resolved, diff_list, conflict)) < 0)
|
||||
goto done;
|
||||
|
||||
if (automerge_flags != GIT_MERGE_AUTOMERGE_NONE) {
|
||||
if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0)
|
||||
goto done;
|
||||
if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0)
|
||||
goto done;
|
||||
|
||||
if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0)
|
||||
goto done;
|
||||
if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0)
|
||||
goto done;
|
||||
|
||||
if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, automerge_flags)) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, merge_file_favor)) < 0)
|
||||
goto done;
|
||||
|
||||
*out = resolved;
|
||||
|
||||
@ -1147,6 +1155,44 @@ GIT_INLINE(int) merge_diff_detect_type(
|
||||
return 0;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) merge_diff_detect_binary(
|
||||
git_repository *repo,
|
||||
git_merge_diff *conflict)
|
||||
{
|
||||
git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
|
||||
int error = 0;
|
||||
|
||||
if (GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->ancestor_entry)) {
|
||||
if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor_entry.oid)) < 0)
|
||||
goto done;
|
||||
|
||||
conflict->binary = git_blob_is_binary(ancestor_blob);
|
||||
}
|
||||
|
||||
if (!conflict->binary &&
|
||||
GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->our_entry)) {
|
||||
if ((error = git_blob_lookup(&our_blob, repo, &conflict->our_entry.oid)) < 0)
|
||||
goto done;
|
||||
|
||||
conflict->binary = git_blob_is_binary(our_blob);
|
||||
}
|
||||
|
||||
if (!conflict->binary &&
|
||||
GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->their_entry)) {
|
||||
if ((error = git_blob_lookup(&their_blob, repo, &conflict->their_entry.oid)) < 0)
|
||||
goto done;
|
||||
|
||||
conflict->binary = git_blob_is_binary(their_blob);
|
||||
}
|
||||
|
||||
done:
|
||||
git_blob_free(ancestor_blob);
|
||||
git_blob_free(our_blob);
|
||||
git_blob_free(their_blob);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) index_entry_dup(
|
||||
git_index_entry *out,
|
||||
git_pool *pool,
|
||||
@ -1218,6 +1264,7 @@ static int merge_diff_list_insert_conflict(
|
||||
if ((conflict = merge_diff_from_index_entries(diff_list, tree_items)) == NULL ||
|
||||
merge_diff_detect_type(conflict) < 0 ||
|
||||
merge_diff_detect_df_conflict(merge_df_data, conflict) < 0 ||
|
||||
merge_diff_detect_binary(diff_list->repo, conflict) < 0 ||
|
||||
git_vector_insert(&diff_list->conflicts, conflict) < 0)
|
||||
return -1;
|
||||
|
||||
@ -1589,7 +1636,7 @@ int git_merge_trees(
|
||||
git_vector_foreach(&changes, i, conflict) {
|
||||
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;
|
||||
|
||||
if (!resolved)
|
||||
@ -2119,6 +2166,8 @@ static int merge_normalize_opts(
|
||||
git_repository *repo,
|
||||
git_merge_opts *opts,
|
||||
const git_merge_opts *given,
|
||||
const git_merge_head *ancestor_head,
|
||||
const git_merge_head *our_head,
|
||||
size_t their_heads_len,
|
||||
const git_merge_head **their_heads)
|
||||
{
|
||||
@ -2138,8 +2187,20 @@ static int merge_normalize_opts(
|
||||
if (!opts->checkout_opts.checkout_strategy)
|
||||
opts->checkout_opts.checkout_strategy = default_checkout_strategy;
|
||||
|
||||
if (!opts->checkout_opts.our_label)
|
||||
opts->checkout_opts.our_label = "HEAD";
|
||||
/* TODO: for multiple ancestors in merge-recursive, this is "merged common ancestors" */
|
||||
if (!opts->checkout_opts.ancestor_label) {
|
||||
if (ancestor_head && ancestor_head->commit)
|
||||
opts->checkout_opts.ancestor_label = git_commit_summary(ancestor_head->commit);
|
||||
else
|
||||
opts->checkout_opts.ancestor_label = "ancestor";
|
||||
}
|
||||
|
||||
if (!opts->checkout_opts.our_label) {
|
||||
if (our_head && our_head->ref_name)
|
||||
opts->checkout_opts.our_label = our_head->ref_name;
|
||||
else
|
||||
opts->checkout_opts.our_label = "ours";
|
||||
}
|
||||
|
||||
if (!opts->checkout_opts.their_label) {
|
||||
if (their_heads_len == 1 && their_heads[0]->ref_name)
|
||||
@ -2434,9 +2495,6 @@ int git_merge(
|
||||
their_trees = git__calloc(their_heads_len, sizeof(git_tree *));
|
||||
GITERR_CHECK_ALLOC(their_trees);
|
||||
|
||||
if ((error = merge_normalize_opts(repo, &opts, given_opts, their_heads_len, their_heads)) < 0)
|
||||
goto on_error;
|
||||
|
||||
if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0)
|
||||
goto on_error;
|
||||
|
||||
@ -2448,6 +2506,9 @@ int git_merge(
|
||||
error != GIT_ENOTFOUND)
|
||||
goto on_error;
|
||||
|
||||
if ((error = merge_normalize_opts(repo, &opts, given_opts, ancestor_head, our_head, their_heads_len, their_heads)) < 0)
|
||||
goto on_error;
|
||||
|
||||
if (their_heads_len == 1 &&
|
||||
ancestor_head != NULL &&
|
||||
(merge_check_uptodate(result, ancestor_head, their_heads[0]) ||
|
||||
|
@ -106,6 +106,8 @@ typedef struct {
|
||||
|
||||
git_index_entry their_entry;
|
||||
git_delta_t their_status;
|
||||
|
||||
int binary:1;
|
||||
} git_merge_diff;
|
||||
|
||||
/** Internal structure for merge inputs */
|
||||
|
@ -130,7 +130,7 @@ int git_merge_files(
|
||||
git_merge_file_input *ancestor,
|
||||
git_merge_file_input *ours,
|
||||
git_merge_file_input *theirs,
|
||||
git_merge_automerge_flags flags)
|
||||
git_merge_file_options *opts)
|
||||
{
|
||||
xmparam_t xmparam;
|
||||
mmbuffer_t mmbuffer;
|
||||
@ -152,11 +152,19 @@ int git_merge_files(
|
||||
out->path = merge_file_best_path(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;
|
||||
|
||||
if (flags == GIT_MERGE_AUTOMERGE_FAVOR_THEIRS)
|
||||
else if (opts && opts->favor == GIT_MERGE_FILE_FAVOR_THEIRS)
|
||||
xmparam.favor = XDL_MERGE_FAVOR_THEIRS;
|
||||
else if (opts && opts->favor == GIT_MERGE_FILE_FAVOR_UNION)
|
||||
xmparam.favor = XDL_MERGE_FAVOR_UNION;
|
||||
|
||||
xmparam.level =
|
||||
(opts && (opts->flags & GIT_MERGE_FILE_SIMPLIFY_ALNUM)) ?
|
||||
XDL_MERGE_ZEALOUS_ALNUM : XDL_MERGE_ZEALOUS;
|
||||
|
||||
if (opts && opts->style == GIT_MERGE_FILE_STYLE_DIFF3)
|
||||
xmparam.style = XDL_MERGE_DIFF3;
|
||||
|
||||
if ((xdl_result = xdl_merge(&ancestor->mmfile, &ours->mmfile,
|
||||
&theirs->mmfile, &xmparam, &mmbuffer)) < 0) {
|
||||
|
@ -34,6 +34,27 @@ typedef struct {
|
||||
|
||||
#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 enum {
|
||||
/* Create standard conflicted merge files */
|
||||
GIT_MERGE_FILE_STYLE_MERGE = 0,
|
||||
|
||||
/* Create diff3-style files */
|
||||
GIT_MERGE_FILE_STYLE_DIFF3 = 1,
|
||||
} git_merge_file_style_t;
|
||||
|
||||
typedef struct {
|
||||
git_merge_file_favor_t favor;
|
||||
git_merge_file_flags_t flags;
|
||||
git_merge_file_style_t style;
|
||||
} git_merge_file_options;
|
||||
|
||||
#define GIT_MERGE_FILE_OPTIONS_INIT {0}
|
||||
|
||||
int git_merge_file_input_from_index_entry(
|
||||
git_merge_file_input *input,
|
||||
git_repository *repo,
|
||||
@ -49,7 +70,7 @@ int git_merge_files(
|
||||
git_merge_file_input *ancestor,
|
||||
git_merge_file_input *ours,
|
||||
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)
|
||||
{
|
||||
|
@ -149,7 +149,7 @@ void test_merge_trees_automerge__favor_ours(void)
|
||||
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));
|
||||
|
||||
@ -180,7 +180,7 @@ void test_merge_trees_automerge__favor_theirs(void)
|
||||
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));
|
||||
|
||||
|
@ -25,7 +25,7 @@ void test_merge_trees_trivial__cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
static int merge_trivial(git_index **index, const char *ours, const char *theirs, bool automerge)
|
||||
static int merge_trivial(git_index **index, const char *ours, const char *theirs)
|
||||
{
|
||||
git_commit *our_commit, *their_commit, *ancestor_commit;
|
||||
git_tree *our_tree, *their_tree, *ancestor_tree;
|
||||
@ -33,8 +33,6 @@ static int merge_trivial(git_index **index, const char *ours, const char *theirs
|
||||
git_buf branch_buf = GIT_BUF_INIT;
|
||||
git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT;
|
||||
|
||||
opts.automerge_flags |= automerge ? 0 : GIT_MERGE_AUTOMERGE_NONE;
|
||||
|
||||
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_commit_lookup(&our_commit, repo, &our_oid));
|
||||
@ -86,7 +84,7 @@ void test_merge_trees_trivial__2alt(void)
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-2alt", "trivial-2alt-branch", 0));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-2alt", "trivial-2alt-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(result, "new-in-branch.txt", 0));
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
@ -101,7 +99,7 @@ void test_merge_trees_trivial__3alt(void)
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-3alt", "trivial-3alt-branch", 0));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-3alt", "trivial-3alt-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(result, "new-in-3alt.txt", 0));
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
@ -116,7 +114,7 @@ void test_merge_trees_trivial__4(void)
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-4", "trivial-4-branch", 0));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-4", "trivial-4-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "new-and-different.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
@ -134,7 +132,7 @@ void test_merge_trees_trivial__5alt_1(void)
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-5alt-1", "trivial-5alt-1-branch", 0));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-5alt-1", "trivial-5alt-1-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(result, "new-and-same.txt", 0));
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
@ -149,7 +147,7 @@ void test_merge_trees_trivial__5alt_2(void)
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-5alt-2", "trivial-5alt-2-branch", 0));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-5alt-2", "trivial-5alt-2-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(result, "modified-to-same.txt", 0));
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
@ -160,29 +158,12 @@ void test_merge_trees_trivial__5alt_2(void)
|
||||
|
||||
/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */
|
||||
void test_merge_trees_trivial__6(void)
|
||||
{
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount(result) == 1);
|
||||
cl_assert(entry = git_index_get_bypath(result, "removed-in-both.txt", 1));
|
||||
|
||||
git_index_free(result);
|
||||
}
|
||||
|
||||
/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */
|
||||
void test_merge_trees_trivial__6_automerge(void)
|
||||
{
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
const git_index_reuc_entry *reuc;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", 1));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 1);
|
||||
@ -195,30 +176,12 @@ void test_merge_trees_trivial__6_automerge(void)
|
||||
|
||||
/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */
|
||||
void test_merge_trees_trivial__8(void)
|
||||
{
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount(result) == 2);
|
||||
cl_assert(entry = git_index_get_bypath(result, "removed-in-8.txt", 1));
|
||||
cl_assert(entry = git_index_get_bypath(result, "removed-in-8.txt", 3));
|
||||
|
||||
git_index_free(result);
|
||||
}
|
||||
|
||||
/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */
|
||||
void test_merge_trees_trivial__8_automerge(void)
|
||||
{
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
const git_index_reuc_entry *reuc;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", 1));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL);
|
||||
|
||||
@ -236,25 +199,7 @@ void test_merge_trees_trivial__7(void)
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount(result) == 2);
|
||||
cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 1));
|
||||
cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 3));
|
||||
|
||||
git_index_free(result);
|
||||
}
|
||||
|
||||
/* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */
|
||||
void test_merge_trees_trivial__7_automerge(void)
|
||||
{
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", 0));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
@ -268,30 +213,12 @@ void test_merge_trees_trivial__7_automerge(void)
|
||||
|
||||
/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */
|
||||
void test_merge_trees_trivial__10(void)
|
||||
{
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount(result) == 2);
|
||||
cl_assert(entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 1));
|
||||
cl_assert(entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 2));
|
||||
|
||||
git_index_free(result);
|
||||
}
|
||||
|
||||
/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */
|
||||
void test_merge_trees_trivial__10_automerge(void)
|
||||
{
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
const git_index_reuc_entry *reuc;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", 1));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL);
|
||||
|
||||
@ -309,25 +236,7 @@ void test_merge_trees_trivial__9(void)
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount(result) == 2);
|
||||
cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 1));
|
||||
cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 2));
|
||||
|
||||
git_index_free(result);
|
||||
}
|
||||
|
||||
/* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */
|
||||
void test_merge_trees_trivial__9_automerge(void)
|
||||
{
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", 1));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
@ -346,7 +255,7 @@ void test_merge_trees_trivial__13(void)
|
||||
const git_index_entry *entry;
|
||||
git_oid expected_oid;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch", 0));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(result, "modified-in-13.txt", 0));
|
||||
cl_git_pass(git_oid_fromstr(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b"));
|
||||
@ -365,7 +274,7 @@ void test_merge_trees_trivial__14(void)
|
||||
const git_index_entry *entry;
|
||||
git_oid expected_oid;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch", 0));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(result, "modified-in-14-branch.txt", 0));
|
||||
cl_git_pass(git_oid_fromstr(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9"));
|
||||
@ -383,7 +292,7 @@ void test_merge_trees_trivial__11(void)
|
||||
git_index *result;
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial(&result, "trivial-11", "trivial-11-branch", 0));
|
||||
cl_git_pass(merge_trivial(&result, "trivial-11", "trivial-11-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(result, "modified-in-both.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(result) == 0);
|
||||
|
@ -93,13 +93,26 @@ static git_index *repo_index;
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is changed in branch\r\n"
|
||||
|
||||
#define CONFLICTING_DIFF3_FILE \
|
||||
#define CONFLICTING_MERGE_FILE \
|
||||
"<<<<<<< HEAD\n" \
|
||||
"this file is changed in master and branch\n" \
|
||||
"=======\n" \
|
||||
"this file is changed in branch and master\n" \
|
||||
">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n"
|
||||
|
||||
#define CONFLICTING_DIFF3_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"
|
||||
|
||||
// Fixture setup and teardown
|
||||
void test_merge_workdir_simple__initialize(void)
|
||||
{
|
||||
@ -113,7 +126,7 @@ void test_merge_workdir_simple__cleanup(void)
|
||||
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_merge_head *their_heads[1];
|
||||
@ -123,7 +136,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_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;
|
||||
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts));
|
||||
|
||||
@ -244,7 +257,7 @@ void test_merge_workdir_simple__automerge_crlf(void)
|
||||
#endif /* GIT_WIN32 */
|
||||
}
|
||||
|
||||
void test_merge_workdir_simple__diff3(void)
|
||||
void test_merge_workdir_simple__mergefile(void)
|
||||
{
|
||||
git_merge_result *result;
|
||||
git_buf conflicting_buf = GIT_BUF_INIT;
|
||||
@ -271,6 +284,44 @@ void test_merge_workdir_simple__diff3(void)
|
||||
cl_assert(result = merge_simple_branch(0, 0));
|
||||
cl_assert(!git_merge_result_is_fastforward(result));
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&conflicting_buf,
|
||||
TEST_REPO_PATH "/conflicting.txt"));
|
||||
cl_assert(strcmp(conflicting_buf.ptr, CONFLICTING_MERGE_FILE) == 0);
|
||||
git_buf_free(&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_merge_result_free(result);
|
||||
}
|
||||
|
||||
void test_merge_workdir_simple__diff3(void)
|
||||
{
|
||||
git_merge_result *result;
|
||||
git_buf conflicting_buf = GIT_BUF_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_assert(result = merge_simple_branch(0, GIT_CHECKOUT_CONFLICT_STYLE_DIFF3));
|
||||
cl_assert(!git_merge_result_is_fastforward(result));
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&conflicting_buf,
|
||||
TEST_REPO_PATH "/conflicting.txt"));
|
||||
cl_assert(strcmp(conflicting_buf.ptr, CONFLICTING_DIFF3_FILE) == 0);
|
||||
@ -282,6 +333,131 @@ void test_merge_workdir_simple__diff3(void)
|
||||
git_merge_result_free(result);
|
||||
}
|
||||
|
||||
void test_merge_workdir_simple__union(void)
|
||||
{
|
||||
git_merge_result *result;
|
||||
git_buf conflicting_buf = GIT_BUF_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, "72cdb057b340205164478565e91eb71647e66891", 0, "conflicting.txt" },
|
||||
|
||||
UNCHANGED_INDEX_ENTRY,
|
||||
};
|
||||
|
||||
struct merge_reuc_entry merge_reuc_entries[] = {
|
||||
AUTOMERGEABLE_REUC_ENTRY,
|
||||
CONFLICTING_REUC_ENTRY,
|
||||
REMOVED_IN_BRANCH_REUC_ENTRY,
|
||||
REMOVED_IN_MASTER_REUC_ENTRY
|
||||
};
|
||||
|
||||
set_core_autocrlf_to(repo, false);
|
||||
|
||||
cl_assert(result = merge_simple_branch(GIT_MERGE_FILE_FAVOR_UNION, 0));
|
||||
cl_assert(!git_merge_result_is_fastforward(result));
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&conflicting_buf,
|
||||
TEST_REPO_PATH "/conflicting.txt"));
|
||||
cl_assert(strcmp(conflicting_buf.ptr, CONFLICTING_UNION_FILE) == 0);
|
||||
git_buf_free(&conflicting_buf);
|
||||
|
||||
cl_assert(merge_test_index(repo_index, merge_index_entries, 6));
|
||||
cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 4));
|
||||
|
||||
git_merge_result_free(result);
|
||||
}
|
||||
|
||||
void test_merge_workdir_simple__diff3_from_config(void)
|
||||
{
|
||||
git_merge_result *result;
|
||||
git_config *config;
|
||||
git_buf conflicting_buf = GIT_BUF_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", "diff3"));
|
||||
|
||||
cl_assert(result = merge_simple_branch(0, 0));
|
||||
cl_assert(!git_merge_result_is_fastforward(result));
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&conflicting_buf,
|
||||
TEST_REPO_PATH "/conflicting.txt"));
|
||||
cl_assert(strcmp(conflicting_buf.ptr, CONFLICTING_DIFF3_FILE) == 0);
|
||||
git_buf_free(&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_merge_result_free(result);
|
||||
git_config_free(config);
|
||||
}
|
||||
|
||||
void test_merge_workdir_simple__merge_overrides_config(void)
|
||||
{
|
||||
git_merge_result *result;
|
||||
git_config *config;
|
||||
git_buf conflicting_buf = GIT_BUF_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", "diff3"));
|
||||
|
||||
cl_assert(result = merge_simple_branch(0, GIT_CHECKOUT_CONFLICT_STYLE_MERGE));
|
||||
cl_assert(!git_merge_result_is_fastforward(result));
|
||||
|
||||
cl_git_pass(git_futils_readbuffer(&conflicting_buf,
|
||||
TEST_REPO_PATH "/conflicting.txt"));
|
||||
cl_assert(strcmp(conflicting_buf.ptr, CONFLICTING_MERGE_FILE) == 0);
|
||||
git_buf_free(&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_merge_result_free(result);
|
||||
git_config_free(config);
|
||||
}
|
||||
|
||||
void test_merge_workdir_simple__checkout_ours(void)
|
||||
{
|
||||
git_merge_result *result;
|
||||
@ -336,7 +512,7 @@ void test_merge_workdir_simple__favor_ours(void)
|
||||
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(merge_test_index(repo_index, merge_index_entries, 6));
|
||||
@ -365,7 +541,7 @@ void test_merge_workdir_simple__favor_theirs(void)
|
||||
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(merge_test_index(repo_index, merge_index_entries, 6));
|
||||
@ -414,7 +590,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_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_assert(merge_test_index(repo_index, merge_index_entries, 20));
|
||||
@ -447,7 +623,7 @@ void test_merge_workdir_simple__unrelated(void)
|
||||
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]));
|
||||
|
||||
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_assert(merge_test_index(repo_index, merge_index_entries, 9));
|
||||
@ -480,7 +656,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_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_assert(merge_test_index(repo_index, merge_index_entries, 11));
|
||||
@ -489,3 +665,40 @@ void test_merge_workdir_simple__unrelated_with_conflicts(void)
|
||||
git_merge_result_free(result);
|
||||
}
|
||||
|
||||
void test_merge_workdir_simple__binary(void)
|
||||
{
|
||||
git_oid our_oid, their_oid, our_file_oid;
|
||||
git_commit *our_commit;
|
||||
git_merge_head *their_head;
|
||||
git_merge_result *result;
|
||||
const git_index_entry *binary_entry;
|
||||
git_merge_opts opts = GIT_MERGE_OPTS_INIT;
|
||||
|
||||
struct merge_index_entry merge_index_entries[] = {
|
||||
{ 0100644, "1c51d885170f57a0c4e8c69ff6363d91a5b51f85", 1, "binary" },
|
||||
{ 0100644, "23ed141a6ae1e798b2f721afedbe947c119111ba", 2, "binary" },
|
||||
{ 0100644, "836b8b82b26cab22eaaed8820877c76d6c8bca19", 3, "binary" },
|
||||
};
|
||||
|
||||
cl_git_pass(git_oid_fromstr(&our_oid, "cc338e4710c9b257106b8d16d82f86458d5beaf1"));
|
||||
cl_git_pass(git_oid_fromstr(&their_oid, "ad01aebfdf2ac13145efafe3f9fcf798882f1730"));
|
||||
|
||||
cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid));
|
||||
cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD));
|
||||
|
||||
cl_git_pass(git_merge_head_from_oid(&their_head, repo, &their_oid));
|
||||
|
||||
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)&their_head, 1, &opts));
|
||||
|
||||
cl_assert(merge_test_index(repo_index, merge_index_entries, 3));
|
||||
|
||||
cl_git_pass(git_index_add_bypath(repo_index, "binary"));
|
||||
cl_assert((binary_entry = git_index_get_bypath(repo_index, "binary", 0)) != NULL);
|
||||
|
||||
cl_git_pass(git_oid_fromstr(&our_file_oid, "23ed141a6ae1e798b2f721afedbe947c119111ba"));
|
||||
cl_assert(git_oid_cmp(&binary_entry->oid, &our_file_oid) == 0);
|
||||
|
||||
git_merge_head_free(their_head);
|
||||
git_merge_result_free(result);
|
||||
git_commit_free(our_commit);
|
||||
}
|
||||
|
101
tests/merge/workdir/submodules.c
Normal file
101
tests/merge/workdir/submodules.c
Normal file
@ -0,0 +1,101 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "git2/repository.h"
|
||||
#include "git2/merge.h"
|
||||
#include "buffer.h"
|
||||
#include "merge.h"
|
||||
#include "../merge_helpers.h"
|
||||
|
||||
static git_repository *repo;
|
||||
|
||||
#define TEST_REPO_PATH "merge-resolve"
|
||||
|
||||
#define SUBMODULE_MAIN_BRANCH "submodules"
|
||||
#define SUBMODULE_OTHER_BRANCH "submodules-branch"
|
||||
#define SUBMODULE_OTHER2_BRANCH "submodules-branch2"
|
||||
|
||||
#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
|
||||
|
||||
// Fixture setup and teardown
|
||||
void test_merge_workdir_submodules__initialize(void)
|
||||
{
|
||||
repo = cl_git_sandbox_init(TEST_REPO_PATH);
|
||||
}
|
||||
|
||||
void test_merge_workdir_submodules__cleanup(void)
|
||||
{
|
||||
cl_git_sandbox_cleanup();
|
||||
}
|
||||
|
||||
void test_merge_workdir_submodules__automerge(void)
|
||||
{
|
||||
git_reference *our_ref, *their_ref;
|
||||
git_commit *our_commit;
|
||||
git_merge_head *their_head;
|
||||
git_merge_result *result;
|
||||
git_merge_opts opts = GIT_MERGE_OPTS_INIT;
|
||||
git_index *index;
|
||||
|
||||
struct merge_index_entry merge_index_entries[] = {
|
||||
{ 0100644, "caff6b7d44973f53e3e0cf31d0d695188b19aec6", 0, ".gitmodules" },
|
||||
{ 0100644, "950a663a6a7b2609eed1ed1ba9f41eb1a3192a9f", 0, "file1.txt" },
|
||||
{ 0100644, "343e660b9cb4bee5f407c2e33fcb9df24d9407a4", 0, "file2.txt" },
|
||||
{ 0160000, "d3d806a4bef96889117fd7ebac0e3cb5ec152932", 1, "submodule" },
|
||||
{ 0160000, "297aa6cd028b3336c7802c7a6f49143da4e1602d", 2, "submodule" },
|
||||
{ 0160000, "ae39c77c70cb6bad18bb471912460c4e1ba0f586", 3, "submodule" },
|
||||
};
|
||||
|
||||
cl_git_pass(git_reference_lookup(&our_ref, repo, "refs/heads/" SUBMODULE_MAIN_BRANCH));
|
||||
cl_git_pass(git_commit_lookup(&our_commit, repo, git_reference_target(our_ref)));
|
||||
cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD));
|
||||
|
||||
cl_git_pass(git_reference_lookup(&their_ref, repo, "refs/heads/" SUBMODULE_OTHER_BRANCH));
|
||||
cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref));
|
||||
|
||||
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)&their_head, 1, &opts));
|
||||
|
||||
cl_git_pass(git_repository_index(&index, repo));
|
||||
cl_assert(merge_test_index(index, merge_index_entries, 6));
|
||||
|
||||
git_index_free(index);
|
||||
git_merge_result_free(result);
|
||||
git_merge_head_free(their_head);
|
||||
git_commit_free(our_commit);
|
||||
git_reference_free(their_ref);
|
||||
git_reference_free(our_ref);
|
||||
}
|
||||
|
||||
void test_merge_workdir_submodules__take_changed(void)
|
||||
{
|
||||
git_reference *our_ref, *their_ref;
|
||||
git_commit *our_commit;
|
||||
git_merge_head *their_head;
|
||||
git_merge_result *result;
|
||||
git_merge_opts opts = GIT_MERGE_OPTS_INIT;
|
||||
git_index *index;
|
||||
|
||||
struct merge_index_entry merge_index_entries[] = {
|
||||
{ 0100644, "caff6b7d44973f53e3e0cf31d0d695188b19aec6", 0, ".gitmodules" },
|
||||
{ 0100644, "b438ff23300b2e0f80b84a6f30140dfa91e71423", 0, "file1.txt" },
|
||||
{ 0100644, "f27fbafdfa6693f8f7a5128506fe3e338dbfcad2", 0, "file2.txt" },
|
||||
{ 0160000, "297aa6cd028b3336c7802c7a6f49143da4e1602d", 0, "submodule" },
|
||||
};
|
||||
|
||||
cl_git_pass(git_reference_lookup(&our_ref, repo, "refs/heads/" SUBMODULE_MAIN_BRANCH));
|
||||
cl_git_pass(git_commit_lookup(&our_commit, repo, git_reference_target(our_ref)));
|
||||
cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD));
|
||||
|
||||
cl_git_pass(git_reference_lookup(&their_ref, repo, "refs/heads/" SUBMODULE_OTHER2_BRANCH));
|
||||
cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref));
|
||||
|
||||
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)&their_head, 1, &opts));
|
||||
|
||||
cl_git_pass(git_repository_index(&index, repo));
|
||||
cl_assert(merge_test_index(index, merge_index_entries, 4));
|
||||
|
||||
git_index_free(index);
|
||||
git_merge_result_free(result);
|
||||
git_merge_head_free(their_head);
|
||||
git_commit_free(our_commit);
|
||||
git_reference_free(their_ref);
|
||||
git_reference_free(our_ref);
|
||||
}
|
@ -28,7 +28,7 @@ void test_merge_workdir_trivial__cleanup(void)
|
||||
}
|
||||
|
||||
|
||||
static int merge_trivial(const char *ours, const char *theirs, bool automerge)
|
||||
static int merge_trivial(const char *ours, const char *theirs)
|
||||
{
|
||||
git_buf branch_buf = GIT_BUF_INIT;
|
||||
git_checkout_opts checkout_opts = GIT_CHECKOUT_OPTS_INIT;
|
||||
@ -39,8 +39,6 @@ static int merge_trivial(const char *ours, const char *theirs, bool automerge)
|
||||
|
||||
checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
|
||||
opts.merge_tree_opts.automerge_flags |= automerge ? 0 : GIT_MERGE_AUTOMERGE_NONE;
|
||||
|
||||
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));
|
||||
|
||||
@ -83,7 +81,7 @@ void test_merge_workdir_trivial__2alt(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-2alt", "trivial-2alt-branch", 0));
|
||||
cl_git_pass(merge_trivial("trivial-2alt", "trivial-2alt-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "new-in-branch.txt", 0));
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
@ -95,7 +93,7 @@ void test_merge_workdir_trivial__3alt(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-3alt", "trivial-3alt-branch", 0));
|
||||
cl_git_pass(merge_trivial("trivial-3alt", "trivial-3alt-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "new-in-3alt.txt", 0));
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
@ -107,7 +105,7 @@ void test_merge_workdir_trivial__4(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-4", "trivial-4-branch", 0));
|
||||
cl_git_pass(merge_trivial("trivial-4", "trivial-4-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "new-and-different.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
@ -122,7 +120,7 @@ void test_merge_workdir_trivial__5alt_1(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-5alt-1", "trivial-5alt-1-branch", 0));
|
||||
cl_git_pass(merge_trivial("trivial-5alt-1", "trivial-5alt-1-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "new-and-same.txt", 0));
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
@ -134,7 +132,7 @@ void test_merge_workdir_trivial__5alt_2(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-5alt-2", "trivial-5alt-2-branch", 0));
|
||||
cl_git_pass(merge_trivial("trivial-5alt-2", "trivial-5alt-2-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "modified-to-same.txt", 0));
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
@ -143,25 +141,11 @@ void test_merge_workdir_trivial__5alt_2(void)
|
||||
|
||||
/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */
|
||||
void test_merge_workdir_trivial__6(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-6", "trivial-6-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-both.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount() == 1);
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-both.txt", 1));
|
||||
}
|
||||
|
||||
/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */
|
||||
void test_merge_workdir_trivial__6_automerge(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
const git_index_reuc_entry *reuc;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-6", "trivial-6-branch", 1));
|
||||
cl_git_pass(merge_trivial("trivial-6", "trivial-6-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-both.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 1);
|
||||
@ -172,26 +156,11 @@ void test_merge_workdir_trivial__6_automerge(void)
|
||||
|
||||
/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */
|
||||
void test_merge_workdir_trivial__8(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-8", "trivial-8-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-8.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount() == 2);
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-8.txt", 1));
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-8.txt", 3));
|
||||
}
|
||||
|
||||
/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */
|
||||
void test_merge_workdir_trivial__8_automerge(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
const git_index_reuc_entry *reuc;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-8", "trivial-8-branch", 1));
|
||||
cl_git_pass(merge_trivial("trivial-8", "trivial-8-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-8.txt", 0)) == NULL);
|
||||
|
||||
@ -206,22 +175,7 @@ void test_merge_workdir_trivial__7(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-7", "trivial-7-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount() == 2);
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 1));
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 3));
|
||||
}
|
||||
|
||||
/* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */
|
||||
void test_merge_workdir_trivial__7_automerge(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-7", "trivial-7-branch", 0));
|
||||
cl_git_pass(merge_trivial("trivial-7", "trivial-7-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
@ -233,26 +187,11 @@ void test_merge_workdir_trivial__7_automerge(void)
|
||||
|
||||
/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */
|
||||
void test_merge_workdir_trivial__10(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-10", "trivial-10-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-10-branch.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount() == 2);
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-10-branch.txt", 1));
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-10-branch.txt", 2));
|
||||
}
|
||||
|
||||
/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */
|
||||
void test_merge_workdir_trivial__10_automerge(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
const git_index_reuc_entry *reuc;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-10", "trivial-10-branch", 1));
|
||||
cl_git_pass(merge_trivial("trivial-10", "trivial-10-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-10-branch.txt", 0)) == NULL);
|
||||
|
||||
@ -267,22 +206,7 @@ void test_merge_workdir_trivial__9(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-9", "trivial-9-branch", 0));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
|
||||
cl_assert(merge_trivial_conflict_entrycount() == 2);
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 1));
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 2));
|
||||
}
|
||||
|
||||
/* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */
|
||||
void test_merge_workdir_trivial__9_automerge(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-9", "trivial-9-branch", 1));
|
||||
cl_git_pass(merge_trivial("trivial-9", "trivial-9-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
@ -298,7 +222,7 @@ void test_merge_workdir_trivial__13(void)
|
||||
const git_index_entry *entry;
|
||||
git_oid expected_oid;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-13", "trivial-13-branch", 0));
|
||||
cl_git_pass(merge_trivial("trivial-13", "trivial-13-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "modified-in-13.txt", 0));
|
||||
cl_git_pass(git_oid_fromstr(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b"));
|
||||
@ -314,7 +238,7 @@ void test_merge_workdir_trivial__14(void)
|
||||
const git_index_entry *entry;
|
||||
git_oid expected_oid;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-14", "trivial-14-branch", 0));
|
||||
cl_git_pass(merge_trivial("trivial-14", "trivial-14-branch"));
|
||||
|
||||
cl_assert(entry = git_index_get_bypath(repo_index, "modified-in-14-branch.txt", 0));
|
||||
cl_git_pass(git_oid_fromstr(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9"));
|
||||
@ -329,7 +253,7 @@ void test_merge_workdir_trivial__11(void)
|
||||
{
|
||||
const git_index_entry *entry;
|
||||
|
||||
cl_git_pass(merge_trivial("trivial-11", "trivial-11-branch", 0));
|
||||
cl_git_pass(merge_trivial("trivial-11", "trivial-11-branch"));
|
||||
|
||||
cl_assert((entry = git_index_get_bypath(repo_index, "modified-in-both.txt", 0)) == NULL);
|
||||
cl_assert(git_index_reuc_entrycount(repo_index) == 0);
|
||||
|
Binary file not shown.
BIN
tests/resources/merge-resolve/.gitted/modules/submodule/HEAD
Normal file
BIN
tests/resources/merge-resolve/.gitted/modules/submodule/HEAD
Normal file
Binary file not shown.
Binary file not shown.
BIN
tests/resources/merge-resolve/.gitted/modules/submodule/config
Normal file
BIN
tests/resources/merge-resolve/.gitted/modules/submodule/config
Normal file
Binary file not shown.
BIN
tests/resources/merge-resolve/.gitted/modules/submodule/index
Normal file
BIN
tests/resources/merge-resolve/.gitted/modules/submodule/index
Normal file
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.
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tests/resources/merge-resolve/.gitted/refs/heads/submodules
Normal file
BIN
tests/resources/merge-resolve/.gitted/refs/heads/submodules
Normal file
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.
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 revert --no-commit d1d403d22cbe24592d725f442835cf46fe60c8ac */
|
||||
void test_revert_workdir__conflict_use_ours(void)
|
||||
@ -146,22 +343,19 @@ void test_revert_workdir__conflict_use_ours(void)
|
||||
git_revert_opts opts = GIT_REVERT_OPTS_INIT;
|
||||
|
||||
struct merge_index_entry merge_index_entries[] = {
|
||||
{ 0100644, "3a3ef367eaf3fe79effbfb0a56b269c04c2b59fe", 1, "file1.txt" },
|
||||
{ 0100644, "7731926a337c4eaba1e2187d90ebfa0a93659382", 2, "file1.txt" },
|
||||
{ 0100644, "747726e021bc5f44b86de60e3032fd6f9f1b8383", 3, "file1.txt" },
|
||||
{ 0100644, "caf99de3a49827117bb66721010eac461b06a80c", 0, "file1.txt" },
|
||||
{ 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" },
|
||||
{ 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" },
|
||||
{ 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" },
|
||||
};
|
||||
|
||||
struct merge_index_entry merge_filesystem_entries[] = {
|
||||
{ 0100644, "7731926a337c4eaba1e2187d90ebfa0a93659382", 0, "file1.txt" },
|
||||
{ 0100644, "caf99de3a49827117bb66721010eac461b06a80c", 0, "file1.txt" },
|
||||
{ 0100644, "0ab09ea6d4c3634bdf6c221626d8b6f7dd890767", 0, "file2.txt" },
|
||||
{ 0100644, "f4e107c230d08a60fb419d19869f1f282b272d9c", 0, "file3.txt" },
|
||||
{ 0100644, "0f5bfcf58c558d865da6be0281d7795993646cee", 0, "file6.txt" },
|
||||
};
|
||||
|
||||
opts.merge_tree_opts.automerge_flags = GIT_MERGE_AUTOMERGE_NONE;
|
||||
opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS;
|
||||
|
||||
git_oid_fromstr(&head_oid, "72333f47d4e83616630ff3b0ffe4c0faebcc3c45");
|
||||
@ -172,7 +366,7 @@ void test_revert_workdir__conflict_use_ours(void)
|
||||
cl_git_pass(git_commit_lookup(&commit, repo, &revert_oid));
|
||||
cl_git_pass(git_revert(repo, commit, &opts));
|
||||
|
||||
cl_assert(merge_test_index(repo_index, merge_index_entries, 6));
|
||||
cl_assert(merge_test_index(repo_index, merge_index_entries, 4));
|
||||
cl_assert(merge_test_workdir(repo, merge_filesystem_entries, 4));
|
||||
|
||||
git_commit_free(commit);
|
||||
|
Loading…
Reference in New Issue
Block a user