mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-04 14:13:19 +00:00
Two-step conflict checkout (load / perform)
Move conflict handling into two steps: load the conflicts and then apply the conflicts. This is more compatible with the existing checkout implementation and makes progress reporting more sane.
This commit is contained in:
parent
cfae7f85fb
commit
216f97e4f6
@ -29,18 +29,6 @@
|
||||
|
||||
/* See docs/checkout-internals.md for more information */
|
||||
|
||||
enum {
|
||||
CHECKOUT_ACTION__NONE = 0,
|
||||
CHECKOUT_ACTION__REMOVE = 1,
|
||||
CHECKOUT_ACTION__UPDATE_BLOB = 2,
|
||||
CHECKOUT_ACTION__UPDATE_SUBMODULE = 4,
|
||||
CHECKOUT_ACTION__CONFLICT = 8,
|
||||
CHECKOUT_ACTION__MAX = 8,
|
||||
CHECKOUT_ACTION__DEFER_REMOVE = 16,
|
||||
CHECKOUT_ACTION__REMOVE_AND_UPDATE =
|
||||
(CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
|
||||
};
|
||||
|
||||
static int checkout_notify(
|
||||
checkout_data *data,
|
||||
git_checkout_notify_t why,
|
||||
@ -641,6 +629,14 @@ static int checkout_get_actions(
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if ((error = git_checkout__get_conflicts(data, workdir, &pathspec)) < 0)
|
||||
goto fail;
|
||||
|
||||
counts[CHECKOUT_ACTION__UPDATE_CONFLICT] = git_vector_length(&data->conflicts);
|
||||
|
||||
/* HERE */
|
||||
|
||||
git_pathspec__vfree(&pathspec);
|
||||
git_pool_clear(&pathpool);
|
||||
|
||||
@ -841,7 +837,7 @@ static int checkout_submodule(
|
||||
return checkout_submodule_update_index(data, file);
|
||||
}
|
||||
|
||||
static void report_progress(
|
||||
void git_checkout__report_progress(
|
||||
checkout_data *data,
|
||||
const char *path)
|
||||
{
|
||||
@ -965,7 +961,7 @@ static int checkout_remove_the_old(
|
||||
return error;
|
||||
|
||||
data->completed_steps++;
|
||||
report_progress(data, delta->old_file.path);
|
||||
git_checkout__report_progress(data, delta->old_file.path);
|
||||
|
||||
if ((actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) == 0 &&
|
||||
(data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
|
||||
@ -982,7 +978,7 @@ static int checkout_remove_the_old(
|
||||
return error;
|
||||
|
||||
data->completed_steps++;
|
||||
report_progress(data, str);
|
||||
git_checkout__report_progress(data, str);
|
||||
|
||||
if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
|
||||
data->index != NULL)
|
||||
@ -1041,7 +1037,7 @@ static int checkout_create_the_new(
|
||||
return error;
|
||||
|
||||
data->completed_steps++;
|
||||
report_progress(data, delta->new_file.path);
|
||||
git_checkout__report_progress(data, delta->new_file.path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1077,7 +1073,7 @@ static int checkout_create_submodules(
|
||||
return error;
|
||||
|
||||
data->completed_steps++;
|
||||
report_progress(data, delta->new_file.path);
|
||||
git_checkout__report_progress(data, delta->new_file.path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1102,6 +1098,9 @@ static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
|
||||
|
||||
static void checkout_data_clear(checkout_data *data)
|
||||
{
|
||||
checkout_conflictdata *conflict;
|
||||
size_t i;
|
||||
|
||||
if (data->opts_free_baseline) {
|
||||
git_tree_free(data->opts.baseline);
|
||||
data->opts.baseline = NULL;
|
||||
@ -1110,6 +1109,11 @@ static void checkout_data_clear(checkout_data *data)
|
||||
git_vector_free(&data->removes);
|
||||
git_pool_clear(&data->pool);
|
||||
|
||||
git_vector_foreach(&data->conflicts, i, conflict)
|
||||
git__free(conflict);
|
||||
|
||||
git_vector_free(&data->conflicts);
|
||||
|
||||
git__free(data->pfx);
|
||||
data->pfx = NULL;
|
||||
|
||||
@ -1226,6 +1230,7 @@ static int checkout_data_init(
|
||||
}
|
||||
|
||||
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 ||
|
||||
(error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 ||
|
||||
(error = git_path_to_dir(&data->path)) < 0)
|
||||
@ -1296,16 +1301,18 @@ int git_checkout_iterator(
|
||||
goto cleanup;
|
||||
|
||||
/* Loop through diff (and working directory iterator) building a list of
|
||||
* actions to be taken, plus look for conflicts and send notifications.
|
||||
* actions to be taken, plus look for conflicts and send notifications,
|
||||
* then loop through conflicts.
|
||||
*/
|
||||
if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
|
||||
counts[CHECKOUT_ACTION__UPDATE_BLOB] +
|
||||
counts[CHECKOUT_ACTION__UPDATE_SUBMODULE];
|
||||
counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] +
|
||||
counts[CHECKOUT_ACTION__UPDATE_CONFLICT];
|
||||
|
||||
report_progress(&data, NULL); /* establish 0 baseline */
|
||||
git_checkout__report_progress(&data, NULL); /* establish 0 baseline */
|
||||
|
||||
/* To deal with some order dependencies, perform remaining checkout
|
||||
* in three passes: removes, then update blobs, then update submodules.
|
||||
@ -1322,10 +1329,11 @@ int git_checkout_iterator(
|
||||
(error = checkout_create_submodules(actions, &data)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
assert(data.completed_steps == data.total_steps);
|
||||
if (counts[CHECKOUT_ACTION__UPDATE_CONFLICT] > 0 &&
|
||||
(error = git_checkout__conflicts(&data)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Write conflict data to disk */
|
||||
error = git_checkout__conflicts(&data);
|
||||
assert(data.completed_steps == data.total_steps);
|
||||
|
||||
cleanup:
|
||||
if (error == GIT_EUSER)
|
||||
|
@ -22,6 +22,7 @@ typedef struct {
|
||||
git_index *index;
|
||||
git_pool pool;
|
||||
git_vector removes;
|
||||
git_vector conflicts;
|
||||
git_buf path;
|
||||
size_t workdir_len;
|
||||
unsigned int strategy;
|
||||
@ -31,6 +32,29 @@ typedef struct {
|
||||
size_t completed_steps;
|
||||
} checkout_data;
|
||||
|
||||
typedef struct {
|
||||
const git_index_entry *ancestor;
|
||||
const git_index_entry *ours;
|
||||
const git_index_entry *theirs;
|
||||
|
||||
int name_collision:1,
|
||||
directoryfile:1,
|
||||
one_to_two:1;
|
||||
} checkout_conflictdata;
|
||||
|
||||
enum {
|
||||
CHECKOUT_ACTION__NONE = 0,
|
||||
CHECKOUT_ACTION__REMOVE = 1,
|
||||
CHECKOUT_ACTION__UPDATE_BLOB = 2,
|
||||
CHECKOUT_ACTION__UPDATE_SUBMODULE = 4,
|
||||
CHECKOUT_ACTION__CONFLICT = 8,
|
||||
CHECKOUT_ACTION__UPDATE_CONFLICT = 16,
|
||||
CHECKOUT_ACTION__MAX = 16,
|
||||
CHECKOUT_ACTION__DEFER_REMOVE = 32,
|
||||
CHECKOUT_ACTION__REMOVE_AND_UPDATE =
|
||||
(CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the working directory to match the target iterator. The
|
||||
* expected baseline value can be passed in via the checkout options
|
||||
@ -52,6 +76,11 @@ int git_checkout__write_content(
|
||||
unsigned int mode,
|
||||
struct stat *st);
|
||||
|
||||
void git_checkout__report_progress(
|
||||
checkout_data *data,
|
||||
const char *path);
|
||||
|
||||
int git_checkout__get_conflicts(checkout_data *data, git_iterator *workdir, git_vector *pathspec);
|
||||
int git_checkout__conflicts(checkout_data *data);
|
||||
|
||||
#endif
|
||||
|
@ -11,22 +11,13 @@
|
||||
|
||||
#include "vector.h"
|
||||
#include "index.h"
|
||||
#include "pathspec.h"
|
||||
#include "merge_file.h"
|
||||
#include "git2/repository.h"
|
||||
#include "git2/types.h"
|
||||
#include "git2/index.h"
|
||||
#include "git2/sys/index.h"
|
||||
|
||||
typedef struct {
|
||||
const git_index_entry *ancestor;
|
||||
const git_index_entry *ours;
|
||||
const git_index_entry *theirs;
|
||||
|
||||
int name_collision:1,
|
||||
directoryfile:1,
|
||||
one_to_two:1;
|
||||
} checkout_conflictdata;
|
||||
|
||||
GIT_INLINE(int) checkout_idxentry_cmp(
|
||||
const git_index_entry *a,
|
||||
const git_index_entry *b)
|
||||
@ -68,7 +59,34 @@ int checkout_conflictdata_empty(const git_vector *conflicts, size_t idx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int checkout_conflicts_load(checkout_data *data, git_vector *conflicts)
|
||||
GIT_INLINE(bool) conflict_pathspec_match(
|
||||
checkout_data *data,
|
||||
git_iterator *workdir,
|
||||
git_vector *pathspec,
|
||||
const git_index_entry *ancestor,
|
||||
const git_index_entry *ours,
|
||||
const git_index_entry *theirs)
|
||||
{
|
||||
/* if the pathspec matches ours *or* theirs, proceed */
|
||||
if (ours && git_pathspec__match(pathspec, ours->path,
|
||||
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
|
||||
git_iterator_ignore_case(workdir), NULL, NULL))
|
||||
return true;
|
||||
|
||||
if (theirs && git_pathspec__match(pathspec, theirs->path,
|
||||
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
|
||||
git_iterator_ignore_case(workdir), NULL, NULL))
|
||||
return true;
|
||||
|
||||
if (ancestor && git_pathspec__match(pathspec, ancestor->path,
|
||||
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
|
||||
git_iterator_ignore_case(workdir), NULL, NULL))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec)
|
||||
{
|
||||
git_index_conflict_iterator *iterator = NULL;
|
||||
const git_index_entry *ancestor, *ours, *theirs;
|
||||
@ -78,11 +96,12 @@ static int checkout_conflicts_load(checkout_data *data, git_vector *conflicts)
|
||||
if ((error = git_index_conflict_iterator_new(&iterator, data->index)) < 0)
|
||||
goto done;
|
||||
|
||||
conflicts->_cmp = checkout_conflictdata_cmp;
|
||||
data->conflicts._cmp = checkout_conflictdata_cmp;
|
||||
|
||||
/* Collect the conflicts */
|
||||
while ((error = git_index_conflict_next(
|
||||
&ancestor, &ours, &theirs, iterator)) == 0) {
|
||||
while ((error = git_index_conflict_next(&ancestor, &ours, &theirs, iterator)) == 0) {
|
||||
if (!conflict_pathspec_match(data, workdir, pathspec, ancestor, ours, theirs))
|
||||
continue;
|
||||
|
||||
conflict = git__calloc(1, sizeof(checkout_conflictdata));
|
||||
GITERR_CHECK_ALLOC(conflict);
|
||||
@ -91,7 +110,7 @@ static int checkout_conflicts_load(checkout_data *data, git_vector *conflicts)
|
||||
conflict->ours = ours;
|
||||
conflict->theirs = theirs;
|
||||
|
||||
git_vector_insert(conflicts, conflict);
|
||||
git_vector_insert(&data->conflicts, conflict);
|
||||
}
|
||||
|
||||
if (error == GIT_ITEROVER)
|
||||
@ -122,25 +141,25 @@ static int checkout_conflicts_cmp_ancestor(const void *p, const void *c)
|
||||
}
|
||||
|
||||
static checkout_conflictdata *checkout_conflicts_search_ancestor(
|
||||
git_vector *conflicts,
|
||||
checkout_data *data,
|
||||
const char *path)
|
||||
{
|
||||
size_t pos;
|
||||
|
||||
if (git_vector_bsearch2(&pos, conflicts, checkout_conflicts_cmp_ancestor, path) < 0)
|
||||
if (git_vector_bsearch2(&pos, &data->conflicts, checkout_conflicts_cmp_ancestor, path) < 0)
|
||||
return NULL;
|
||||
|
||||
return git_vector_get(conflicts, pos);
|
||||
return git_vector_get(&data->conflicts, pos);
|
||||
}
|
||||
|
||||
static checkout_conflictdata *checkout_conflicts_search_branch(
|
||||
git_vector *conflicts,
|
||||
checkout_data *data,
|
||||
const char *path)
|
||||
{
|
||||
checkout_conflictdata *conflict;
|
||||
size_t i;
|
||||
|
||||
git_vector_foreach(conflicts, i, conflict) {
|
||||
git_vector_foreach(&data->conflicts, i, conflict) {
|
||||
int cmp = -1;
|
||||
|
||||
if (conflict->ancestor)
|
||||
@ -162,7 +181,7 @@ static int checkout_conflicts_load_byname_entry(
|
||||
checkout_conflictdata **ancestor_out,
|
||||
checkout_conflictdata **ours_out,
|
||||
checkout_conflictdata **theirs_out,
|
||||
git_vector *conflicts,
|
||||
checkout_data *data,
|
||||
const git_index_name_entry *name_entry)
|
||||
{
|
||||
checkout_conflictdata *ancestor, *ours = NULL, *theirs = NULL;
|
||||
@ -184,7 +203,7 @@ static int checkout_conflicts_load_byname_entry(
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((ancestor = checkout_conflicts_search_ancestor(conflicts,
|
||||
if ((ancestor = checkout_conflicts_search_ancestor(data,
|
||||
name_entry->ancestor)) == NULL) {
|
||||
giterr_set(GITERR_INDEX,
|
||||
"A NAME entry referenced ancestor entry '%s' which does not exist in the main index",
|
||||
@ -196,7 +215,7 @@ static int checkout_conflicts_load_byname_entry(
|
||||
if (name_entry->ours) {
|
||||
if (strcmp(name_entry->ancestor, name_entry->ours) == 0)
|
||||
ours = ancestor;
|
||||
else if ((ours = checkout_conflicts_search_branch(conflicts, name_entry->ours)) == NULL ||
|
||||
else if ((ours = checkout_conflicts_search_branch(data, name_entry->ours)) == NULL ||
|
||||
ours->ours == NULL) {
|
||||
giterr_set(GITERR_INDEX,
|
||||
"A NAME entry referenced our entry '%s' which does not exist in the main index",
|
||||
@ -211,7 +230,7 @@ static int checkout_conflicts_load_byname_entry(
|
||||
theirs = ancestor;
|
||||
else if (name_entry->ours && strcmp(name_entry->ours, name_entry->theirs) == 0)
|
||||
theirs = ours;
|
||||
else if ((theirs = checkout_conflicts_search_branch(conflicts, name_entry->theirs)) == NULL ||
|
||||
else if ((theirs = checkout_conflicts_search_branch(data, name_entry->theirs)) == NULL ||
|
||||
theirs->theirs == NULL) {
|
||||
giterr_set(GITERR_INDEX,
|
||||
"A NAME entry referenced their entry '%s' which does not exist in the main index",
|
||||
@ -230,8 +249,7 @@ done:
|
||||
}
|
||||
|
||||
static int checkout_conflicts_coalesce_renames(
|
||||
checkout_data *data,
|
||||
git_vector *conflicts)
|
||||
checkout_data *data)
|
||||
{
|
||||
const git_index_name_entry *name_entry;
|
||||
checkout_conflictdata *ancestor_conflict, *our_conflict, *their_conflict;
|
||||
@ -239,15 +257,14 @@ static int checkout_conflicts_coalesce_renames(
|
||||
int error = 0;
|
||||
|
||||
/* Juggle entries based on renames */
|
||||
for (i = 0, names = git_index_name_entrycount(data->index);
|
||||
i < names;
|
||||
i++) {
|
||||
|
||||
names = git_index_name_entrycount(data->index);
|
||||
|
||||
for (i = 0; i < names; i++) {
|
||||
name_entry = git_index_name_get_byindex(data->index, i);
|
||||
|
||||
if ((error = checkout_conflicts_load_byname_entry(
|
||||
&ancestor_conflict, &our_conflict, &their_conflict,
|
||||
conflicts, name_entry)) < 0)
|
||||
data, name_entry)) < 0)
|
||||
goto done;
|
||||
|
||||
if (our_conflict && our_conflict != ancestor_conflict) {
|
||||
@ -277,7 +294,7 @@ static int checkout_conflicts_coalesce_renames(
|
||||
ancestor_conflict->one_to_two = 1;
|
||||
}
|
||||
|
||||
git_vector_remove_matching(conflicts, checkout_conflictdata_empty);
|
||||
git_vector_remove_matching(&data->conflicts, checkout_conflictdata_empty);
|
||||
|
||||
done:
|
||||
return error;
|
||||
@ -307,8 +324,7 @@ GIT_INLINE(void) path_equal_or_prefixed(
|
||||
}
|
||||
|
||||
static int checkout_conflicts_mark_directoryfile(
|
||||
checkout_data *data,
|
||||
git_vector *conflicts)
|
||||
checkout_data *data)
|
||||
{
|
||||
checkout_conflictdata *conflict;
|
||||
const git_index_entry *entry;
|
||||
@ -320,7 +336,7 @@ static int checkout_conflicts_mark_directoryfile(
|
||||
len = git_index_entrycount(data->index);
|
||||
|
||||
/* Find d/f conflicts */
|
||||
git_vector_foreach(conflicts, i, conflict) {
|
||||
git_vector_foreach(&data->conflicts, i, conflict) {
|
||||
if ((conflict->ours && conflict->theirs) ||
|
||||
(!conflict->ours && !conflict->theirs))
|
||||
continue;
|
||||
@ -560,6 +576,22 @@ done:
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_checkout__get_conflicts(checkout_data *data, git_iterator *workdir, git_vector *pathspec)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (data->strategy & GIT_CHECKOUT_SKIP_UNMERGED)
|
||||
return 0;
|
||||
|
||||
if ((error = checkout_conflicts_load(data, workdir, pathspec)) < 0 ||
|
||||
(error = checkout_conflicts_coalesce_renames(data)) < 0 ||
|
||||
(error = checkout_conflicts_mark_directoryfile(data)) < 0)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_checkout__conflicts(checkout_data *data)
|
||||
{
|
||||
git_vector conflicts = GIT_VECTOR_INIT;
|
||||
@ -567,15 +599,7 @@ int git_checkout__conflicts(checkout_data *data)
|
||||
size_t i;
|
||||
int error = 0;
|
||||
|
||||
if (data->strategy & GIT_CHECKOUT_SKIP_UNMERGED)
|
||||
return 0;
|
||||
|
||||
if ((error = checkout_conflicts_load(data, &conflicts)) < 0 ||
|
||||
(error = checkout_conflicts_coalesce_renames(data, &conflicts)) < 0 ||
|
||||
(error = checkout_conflicts_mark_directoryfile(data, &conflicts)) < 0)
|
||||
goto done;
|
||||
|
||||
git_vector_foreach(&conflicts, i, conflict) {
|
||||
git_vector_foreach(&data->conflicts, i, conflict) {
|
||||
/* Both deleted: nothing to do */
|
||||
if (conflict->ours == NULL && conflict->theirs == NULL)
|
||||
error = 0;
|
||||
@ -621,13 +645,15 @@ int git_checkout__conflicts(checkout_data *data)
|
||||
|
||||
else
|
||||
error = checkout_write_merge(data, conflict);
|
||||
|
||||
if (error)
|
||||
break;
|
||||
|
||||
data->completed_steps++;
|
||||
git_checkout__report_progress(data,
|
||||
conflict->ours ? conflict->ours->path :
|
||||
(conflict->theirs ? conflict->theirs->path : conflict->ancestor->path));
|
||||
}
|
||||
|
||||
done:
|
||||
git_vector_foreach(&conflicts, i, conflict)
|
||||
git__free(conflict);
|
||||
|
||||
git_vector_free(&conflicts);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -1022,3 +1022,103 @@ void test_checkout_conflict__update_only(void)
|
||||
cl_assert(!git_path_exists("merge-resolve/directory_file-one~ours"));
|
||||
cl_assert(!git_path_exists("merge-resolve/directory_file-two~theirs"));
|
||||
}
|
||||
|
||||
void test_checkout_conflict__path_filters(void)
|
||||
{
|
||||
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||
char *paths[] = { "conflicting-1.txt", "conflicting-3.txt" };
|
||||
git_strarray patharray = {0};
|
||||
|
||||
struct checkout_index_entry checkout_index_entries[] = {
|
||||
{ 0100644, CONFLICTING_ANCESTOR_OID, 1, "conflicting-1.txt" },
|
||||
{ 0100644, CONFLICTING_OURS_OID, 2, "conflicting-1.txt" },
|
||||
{ 0100644, CONFLICTING_THEIRS_OID, 3, "conflicting-1.txt" },
|
||||
|
||||
{ 0100644, CONFLICTING_ANCESTOR_OID, 1, "conflicting-2.txt" },
|
||||
{ 0100644, CONFLICTING_OURS_OID, 2, "conflicting-2.txt" },
|
||||
{ 0100644, CONFLICTING_THEIRS_OID, 3, "conflicting-2.txt" },
|
||||
|
||||
{ 0100644, AUTOMERGEABLE_ANCESTOR_OID, 1, "conflicting-3.txt" },
|
||||
{ 0100644, AUTOMERGEABLE_OURS_OID, 2, "conflicting-3.txt" },
|
||||
{ 0100644, AUTOMERGEABLE_THEIRS_OID, 3, "conflicting-3.txt" },
|
||||
|
||||
{ 0100644, AUTOMERGEABLE_ANCESTOR_OID, 1, "conflicting-4.txt" },
|
||||
{ 0100644, AUTOMERGEABLE_OURS_OID, 2, "conflicting-4.txt" },
|
||||
{ 0100644, AUTOMERGEABLE_THEIRS_OID, 3, "conflicting-4.txt" },
|
||||
};
|
||||
|
||||
patharray.count = 2;
|
||||
patharray.strings = paths;
|
||||
|
||||
opts.paths = patharray;
|
||||
|
||||
create_index(checkout_index_entries, 12);
|
||||
git_index_write(g_index);
|
||||
|
||||
cl_git_pass(git_checkout_index(g_repo, g_index, &opts));
|
||||
|
||||
ensure_workdir_contents("conflicting-1.txt", CONFLICTING_DIFF3_FILE);
|
||||
cl_assert(!git_path_exists("merge-resolve/conflicting-2.txt"));
|
||||
ensure_workdir_contents("conflicting-3.txt", AUTOMERGEABLE_MERGED_FILE);
|
||||
cl_assert(!git_path_exists("merge-resolve/conflicting-4.txt"));
|
||||
}
|
||||
|
||||
static void collect_progress(
|
||||
const char *path,
|
||||
size_t completed_steps,
|
||||
size_t total_steps,
|
||||
void *payload)
|
||||
{
|
||||
git_vector *paths = payload;
|
||||
|
||||
if (path == NULL)
|
||||
return;
|
||||
|
||||
git_vector_insert(paths, strdup(path));
|
||||
}
|
||||
|
||||
void test_checkout_conflict__report_progress(void)
|
||||
{
|
||||
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||
git_vector paths = GIT_VECTOR_INIT;
|
||||
char *path;
|
||||
size_t i;
|
||||
|
||||
struct checkout_index_entry checkout_index_entries[] = {
|
||||
{ 0100644, CONFLICTING_ANCESTOR_OID, 1, "conflicting-1.txt" },
|
||||
{ 0100644, CONFLICTING_OURS_OID, 2, "conflicting-1.txt" },
|
||||
{ 0100644, CONFLICTING_THEIRS_OID, 3, "conflicting-1.txt" },
|
||||
|
||||
{ 0100644, CONFLICTING_ANCESTOR_OID, 1, "conflicting-2.txt" },
|
||||
{ 0100644, CONFLICTING_OURS_OID, 2, "conflicting-2.txt" },
|
||||
{ 0100644, CONFLICTING_THEIRS_OID, 3, "conflicting-2.txt" },
|
||||
|
||||
{ 0100644, AUTOMERGEABLE_ANCESTOR_OID, 1, "conflicting-3.txt" },
|
||||
{ 0100644, AUTOMERGEABLE_OURS_OID, 2, "conflicting-3.txt" },
|
||||
{ 0100644, AUTOMERGEABLE_THEIRS_OID, 3, "conflicting-3.txt" },
|
||||
|
||||
{ 0100644, AUTOMERGEABLE_ANCESTOR_OID, 1, "conflicting-4.txt" },
|
||||
{ 0100644, AUTOMERGEABLE_OURS_OID, 2, "conflicting-4.txt" },
|
||||
{ 0100644, AUTOMERGEABLE_THEIRS_OID, 3, "conflicting-4.txt" },
|
||||
};
|
||||
|
||||
opts.progress_cb = collect_progress;
|
||||
opts.progress_payload = &paths;
|
||||
|
||||
|
||||
create_index(checkout_index_entries, 12);
|
||||
git_index_write(g_index);
|
||||
|
||||
cl_git_pass(git_checkout_index(g_repo, g_index, &opts));
|
||||
|
||||
cl_assert_equal_i(4, git_vector_length(&paths));
|
||||
cl_assert_equal_s("conflicting-1.txt", git_vector_get(&paths, 0));
|
||||
cl_assert_equal_s("conflicting-2.txt", git_vector_get(&paths, 1));
|
||||
cl_assert_equal_s("conflicting-3.txt", git_vector_get(&paths, 2));
|
||||
cl_assert_equal_s("conflicting-4.txt", git_vector_get(&paths, 3));
|
||||
|
||||
git_vector_foreach(&paths, i, path)
|
||||
git__free(path);
|
||||
|
||||
git_vector_free(&paths);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user