mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-21 12:24:58 +00:00
Introduce git_merge_file for consumers
This commit is contained in:
parent
f29e48995e
commit
05d47768ca
@ -22,6 +22,43 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* The file inputs to `git_merge_file`. Callers should populate the
|
||||
* `git_merge_file_input` structure with descriptions of the files in
|
||||
* each side of the conflict for use in producing the merge file.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
|
||||
/** Pointer to the contents of the file. */
|
||||
const char *ptr;
|
||||
|
||||
/** Size of the contents pointed to in `ptr`. */
|
||||
size_t size;
|
||||
|
||||
/** File name of the conflicted file, or `NULL` to not merge the path. */
|
||||
const char *path;
|
||||
|
||||
/** File mode of the conflicted file, or `0` to not merge the mode. */
|
||||
unsigned int mode;
|
||||
} git_merge_file_input;
|
||||
|
||||
#define GIT_MERGE_FILE_INPUT_VERSION 1
|
||||
#define GIT_MERGE_FILE_INPUT_INIT {GIT_MERGE_FILE_INPUT_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_merge_file_input` with default values. Equivalent to
|
||||
* creating an instance with GIT_MERGE_FILE_INPUT_INIT.
|
||||
*
|
||||
* @param opts the `git_merge_file_input` instance to initialize.
|
||||
* @param version the version of the struct; you should pass
|
||||
* `GIT_MERGE_FILE_INPUT_VERSION` here.
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_file_init_input(
|
||||
git_merge_file_input *opts,
|
||||
int version);
|
||||
|
||||
/**
|
||||
* Flags for `git_merge_tree` options. A combination of these flags can be
|
||||
* passed in via the `flags` value in the `git_merge_tree_opts`.
|
||||
@ -71,6 +108,86 @@ typedef enum {
|
||||
GIT_MERGE_FILE_FAVOR_UNION = 3,
|
||||
} git_merge_file_favor_t;
|
||||
|
||||
typedef enum {
|
||||
/* Defaults */
|
||||
GIT_MERGE_FILE_DEFAULT = 0,
|
||||
|
||||
/* Create standard conflicted merge files */
|
||||
GIT_MERGE_FILE_STYLE_MERGE = (1 << 0),
|
||||
|
||||
/* Create diff3-style files */
|
||||
GIT_MERGE_FILE_STYLE_DIFF3 = (1 << 1),
|
||||
|
||||
/* Condense non-alphanumeric regions for simplified diff file */
|
||||
GIT_MERGE_FILE_SIMPLIFY_ALNUM = (1 << 2),
|
||||
} git_merge_file_flags_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
|
||||
/**
|
||||
* Label for the ancestor file side of the conflict which will be prepended
|
||||
* to labels in diff3-format merge files.
|
||||
*/
|
||||
const char *ancestor_label;
|
||||
|
||||
/**
|
||||
* Label for our file side of the conflict which will be prepended
|
||||
* to labels in merge files.
|
||||
*/
|
||||
const char *our_label;
|
||||
|
||||
/**
|
||||
* Label for their file side of the conflict which will be prepended
|
||||
* to labels in merge files.
|
||||
*/
|
||||
const char *their_label;
|
||||
|
||||
/** The file to favor in region conflicts. */
|
||||
git_merge_file_favor_t favor;
|
||||
|
||||
/** Merge file flags. */
|
||||
git_merge_file_flags_t flags;
|
||||
} git_merge_file_options;
|
||||
|
||||
#define GIT_MERGE_FILE_OPTIONS_VERSION 1
|
||||
#define GIT_MERGE_FILE_OPTIONS_INIT {GIT_MERGE_FILE_OPTIONS_VERSION}
|
||||
|
||||
/**
|
||||
* Initializes a `git_merge_file_options` with default values. Equivalent to
|
||||
* creating an instance with GIT_MERGE_FILE_OPTIONS_INIT.
|
||||
*
|
||||
* @param opts the `git_merge_file_options` instance to initialize.
|
||||
* @param version the version of the struct; you should pass
|
||||
* `GIT_MERGE_FILE_OPTIONS_VERSION` here.
|
||||
* @return Zero on success; -1 on failure.
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_file_init_options(
|
||||
git_merge_file_options *opts,
|
||||
int version);
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* True if the output was automerged, false if the output contains
|
||||
* conflict markers.
|
||||
*/
|
||||
unsigned int automergeable;
|
||||
|
||||
/**
|
||||
* The path that the resultant merge file should use, or NULL if a
|
||||
* filename conflict would occur.
|
||||
*/
|
||||
char *path;
|
||||
|
||||
/** The mode that the resultant merge file should use. */
|
||||
unsigned int mode;
|
||||
|
||||
/** The contents of the merge. */
|
||||
unsigned char *ptr;
|
||||
|
||||
/** The length of the merge contents. */
|
||||
size_t len;
|
||||
} git_merge_file_result;
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
@ -268,6 +385,58 @@ GIT_EXTERN(int) git_merge_head_from_id(
|
||||
GIT_EXTERN(void) git_merge_head_free(
|
||||
git_merge_head *head);
|
||||
|
||||
/**
|
||||
* Merge two files as they exist in the in-memory data structures, using
|
||||
* the given common ancestor as the baseline, producing a
|
||||
* `git_merge_file_result` that reflects the merge result. The
|
||||
* `git_merge_file_result` must be freed with `git_merge_file_result_free`.
|
||||
*
|
||||
* Note that this function does not reference a repository and any
|
||||
* configuration must be passed as `git_merge_file_options`.
|
||||
*
|
||||
* @param out The git_merge_file_result to be filled in
|
||||
* @param ancestor The contents of the ancestor file
|
||||
* @param ours The contents of the file in "our" side
|
||||
* @param theirs The contents of the file in "their" side
|
||||
* @param opts The merge file options or `NULL` for defaults
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_file(
|
||||
git_merge_file_result *out,
|
||||
const git_merge_file_input *ancestor,
|
||||
const git_merge_file_input *ours,
|
||||
const git_merge_file_input *theirs,
|
||||
const git_merge_file_options *opts);
|
||||
|
||||
/**
|
||||
* Merge two files as they exist in the index, using the given common
|
||||
* ancestor as the baseline, producing a `git_merge_file_result` that
|
||||
* reflects the merge result. The `git_merge_file_result` must be freed with
|
||||
* `git_merge_file_result_free`.
|
||||
*
|
||||
* @param out The git_merge_file_result to be filled in
|
||||
* @param repo The repository
|
||||
* @param ancestor The index entry for the ancestor file (stage level 1)
|
||||
* @param our_path The index entry for our file (stage level 2)
|
||||
* @param their_path The index entry for their file (stage level 3)
|
||||
* @param opts The merge file options or NULL
|
||||
* @return 0 on success or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_merge_file_from_index(
|
||||
git_merge_file_result *out,
|
||||
git_repository *repo,
|
||||
const git_index_entry *ancestor,
|
||||
const git_index_entry *ours,
|
||||
const git_index_entry *theirs,
|
||||
const git_merge_file_options *opts);
|
||||
|
||||
/**
|
||||
* Frees a `git_merge_file_result`.
|
||||
*
|
||||
* @param result The result to free or `NULL`
|
||||
*/
|
||||
GIT_EXTERN(void) git_merge_file_result_free(git_merge_file_result *result);
|
||||
|
||||
/**
|
||||
* Merge two trees, producing a `git_index` that reflects the result of
|
||||
* the merge. The index may be written as-is to the working directory
|
||||
|
@ -1681,29 +1681,20 @@ 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;
|
||||
git_merge_file_result result = GIT_MERGE_FILE_RESULT_INIT;
|
||||
git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
|
||||
git_merge_file_result result = {0};
|
||||
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;
|
||||
opts.flags |= GIT_MERGE_FILE_STYLE_DIFF3;
|
||||
|
||||
if ((conflict->ancestor &&
|
||||
(error = git_merge_file_input_from_index_entry(
|
||||
&ancestor, data->repo, conflict->ancestor)) < 0) ||
|
||||
(error = git_merge_file_input_from_index_entry(
|
||||
&ours, data->repo, conflict->ours)) < 0 ||
|
||||
(error = git_merge_file_input_from_index_entry(
|
||||
&theirs, data->repo, conflict->theirs)) < 0)
|
||||
goto done;
|
||||
|
||||
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";
|
||||
opts.ancestor_label = data->opts.ancestor_label ?
|
||||
data->opts.ancestor_label : "ancestor";
|
||||
opts.our_label = data->opts.our_label ?
|
||||
data->opts.our_label : "ours";
|
||||
opts.their_label = data->opts.their_label ?
|
||||
data->opts.their_label : "theirs";
|
||||
|
||||
/* If all the paths are identical, decorate the diff3 file with the branch
|
||||
* names. Otherwise, append branch_name:path.
|
||||
@ -1712,16 +1703,17 @@ static int checkout_write_merge(
|
||||
strcmp(conflict->ours->path, conflict->theirs->path) != 0) {
|
||||
|
||||
if ((error = conflict_entry_name(
|
||||
&our_label, ours.label, conflict->ours->path)) < 0 ||
|
||||
&our_label, opts.our_label, conflict->ours->path)) < 0 ||
|
||||
(error = conflict_entry_name(
|
||||
&their_label, theirs.label, conflict->theirs->path)) < 0)
|
||||
&their_label, opts.their_label, conflict->theirs->path)) < 0)
|
||||
goto done;
|
||||
|
||||
ours.label = git_buf_cstr(&our_label);
|
||||
theirs.label = git_buf_cstr(&their_label);
|
||||
opts.our_label = git_buf_cstr(&our_label);
|
||||
opts.their_label = git_buf_cstr(&their_label);
|
||||
}
|
||||
|
||||
if ((error = git_merge_files(&result, &ancestor, &ours, &theirs, &merge_file_opts)) < 0)
|
||||
if ((error = git_merge_file_from_index(&result, data->repo,
|
||||
conflict->ancestor, conflict->ours, conflict->theirs, &opts)) < 0)
|
||||
goto done;
|
||||
|
||||
if (result.path == NULL || result.mode == 0) {
|
||||
@ -1739,7 +1731,7 @@ static int checkout_write_merge(
|
||||
|
||||
if ((error = git_futils_mkpath2file(path_workdir.ptr, 0755)) < 0 ||
|
||||
(error = git_filebuf_open(&output, path_workdir.ptr, GIT_FILEBUF_DO_NOT_BUFFER, result.mode)) < 0 ||
|
||||
(error = git_filebuf_write(&output, result.data, result.len)) < 0 ||
|
||||
(error = git_filebuf_write(&output, result.ptr, result.len)) < 0 ||
|
||||
(error = git_filebuf_commit(&output)) < 0)
|
||||
goto done;
|
||||
|
||||
@ -1747,9 +1739,6 @@ done:
|
||||
git_buf_free(&our_label);
|
||||
git_buf_free(&their_label);
|
||||
|
||||
git_merge_file_input_free(&ancestor);
|
||||
git_merge_file_input_free(&ours);
|
||||
git_merge_file_input_free(&theirs);
|
||||
git_merge_file_result_free(&result);
|
||||
git_buf_free(&path_workdir);
|
||||
git_buf_free(&path_suffixed);
|
||||
|
@ -300,7 +300,7 @@ static void index_entry_free(git_index_entry *entry)
|
||||
git__free(entry);
|
||||
}
|
||||
|
||||
static unsigned int index_create_mode(unsigned int mode)
|
||||
unsigned int git_index__create_mode(unsigned int mode)
|
||||
{
|
||||
if (S_ISLNK(mode))
|
||||
return S_IFLNK;
|
||||
@ -320,9 +320,9 @@ static unsigned int index_merge_mode(
|
||||
|
||||
if (index->distrust_filemode && S_ISREG(mode))
|
||||
return (existing && S_ISREG(existing->mode)) ?
|
||||
existing->mode : index_create_mode(0666);
|
||||
existing->mode : git_index__create_mode(0666);
|
||||
|
||||
return index_create_mode(mode);
|
||||
return git_index__create_mode(mode);
|
||||
}
|
||||
|
||||
void git_index__set_ignore_case(git_index *index, bool ignore_case)
|
||||
@ -619,7 +619,7 @@ void git_index_entry__init_from_stat(
|
||||
entry->dev = st->st_rdev;
|
||||
entry->ino = st->st_ino;
|
||||
entry->mode = (!trust_mode && S_ISREG(st->st_mode)) ?
|
||||
index_create_mode(0666) : index_create_mode(st->st_mode);
|
||||
git_index__create_mode(0666) : git_index__create_mode(st->st_mode);
|
||||
entry->uid = st->st_uid;
|
||||
entry->gid = st->st_gid;
|
||||
entry->file_size = st->st_size;
|
||||
|
@ -60,4 +60,6 @@ extern int git_index__find(
|
||||
|
||||
extern void git_index__set_ignore_case(git_index *index, bool ignore_case);
|
||||
|
||||
extern unsigned int git_index__create_mode(unsigned int mode);
|
||||
|
||||
#endif
|
||||
|
55
src/merge.c
55
src/merge.c
@ -539,11 +539,9 @@ static int merge_conflict_resolve_automerge(
|
||||
const git_merge_diff *conflict,
|
||||
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;
|
||||
git_merge_file_result result = GIT_MERGE_FILE_RESULT_INIT;
|
||||
const git_index_entry *ancestor = NULL, *ours = NULL, *theirs = NULL;
|
||||
git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT;
|
||||
git_merge_file_result result = {0};
|
||||
git_index_entry *index_entry;
|
||||
git_odb *odb = NULL;
|
||||
git_oid automerge_oid;
|
||||
@ -553,7 +551,9 @@ static int merge_conflict_resolve_automerge(
|
||||
|
||||
*resolved = 0;
|
||||
|
||||
merge_file_opts.favor = merge_file_favor;
|
||||
if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ||
|
||||
!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry))
|
||||
return 0;
|
||||
|
||||
/* Reject D/F conflicts */
|
||||
if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE)
|
||||
@ -584,13 +584,19 @@ static int merge_conflict_resolve_automerge(
|
||||
if (conflict->binary)
|
||||
return 0;
|
||||
|
||||
ancestor = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ?
|
||||
&conflict->ancestor_entry : NULL;
|
||||
ours = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ?
|
||||
&conflict->our_entry : NULL;
|
||||
theirs = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ?
|
||||
&conflict->their_entry : NULL;
|
||||
|
||||
opts.favor = merge_file_favor;
|
||||
|
||||
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, &merge_file_opts)) < 0 ||
|
||||
(error = git_merge_file_from_index(&result, diff_list->repo, ancestor, ours, theirs, &opts)) < 0 ||
|
||||
!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.ptr, result.len, GIT_OBJ_BLOB)) < 0)
|
||||
goto done;
|
||||
|
||||
if ((index_entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL)
|
||||
@ -609,9 +615,6 @@ static int merge_conflict_resolve_automerge(
|
||||
*resolved = 1;
|
||||
|
||||
done:
|
||||
git_merge_file_input_free(&ancestor);
|
||||
git_merge_file_input_free(&ours);
|
||||
git_merge_file_input_free(&theirs);
|
||||
git_merge_file_result_free(&result);
|
||||
git_odb_free(odb);
|
||||
|
||||
@ -2793,3 +2796,27 @@ int git_merge_tree_init_opts(git_merge_tree_opts* opts, int version)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int git_merge_file_init_input(git_merge_file_input *input, int version)
|
||||
{
|
||||
if (version != GIT_MERGE_FILE_INPUT_VERSION) {
|
||||
giterr_set(GITERR_INVALID, "Invalid version %d for git_merge_file_input", version);
|
||||
return -1;
|
||||
} else {
|
||||
git_merge_file_input i = GIT_MERGE_FILE_INPUT_INIT;
|
||||
memcpy(input, &i, sizeof(i));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int git_merge_file_init_options(git_merge_file_options *opts, int version)
|
||||
{
|
||||
if (version != GIT_MERGE_FILE_OPTIONS_VERSION) {
|
||||
giterr_set(GITERR_INVALID, "Invalid version %d for git_merge_file_options", version);
|
||||
return -1;
|
||||
} else {
|
||||
git_merge_file_options o = GIT_MERGE_FILE_OPTIONS_INIT;
|
||||
memcpy(opts, &o, sizeof(o));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
261
src/merge_file.c
261
src/merge_file.c
@ -8,6 +8,9 @@
|
||||
#include "common.h"
|
||||
#include "repository.h"
|
||||
#include "merge_file.h"
|
||||
#include "posix.h"
|
||||
#include "fileops.h"
|
||||
#include "index.h"
|
||||
|
||||
#include "git2/repository.h"
|
||||
#include "git2/object.h"
|
||||
@ -22,17 +25,17 @@ GIT_INLINE(const char *) merge_file_best_path(
|
||||
const git_merge_file_input *ours,
|
||||
const git_merge_file_input *theirs)
|
||||
{
|
||||
if (!GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) {
|
||||
if (strcmp(ours->path, theirs->path) == 0)
|
||||
if (!ancestor) {
|
||||
if (ours && theirs && strcmp(ours->path, theirs->path) == 0)
|
||||
return ours->path;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(ancestor->path, ours->path) == 0)
|
||||
return theirs->path;
|
||||
else if(strcmp(ancestor->path, theirs->path) == 0)
|
||||
return ours->path;
|
||||
if (ours && strcmp(ancestor->path, ours->path) == 0)
|
||||
return theirs ? theirs->path : NULL;
|
||||
else if(theirs && strcmp(ancestor->path, theirs->path) == 0)
|
||||
return ours ? ours->path : NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -47,136 +50,230 @@ GIT_INLINE(int) merge_file_best_mode(
|
||||
* assume executable. Otherwise, if any mode changed from the ancestor,
|
||||
* use that one.
|
||||
*/
|
||||
if (!GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) {
|
||||
if (ours->mode == GIT_FILEMODE_BLOB_EXECUTABLE ||
|
||||
theirs->mode == GIT_FILEMODE_BLOB_EXECUTABLE)
|
||||
if (!ancestor) {
|
||||
if ((ours && ours->mode == GIT_FILEMODE_BLOB_EXECUTABLE) ||
|
||||
(theirs && theirs->mode == GIT_FILEMODE_BLOB_EXECUTABLE))
|
||||
return GIT_FILEMODE_BLOB_EXECUTABLE;
|
||||
|
||||
return GIT_FILEMODE_BLOB;
|
||||
}
|
||||
|
||||
} else if (ours && theirs) {
|
||||
if (ancestor->mode == ours->mode)
|
||||
return theirs->mode;
|
||||
else if(ancestor->mode == theirs->mode)
|
||||
|
||||
return ours->mode;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_merge_file_input_from_index_entry(
|
||||
git_merge_file_input *input,
|
||||
git_repository *repo,
|
||||
int git_merge_file__input_from_index(
|
||||
git_merge_file_input *input_out,
|
||||
git_odb_object **odb_object_out,
|
||||
git_odb *odb,
|
||||
const git_index_entry *entry)
|
||||
{
|
||||
git_odb *odb = NULL;
|
||||
int error = 0;
|
||||
|
||||
assert(input && repo && entry);
|
||||
assert(input_out && odb_object_out && odb && entry);
|
||||
|
||||
if (entry->mode == 0)
|
||||
return 0;
|
||||
|
||||
if ((error = git_repository_odb(&odb, repo)) < 0 ||
|
||||
(error = git_odb_read(&input->odb_object, odb, &entry->id)) < 0)
|
||||
if ((error = git_odb_read(odb_object_out, odb, &entry->id)) < 0)
|
||||
goto done;
|
||||
|
||||
input->mode = entry->mode;
|
||||
input->path = git__strdup(entry->path);
|
||||
input->mmfile.size = git_odb_object_size(input->odb_object);
|
||||
input->mmfile.ptr = (char *)git_odb_object_data(input->odb_object);
|
||||
|
||||
if (input->label == NULL)
|
||||
input->label = entry->path;
|
||||
input_out->path = entry->path;
|
||||
input_out->mode = entry->mode;
|
||||
input_out->ptr = (char *)git_odb_object_data(*odb_object_out);
|
||||
input_out->size = git_odb_object_size(*odb_object_out);
|
||||
|
||||
done:
|
||||
git_odb_free(odb);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_merge_file_input_from_diff_file(
|
||||
git_merge_file_input *input,
|
||||
git_repository *repo,
|
||||
const git_diff_file *file)
|
||||
static void merge_file_normalize_opts(
|
||||
git_merge_file_options *out,
|
||||
const git_merge_file_options *given_opts)
|
||||
{
|
||||
git_odb *odb = NULL;
|
||||
int error = 0;
|
||||
|
||||
assert(input && repo && file);
|
||||
|
||||
if (file->mode == 0)
|
||||
return 0;
|
||||
|
||||
if ((error = git_repository_odb(&odb, repo)) < 0 ||
|
||||
(error = git_odb_read(&input->odb_object, odb, &file->id)) < 0)
|
||||
goto done;
|
||||
|
||||
input->mode = file->mode;
|
||||
input->path = git__strdup(file->path);
|
||||
input->mmfile.size = git_odb_object_size(input->odb_object);
|
||||
input->mmfile.ptr = (char *)git_odb_object_data(input->odb_object);
|
||||
|
||||
if (input->label == NULL)
|
||||
input->label = file->path;
|
||||
|
||||
done:
|
||||
git_odb_free(odb);
|
||||
|
||||
return error;
|
||||
if (given_opts)
|
||||
memcpy(out, given_opts, sizeof(git_merge_file_options));
|
||||
else {
|
||||
git_merge_file_options default_opts = GIT_MERGE_FILE_OPTIONS_INIT;
|
||||
memcpy(out, &default_opts, sizeof(git_merge_file_options));
|
||||
}
|
||||
}
|
||||
|
||||
int git_merge_files(
|
||||
static int git_merge_file__from_inputs(
|
||||
git_merge_file_result *out,
|
||||
git_merge_file_input *ancestor,
|
||||
git_merge_file_input *ours,
|
||||
git_merge_file_input *theirs,
|
||||
git_merge_file_options *opts)
|
||||
const git_merge_file_input *ancestor,
|
||||
const git_merge_file_input *ours,
|
||||
const git_merge_file_input *theirs,
|
||||
const git_merge_file_options *given_opts)
|
||||
{
|
||||
xmparam_t xmparam;
|
||||
mmfile_t ancestor_mmfile = {0}, our_mmfile = {0}, their_mmfile = {0};
|
||||
mmbuffer_t mmbuffer;
|
||||
git_merge_file_options options = GIT_MERGE_FILE_OPTIONS_INIT;
|
||||
const char *path;
|
||||
int xdl_result;
|
||||
int error = 0;
|
||||
|
||||
assert(out && ancestor && ours && theirs);
|
||||
|
||||
memset(out, 0x0, sizeof(git_merge_file_result));
|
||||
|
||||
if (!GIT_MERGE_FILE_SIDE_EXISTS(ours) || !GIT_MERGE_FILE_SIDE_EXISTS(theirs))
|
||||
return 0;
|
||||
merge_file_normalize_opts(&options, given_opts);
|
||||
|
||||
memset(&xmparam, 0x0, sizeof(xmparam_t));
|
||||
xmparam.ancestor = ancestor->label;
|
||||
xmparam.file1 = ours->label;
|
||||
xmparam.file2 = theirs->label;
|
||||
|
||||
out->path = merge_file_best_path(ancestor, ours, theirs);
|
||||
out->mode = merge_file_best_mode(ancestor, ours, theirs);
|
||||
if (ancestor) {
|
||||
xmparam.ancestor = (options.ancestor_label) ?
|
||||
options.ancestor_label : ancestor->path;
|
||||
ancestor_mmfile.ptr = (char *)ancestor->ptr;
|
||||
ancestor_mmfile.size = ancestor->size;
|
||||
}
|
||||
|
||||
if (opts && opts->favor == GIT_MERGE_FILE_FAVOR_OURS)
|
||||
xmparam.file1 = (options.our_label) ?
|
||||
options.our_label : ours->path;
|
||||
our_mmfile.ptr = (char *)ours->ptr;
|
||||
our_mmfile.size = ours->size;
|
||||
|
||||
xmparam.file2 = (options.their_label) ?
|
||||
options.their_label : theirs->path;
|
||||
their_mmfile.ptr = (char *)theirs->ptr;
|
||||
their_mmfile.size = theirs->size;
|
||||
|
||||
if (options.favor == GIT_MERGE_FILE_FAVOR_OURS)
|
||||
xmparam.favor = XDL_MERGE_FAVOR_OURS;
|
||||
else if (opts && opts->favor == GIT_MERGE_FILE_FAVOR_THEIRS)
|
||||
else if (options.favor == GIT_MERGE_FILE_FAVOR_THEIRS)
|
||||
xmparam.favor = XDL_MERGE_FAVOR_THEIRS;
|
||||
else if (opts && opts->favor == GIT_MERGE_FILE_FAVOR_UNION)
|
||||
else if (options.favor == GIT_MERGE_FILE_FAVOR_UNION)
|
||||
xmparam.favor = XDL_MERGE_FAVOR_UNION;
|
||||
|
||||
xmparam.level =
|
||||
(opts && (opts->flags & GIT_MERGE_FILE_SIMPLIFY_ALNUM)) ?
|
||||
xmparam.level = (options.flags & GIT_MERGE_FILE_SIMPLIFY_ALNUM) ?
|
||||
XDL_MERGE_ZEALOUS_ALNUM : XDL_MERGE_ZEALOUS;
|
||||
|
||||
if (opts && opts->style == GIT_MERGE_FILE_STYLE_DIFF3)
|
||||
if (options.flags & GIT_MERGE_FILE_STYLE_DIFF3)
|
||||
xmparam.style = XDL_MERGE_DIFF3;
|
||||
|
||||
if ((xdl_result = xdl_merge(&ancestor->mmfile, &ours->mmfile,
|
||||
&theirs->mmfile, &xmparam, &mmbuffer)) < 0) {
|
||||
if ((xdl_result = xdl_merge(&ancestor_mmfile, &our_mmfile,
|
||||
&their_mmfile, &xmparam, &mmbuffer)) < 0) {
|
||||
giterr_set(GITERR_MERGE, "Failed to merge files.");
|
||||
error = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((path = merge_file_best_path(ancestor, ours, theirs)) != NULL &&
|
||||
(out->path = strdup(path)) == NULL) {
|
||||
error = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
out->automergeable = (xdl_result == 0);
|
||||
out->data = (unsigned char *)mmbuffer.ptr;
|
||||
out->ptr = (unsigned char *)mmbuffer.ptr;
|
||||
out->len = mmbuffer.size;
|
||||
out->mode = merge_file_best_mode(ancestor, ours, theirs);
|
||||
|
||||
done:
|
||||
if (error < 0)
|
||||
git_merge_file_result_free(out);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static git_merge_file_input *git_merge_file__normalize_inputs(
|
||||
git_merge_file_input *out,
|
||||
const git_merge_file_input *given)
|
||||
{
|
||||
memcpy(out, given, sizeof(git_merge_file_input));
|
||||
|
||||
if (!out->path)
|
||||
out->path = "file.txt";
|
||||
|
||||
if (!out->mode)
|
||||
out->mode = 0100644;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int git_merge_file(
|
||||
git_merge_file_result *out,
|
||||
const git_merge_file_input *ancestor,
|
||||
const git_merge_file_input *ours,
|
||||
const git_merge_file_input *theirs,
|
||||
const git_merge_file_options *options)
|
||||
{
|
||||
git_merge_file_input inputs[3] = { {0} };
|
||||
|
||||
assert(out && ours && theirs);
|
||||
|
||||
memset(out, 0x0, sizeof(git_merge_file_result));
|
||||
|
||||
if (ancestor)
|
||||
ancestor = git_merge_file__normalize_inputs(&inputs[0], ancestor);
|
||||
|
||||
ours = git_merge_file__normalize_inputs(&inputs[1], ours);
|
||||
theirs = git_merge_file__normalize_inputs(&inputs[2], theirs);
|
||||
|
||||
return git_merge_file__from_inputs(out, ancestor, ours, theirs, options);
|
||||
}
|
||||
|
||||
int git_merge_file_from_index(
|
||||
git_merge_file_result *out,
|
||||
git_repository *repo,
|
||||
const git_index_entry *ancestor,
|
||||
const git_index_entry *ours,
|
||||
const git_index_entry *theirs,
|
||||
const git_merge_file_options *options)
|
||||
{
|
||||
git_merge_file_input inputs[3] = { {0} },
|
||||
*ancestor_input = NULL, *our_input = NULL, *their_input = NULL;
|
||||
git_odb *odb = NULL;
|
||||
git_odb_object *odb_object[3] = { 0 };
|
||||
int error = 0;
|
||||
|
||||
assert(out && repo && ours && theirs);
|
||||
|
||||
memset(out, 0x0, sizeof(git_merge_file_result));
|
||||
|
||||
if ((error = git_repository_odb(&odb, repo)) < 0)
|
||||
goto done;
|
||||
|
||||
if (ancestor) {
|
||||
if ((error = git_merge_file__input_from_index(
|
||||
&inputs[0], &odb_object[0], odb, ancestor)) < 0)
|
||||
goto done;
|
||||
|
||||
ancestor_input = &inputs[0];
|
||||
}
|
||||
|
||||
if ((error = git_merge_file__input_from_index(
|
||||
&inputs[1], &odb_object[1], odb, ours)) < 0)
|
||||
goto done;
|
||||
|
||||
our_input = &inputs[1];
|
||||
|
||||
if ((error = git_merge_file__input_from_index(
|
||||
&inputs[2], &odb_object[2], odb, theirs)) < 0)
|
||||
goto done;
|
||||
|
||||
their_input = &inputs[2];
|
||||
|
||||
if ((error = git_merge_file__from_inputs(out,
|
||||
ancestor_input, our_input, their_input, options)) < 0)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
git_odb_object_free(odb_object[0]);
|
||||
git_odb_object_free(odb_object[1]);
|
||||
git_odb_object_free(odb_object[2]);
|
||||
git_odb_free(odb);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void git_merge_file_result_free(git_merge_file_result *result)
|
||||
{
|
||||
if (result == NULL)
|
||||
return;
|
||||
|
||||
git__free(result->path);
|
||||
|
||||
/* xdiff uses malloc() not git_malloc, so we use free(), not git_free() */
|
||||
free(result->ptr);
|
||||
}
|
||||
|
@ -11,82 +11,4 @@
|
||||
|
||||
#include "git2/merge.h"
|
||||
|
||||
typedef struct {
|
||||
const char *label;
|
||||
char *path;
|
||||
unsigned int mode;
|
||||
mmfile_t mmfile;
|
||||
|
||||
git_odb_object *odb_object;
|
||||
} git_merge_file_input;
|
||||
|
||||
#define GIT_MERGE_FILE_INPUT_INIT {0}
|
||||
|
||||
typedef struct {
|
||||
bool automergeable;
|
||||
|
||||
const char *path;
|
||||
int mode;
|
||||
|
||||
unsigned char *data;
|
||||
size_t len;
|
||||
} git_merge_file_result;
|
||||
|
||||
#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,
|
||||
const git_index_entry *entry);
|
||||
|
||||
int git_merge_file_input_from_diff_file(
|
||||
git_merge_file_input *input,
|
||||
git_repository *repo,
|
||||
const git_diff_file *file);
|
||||
|
||||
int git_merge_files(
|
||||
git_merge_file_result *out,
|
||||
git_merge_file_input *ancestor,
|
||||
git_merge_file_input *ours,
|
||||
git_merge_file_input *theirs,
|
||||
git_merge_file_options *opts);
|
||||
|
||||
GIT_INLINE(void) git_merge_file_input_free(git_merge_file_input *input)
|
||||
{
|
||||
assert(input);
|
||||
git__free(input->path);
|
||||
git_odb_object_free(input->odb_object);
|
||||
}
|
||||
|
||||
GIT_INLINE(void) git_merge_file_result_free(git_merge_file_result *filediff)
|
||||
{
|
||||
if (filediff == NULL)
|
||||
return;
|
||||
|
||||
/* xdiff uses malloc() not git_malloc, so we use free(), not git_free() */
|
||||
if (filediff->data != NULL)
|
||||
free(filediff->data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
175
tests/merge/files.c
Normal file
175
tests/merge/files.c
Normal file
@ -0,0 +1,175 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "git2/repository.h"
|
||||
#include "git2/merge.h"
|
||||
#include "buffer.h"
|
||||
#include "merge.h"
|
||||
#include "merge_helpers.h"
|
||||
#include "refs.h"
|
||||
#include "fileops.h"
|
||||
|
||||
#define TEST_REPO_PATH "merge-resolve"
|
||||
#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
|
||||
|
||||
static git_repository *repo;
|
||||
static git_index *repo_index;
|
||||
|
||||
// Fixture setup and teardown
|
||||
void test_merge_files__initialize(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
|
||||
repo = cl_git_sandbox_init(TEST_REPO_PATH);
|
||||
git_repository_index(&repo_index, repo);
|
||||
|
||||
/* Ensure that the user's merge.conflictstyle doesn't interfere */
|
||||
cl_git_pass(git_repository_config(&cfg, repo));
|
||||
cl_git_pass(git_config_set_string(cfg, "merge.conflictstyle", "merge"));
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_merge_files__cleanup(void)
|
||||
{
|
||||
git_index_free(repo_index);
|
||||
cl_git_sandbox_cleanup();
|
||||
}
|
||||
|
||||
void test_merge_files__automerge_from_bufs(void)
|
||||
{
|
||||
git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
|
||||
ours = GIT_MERGE_FILE_INPUT_INIT,
|
||||
theirs = GIT_MERGE_FILE_INPUT_INIT;
|
||||
git_merge_file_result result = {0};
|
||||
const char *expected = "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
|
||||
|
||||
ancestor.ptr = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n";
|
||||
ancestor.size = strlen(ancestor.ptr);
|
||||
ancestor.path = "testfile.txt";
|
||||
ancestor.mode = 0100755;
|
||||
|
||||
ours.ptr = "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n";
|
||||
ours.size = strlen(ours.ptr);
|
||||
ours.path = "testfile.txt";
|
||||
ours.mode = 0100755;
|
||||
|
||||
theirs.ptr = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
|
||||
theirs.size = strlen(theirs.ptr);
|
||||
theirs.path = "testfile.txt";
|
||||
theirs.mode = 0100755;
|
||||
|
||||
cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, 0));
|
||||
|
||||
cl_assert_equal_i(1, result.automergeable);
|
||||
|
||||
cl_assert_equal_s("testfile.txt", result.path);
|
||||
cl_assert_equal_i(0100755, result.mode);
|
||||
|
||||
cl_assert_equal_i(strlen(expected), result.len);
|
||||
cl_assert_equal_strn(expected, result.ptr, result.len);
|
||||
|
||||
git_merge_file_result_free(&result);
|
||||
}
|
||||
|
||||
void test_merge_files__automerge_use_best_path_and_mode(void)
|
||||
{
|
||||
git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
|
||||
ours = GIT_MERGE_FILE_INPUT_INIT,
|
||||
theirs = GIT_MERGE_FILE_INPUT_INIT;
|
||||
git_merge_file_result result = {0};
|
||||
const char *expected = "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
|
||||
|
||||
ancestor.ptr = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n";
|
||||
ancestor.size = strlen(ancestor.ptr);
|
||||
ancestor.path = "testfile.txt";
|
||||
ancestor.mode = 0100755;
|
||||
|
||||
ours.ptr = "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n";
|
||||
ours.size = strlen(ours.ptr);
|
||||
ours.path = "testfile.txt";
|
||||
ours.mode = 0100644;
|
||||
|
||||
theirs.ptr = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
|
||||
theirs.size = strlen(theirs.ptr);
|
||||
theirs.path = "theirs.txt";
|
||||
theirs.mode = 0100755;
|
||||
|
||||
cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, 0));
|
||||
|
||||
cl_assert_equal_i(1, result.automergeable);
|
||||
|
||||
cl_assert_equal_s("theirs.txt", result.path);
|
||||
cl_assert_equal_i(0100644, result.mode);
|
||||
|
||||
cl_assert_equal_i(strlen(expected), result.len);
|
||||
cl_assert_equal_strn(expected, result.ptr, result.len);
|
||||
|
||||
git_merge_file_result_free(&result);
|
||||
}
|
||||
|
||||
void test_merge_files__conflict_from_bufs(void)
|
||||
{
|
||||
git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
|
||||
ours = GIT_MERGE_FILE_INPUT_INIT,
|
||||
theirs = GIT_MERGE_FILE_INPUT_INIT;
|
||||
git_merge_file_result result = {0};
|
||||
|
||||
const char *expected = "<<<<<<< testfile.txt\nAloha!\nOurs.\n=======\nHi!\nTheirs.\n>>>>>>> theirs.txt\n";
|
||||
size_t expected_len = strlen(expected);
|
||||
|
||||
ancestor.ptr = "Hello!\nAncestor!\n";
|
||||
ancestor.size = strlen(ancestor.ptr);
|
||||
ancestor.path = "testfile.txt";
|
||||
ancestor.mode = 0100755;
|
||||
|
||||
ours.ptr = "Aloha!\nOurs.\n";
|
||||
ours.size = strlen(ours.ptr);
|
||||
ours.path = "testfile.txt";
|
||||
ours.mode = 0100644;
|
||||
|
||||
theirs.ptr = "Hi!\nTheirs.\n";
|
||||
theirs.size = strlen(theirs.ptr);
|
||||
theirs.path = "theirs.txt";
|
||||
theirs.mode = 0100755;
|
||||
|
||||
cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, NULL));
|
||||
|
||||
cl_assert_equal_i(0, result.automergeable);
|
||||
|
||||
cl_assert_equal_s("theirs.txt", result.path);
|
||||
cl_assert_equal_i(0100644, result.mode);
|
||||
|
||||
cl_assert_equal_i(expected_len, result.len);
|
||||
cl_assert_equal_strn(expected, result.ptr, expected_len);
|
||||
|
||||
git_merge_file_result_free(&result);
|
||||
}
|
||||
|
||||
void test_merge_files__automerge_from_index(void)
|
||||
{
|
||||
git_merge_file_result result = {0};
|
||||
git_index_entry ancestor, ours, theirs;
|
||||
|
||||
git_oid_fromstr(&ancestor.id, "6212c31dab5e482247d7977e4f0dd3601decf13b");
|
||||
ancestor.path = "automergeable.txt";
|
||||
ancestor.mode = 0100644;
|
||||
|
||||
git_oid_fromstr(&ours.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
|
||||
ours.path = "automergeable.txt";
|
||||
ours.mode = 0100755;
|
||||
|
||||
git_oid_fromstr(&theirs.id, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe");
|
||||
theirs.path = "newname.txt";
|
||||
theirs.mode = 0100644;
|
||||
|
||||
cl_git_pass(git_merge_file_from_index(&result, repo,
|
||||
&ancestor, &ours, &theirs, 0));
|
||||
|
||||
cl_assert_equal_i(1, result.automergeable);
|
||||
|
||||
cl_assert_equal_s("newname.txt", result.path);
|
||||
cl_assert_equal_i(0100755, result.mode);
|
||||
|
||||
cl_assert_equal_i(strlen(AUTOMERGEABLE_MERGED_FILE), result.len);
|
||||
cl_assert_equal_strn(AUTOMERGEABLE_MERGED_FILE, result.ptr, result.len);
|
||||
|
||||
git_merge_file_result_free(&result);
|
||||
}
|
@ -4,6 +4,49 @@
|
||||
#include "merge.h"
|
||||
#include "git2/merge.h"
|
||||
|
||||
#define AUTOMERGEABLE_MERGED_FILE \
|
||||
"this file is changed in master\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is changed in branch\n"
|
||||
|
||||
#define AUTOMERGEABLE_MERGED_FILE_CRLF \
|
||||
"this file is changed in master\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is changed in branch\r\n"
|
||||
|
||||
#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"
|
||||
|
||||
|
||||
struct merge_index_entry {
|
||||
uint16_t mode;
|
||||
char oid_str[41];
|
||||
|
@ -54,28 +54,6 @@ static git_repository *repo;
|
||||
"", \
|
||||
"5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5" }
|
||||
|
||||
#define AUTOMERGEABLE_MERGED_FILE \
|
||||
"this file is changed in master\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is changed in branch\n"
|
||||
|
||||
#define AUTOMERGEABLE_MERGED_FILE_CRLF \
|
||||
"this file is changed in master\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is changed in branch\r\n"
|
||||
|
||||
// Fixture setup and teardown
|
||||
void test_merge_trees_automerge__initialize(void)
|
||||
{
|
||||
|
@ -8,17 +8,6 @@ static git_repository *repo;
|
||||
|
||||
#define TEST_REPO_PATH "merge-resolve"
|
||||
|
||||
#define AUTOMERGEABLE_MERGED_FILE \
|
||||
"this file is changed in master\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is changed in branch\n"
|
||||
|
||||
void test_merge_trees_commits__initialize(void)
|
||||
{
|
||||
repo = cl_git_sandbox_init(TEST_REPO_PATH);
|
||||
|
@ -71,47 +71,6 @@ static git_index *repo_index;
|
||||
"", \
|
||||
"5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5" }
|
||||
|
||||
#define AUTOMERGEABLE_MERGED_FILE \
|
||||
"this file is changed in master\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is automergeable\n" \
|
||||
"this file is changed in branch\n"
|
||||
|
||||
#define AUTOMERGEABLE_MERGED_FILE_CRLF \
|
||||
"this file is changed in master\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is automergeable\r\n" \
|
||||
"this file is changed in branch\r\n"
|
||||
|
||||
#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)
|
||||
|
@ -65,6 +65,16 @@ void test_structinit_structinit__compare(void)
|
||||
git_diff_find_options, GIT_DIFF_FIND_OPTIONS_VERSION, \
|
||||
GIT_DIFF_FIND_OPTIONS_INIT, git_diff_find_init_options);
|
||||
|
||||
/* merge_file_input */
|
||||
CHECK_MACRO_FUNC_INIT_EQUAL( \
|
||||
git_merge_file_input, GIT_MERGE_FILE_INPUT_VERSION, \
|
||||
GIT_MERGE_FILE_INPUT_INIT, git_merge_file_init_input);
|
||||
|
||||
/* merge_file */
|
||||
CHECK_MACRO_FUNC_INIT_EQUAL( \
|
||||
git_merge_file_options, GIT_MERGE_FILE_OPTIONS_VERSION, \
|
||||
GIT_MERGE_FILE_OPTIONS_INIT, git_merge_file_init_options);
|
||||
|
||||
/* merge_tree */
|
||||
CHECK_MACRO_FUNC_INIT_EQUAL( \
|
||||
git_merge_tree_opts, GIT_MERGE_TREE_OPTS_VERSION, \
|
||||
|
Loading…
Reference in New Issue
Block a user