Commit 216f97e4 by Edward Thomson

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.
parent cfae7f85
...@@ -29,18 +29,6 @@ ...@@ -29,18 +29,6 @@
/* See docs/checkout-internals.md for more information */ /* 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( static int checkout_notify(
checkout_data *data, checkout_data *data,
git_checkout_notify_t why, git_checkout_notify_t why,
...@@ -641,6 +629,14 @@ static int checkout_get_actions( ...@@ -641,6 +629,14 @@ static int checkout_get_actions(
goto fail; 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_pathspec__vfree(&pathspec);
git_pool_clear(&pathpool); git_pool_clear(&pathpool);
...@@ -841,7 +837,7 @@ static int checkout_submodule( ...@@ -841,7 +837,7 @@ static int checkout_submodule(
return checkout_submodule_update_index(data, file); return checkout_submodule_update_index(data, file);
} }
static void report_progress( void git_checkout__report_progress(
checkout_data *data, checkout_data *data,
const char *path) const char *path)
{ {
...@@ -965,7 +961,7 @@ static int checkout_remove_the_old( ...@@ -965,7 +961,7 @@ static int checkout_remove_the_old(
return error; return error;
data->completed_steps++; 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 && if ((actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) == 0 &&
(data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
...@@ -982,7 +978,7 @@ static int checkout_remove_the_old( ...@@ -982,7 +978,7 @@ static int checkout_remove_the_old(
return error; return error;
data->completed_steps++; data->completed_steps++;
report_progress(data, str); git_checkout__report_progress(data, str);
if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 && if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
data->index != NULL) data->index != NULL)
...@@ -1041,7 +1037,7 @@ static int checkout_create_the_new( ...@@ -1041,7 +1037,7 @@ static int checkout_create_the_new(
return error; return error;
data->completed_steps++; 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( ...@@ -1077,7 +1073,7 @@ static int checkout_create_submodules(
return error; return error;
data->completed_steps++; 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) ...@@ -1102,6 +1098,9 @@ static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
static void checkout_data_clear(checkout_data *data) static void checkout_data_clear(checkout_data *data)
{ {
checkout_conflictdata *conflict;
size_t i;
if (data->opts_free_baseline) { if (data->opts_free_baseline) {
git_tree_free(data->opts.baseline); git_tree_free(data->opts.baseline);
data->opts.baseline = NULL; data->opts.baseline = NULL;
...@@ -1110,6 +1109,11 @@ static void checkout_data_clear(checkout_data *data) ...@@ -1110,6 +1109,11 @@ static void checkout_data_clear(checkout_data *data)
git_vector_free(&data->removes); git_vector_free(&data->removes);
git_pool_clear(&data->pool); git_pool_clear(&data->pool);
git_vector_foreach(&data->conflicts, i, conflict)
git__free(conflict);
git_vector_free(&data->conflicts);
git__free(data->pfx); git__free(data->pfx);
data->pfx = NULL; data->pfx = NULL;
...@@ -1226,6 +1230,7 @@ static int checkout_data_init( ...@@ -1226,6 +1230,7 @@ static int checkout_data_init(
} }
if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 || 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_pool_init(&data->pool, 1, 0)) < 0 ||
(error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 || (error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 ||
(error = git_path_to_dir(&data->path)) < 0) (error = git_path_to_dir(&data->path)) < 0)
...@@ -1296,16 +1301,18 @@ int git_checkout_iterator( ...@@ -1296,16 +1301,18 @@ int git_checkout_iterator(
goto cleanup; goto cleanup;
/* Loop through diff (and working directory iterator) building a list of /* 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) if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) < 0)
goto cleanup; goto cleanup;
data.total_steps = counts[CHECKOUT_ACTION__REMOVE] + data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
counts[CHECKOUT_ACTION__UPDATE_BLOB] + 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 /* To deal with some order dependencies, perform remaining checkout
* in three passes: removes, then update blobs, then update submodules. * in three passes: removes, then update blobs, then update submodules.
...@@ -1322,10 +1329,11 @@ int git_checkout_iterator( ...@@ -1322,10 +1329,11 @@ int git_checkout_iterator(
(error = checkout_create_submodules(actions, &data)) < 0) (error = checkout_create_submodules(actions, &data)) < 0)
goto cleanup; 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 */ assert(data.completed_steps == data.total_steps);
error = git_checkout__conflicts(&data);
cleanup: cleanup:
if (error == GIT_EUSER) if (error == GIT_EUSER)
......
...@@ -22,6 +22,7 @@ typedef struct { ...@@ -22,6 +22,7 @@ typedef struct {
git_index *index; git_index *index;
git_pool pool; git_pool pool;
git_vector removes; git_vector removes;
git_vector conflicts;
git_buf path; git_buf path;
size_t workdir_len; size_t workdir_len;
unsigned int strategy; unsigned int strategy;
...@@ -31,6 +32,29 @@ typedef struct { ...@@ -31,6 +32,29 @@ typedef struct {
size_t completed_steps; size_t completed_steps;
} checkout_data; } 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 * Update the working directory to match the target iterator. The
* expected baseline value can be passed in via the checkout options * expected baseline value can be passed in via the checkout options
...@@ -52,6 +76,11 @@ int git_checkout__write_content( ...@@ -52,6 +76,11 @@ int git_checkout__write_content(
unsigned int mode, unsigned int mode,
struct stat *st); 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); int git_checkout__conflicts(checkout_data *data);
#endif #endif
...@@ -11,22 +11,13 @@ ...@@ -11,22 +11,13 @@
#include "vector.h" #include "vector.h"
#include "index.h" #include "index.h"
#include "pathspec.h"
#include "merge_file.h" #include "merge_file.h"
#include "git2/repository.h" #include "git2/repository.h"
#include "git2/types.h" #include "git2/types.h"
#include "git2/index.h" #include "git2/index.h"
#include "git2/sys/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( GIT_INLINE(int) checkout_idxentry_cmp(
const git_index_entry *a, const git_index_entry *a,
const git_index_entry *b) const git_index_entry *b)
...@@ -68,7 +59,34 @@ int checkout_conflictdata_empty(const git_vector *conflicts, size_t idx) ...@@ -68,7 +59,34 @@ int checkout_conflictdata_empty(const git_vector *conflicts, size_t idx)
return 1; 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; git_index_conflict_iterator *iterator = NULL;
const git_index_entry *ancestor, *ours, *theirs; const git_index_entry *ancestor, *ours, *theirs;
...@@ -78,11 +96,12 @@ static int checkout_conflicts_load(checkout_data *data, git_vector *conflicts) ...@@ -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) if ((error = git_index_conflict_iterator_new(&iterator, data->index)) < 0)
goto done; goto done;
conflicts->_cmp = checkout_conflictdata_cmp; data->conflicts._cmp = checkout_conflictdata_cmp;
/* Collect the conflicts */ /* Collect the conflicts */
while ((error = git_index_conflict_next( while ((error = git_index_conflict_next(&ancestor, &ours, &theirs, iterator)) == 0) {
&ancestor, &ours, &theirs, iterator)) == 0) { if (!conflict_pathspec_match(data, workdir, pathspec, ancestor, ours, theirs))
continue;
conflict = git__calloc(1, sizeof(checkout_conflictdata)); conflict = git__calloc(1, sizeof(checkout_conflictdata));
GITERR_CHECK_ALLOC(conflict); GITERR_CHECK_ALLOC(conflict);
...@@ -91,7 +110,7 @@ static int checkout_conflicts_load(checkout_data *data, git_vector *conflicts) ...@@ -91,7 +110,7 @@ static int checkout_conflicts_load(checkout_data *data, git_vector *conflicts)
conflict->ours = ours; conflict->ours = ours;
conflict->theirs = theirs; conflict->theirs = theirs;
git_vector_insert(conflicts, conflict); git_vector_insert(&data->conflicts, conflict);
} }
if (error == GIT_ITEROVER) if (error == GIT_ITEROVER)
...@@ -122,25 +141,25 @@ static int checkout_conflicts_cmp_ancestor(const void *p, const void *c) ...@@ -122,25 +141,25 @@ static int checkout_conflicts_cmp_ancestor(const void *p, const void *c)
} }
static checkout_conflictdata *checkout_conflicts_search_ancestor( static checkout_conflictdata *checkout_conflicts_search_ancestor(
git_vector *conflicts, checkout_data *data,
const char *path) const char *path)
{ {
size_t pos; 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 NULL;
return git_vector_get(conflicts, pos); return git_vector_get(&data->conflicts, pos);
} }
static checkout_conflictdata *checkout_conflicts_search_branch( static checkout_conflictdata *checkout_conflicts_search_branch(
git_vector *conflicts, checkout_data *data,
const char *path) const char *path)
{ {
checkout_conflictdata *conflict; checkout_conflictdata *conflict;
size_t i; size_t i;
git_vector_foreach(conflicts, i, conflict) { git_vector_foreach(&data->conflicts, i, conflict) {
int cmp = -1; int cmp = -1;
if (conflict->ancestor) if (conflict->ancestor)
...@@ -162,7 +181,7 @@ static int checkout_conflicts_load_byname_entry( ...@@ -162,7 +181,7 @@ static int checkout_conflicts_load_byname_entry(
checkout_conflictdata **ancestor_out, checkout_conflictdata **ancestor_out,
checkout_conflictdata **ours_out, checkout_conflictdata **ours_out,
checkout_conflictdata **theirs_out, checkout_conflictdata **theirs_out,
git_vector *conflicts, checkout_data *data,
const git_index_name_entry *name_entry) const git_index_name_entry *name_entry)
{ {
checkout_conflictdata *ancestor, *ours = NULL, *theirs = NULL; checkout_conflictdata *ancestor, *ours = NULL, *theirs = NULL;
...@@ -184,7 +203,7 @@ static int checkout_conflicts_load_byname_entry( ...@@ -184,7 +203,7 @@ static int checkout_conflicts_load_byname_entry(
goto done; goto done;
} }
if ((ancestor = checkout_conflicts_search_ancestor(conflicts, if ((ancestor = checkout_conflicts_search_ancestor(data,
name_entry->ancestor)) == NULL) { name_entry->ancestor)) == NULL) {
giterr_set(GITERR_INDEX, giterr_set(GITERR_INDEX,
"A NAME entry referenced ancestor entry '%s' which does not exist in the main 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( ...@@ -196,7 +215,7 @@ static int checkout_conflicts_load_byname_entry(
if (name_entry->ours) { if (name_entry->ours) {
if (strcmp(name_entry->ancestor, name_entry->ours) == 0) if (strcmp(name_entry->ancestor, name_entry->ours) == 0)
ours = ancestor; 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) { ours->ours == NULL) {
giterr_set(GITERR_INDEX, giterr_set(GITERR_INDEX,
"A NAME entry referenced our entry '%s' which does not exist in the main 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( ...@@ -211,7 +230,7 @@ static int checkout_conflicts_load_byname_entry(
theirs = ancestor; theirs = ancestor;
else if (name_entry->ours && strcmp(name_entry->ours, name_entry->theirs) == 0) else if (name_entry->ours && strcmp(name_entry->ours, name_entry->theirs) == 0)
theirs = ours; 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) { theirs->theirs == NULL) {
giterr_set(GITERR_INDEX, giterr_set(GITERR_INDEX,
"A NAME entry referenced their entry '%s' which does not exist in the main index", "A NAME entry referenced their entry '%s' which does not exist in the main index",
...@@ -230,8 +249,7 @@ done: ...@@ -230,8 +249,7 @@ done:
} }
static int checkout_conflicts_coalesce_renames( static int checkout_conflicts_coalesce_renames(
checkout_data *data, checkout_data *data)
git_vector *conflicts)
{ {
const git_index_name_entry *name_entry; const git_index_name_entry *name_entry;
checkout_conflictdata *ancestor_conflict, *our_conflict, *their_conflict; checkout_conflictdata *ancestor_conflict, *our_conflict, *their_conflict;
...@@ -239,15 +257,14 @@ static int checkout_conflicts_coalesce_renames( ...@@ -239,15 +257,14 @@ static int checkout_conflicts_coalesce_renames(
int error = 0; int error = 0;
/* Juggle entries based on renames */ /* Juggle entries based on renames */
for (i = 0, names = git_index_name_entrycount(data->index); names = git_index_name_entrycount(data->index);
i < names;
i++) {
for (i = 0; i < names; i++) {
name_entry = git_index_name_get_byindex(data->index, i); name_entry = git_index_name_get_byindex(data->index, i);
if ((error = checkout_conflicts_load_byname_entry( if ((error = checkout_conflicts_load_byname_entry(
&ancestor_conflict, &our_conflict, &their_conflict, &ancestor_conflict, &our_conflict, &their_conflict,
conflicts, name_entry)) < 0) data, name_entry)) < 0)
goto done; goto done;
if (our_conflict && our_conflict != ancestor_conflict) { if (our_conflict && our_conflict != ancestor_conflict) {
...@@ -277,7 +294,7 @@ static int checkout_conflicts_coalesce_renames( ...@@ -277,7 +294,7 @@ static int checkout_conflicts_coalesce_renames(
ancestor_conflict->one_to_two = 1; ancestor_conflict->one_to_two = 1;
} }
git_vector_remove_matching(conflicts, checkout_conflictdata_empty); git_vector_remove_matching(&data->conflicts, checkout_conflictdata_empty);
done: done:
return error; return error;
...@@ -307,8 +324,7 @@ GIT_INLINE(void) path_equal_or_prefixed( ...@@ -307,8 +324,7 @@ GIT_INLINE(void) path_equal_or_prefixed(
} }
static int checkout_conflicts_mark_directoryfile( static int checkout_conflicts_mark_directoryfile(
checkout_data *data, checkout_data *data)
git_vector *conflicts)
{ {
checkout_conflictdata *conflict; checkout_conflictdata *conflict;
const git_index_entry *entry; const git_index_entry *entry;
...@@ -320,7 +336,7 @@ static int checkout_conflicts_mark_directoryfile( ...@@ -320,7 +336,7 @@ static int checkout_conflicts_mark_directoryfile(
len = git_index_entrycount(data->index); len = git_index_entrycount(data->index);
/* Find d/f conflicts */ /* Find d/f conflicts */
git_vector_foreach(conflicts, i, conflict) { git_vector_foreach(&data->conflicts, i, conflict) {
if ((conflict->ours && conflict->theirs) || if ((conflict->ours && conflict->theirs) ||
(!conflict->ours && !conflict->theirs)) (!conflict->ours && !conflict->theirs))
continue; continue;
...@@ -560,22 +576,30 @@ done: ...@@ -560,22 +576,30 @@ done:
return error; return error;
} }
int git_checkout__conflicts(checkout_data *data) int git_checkout__get_conflicts(checkout_data *data, git_iterator *workdir, git_vector *pathspec)
{ {
git_vector conflicts = GIT_VECTOR_INIT;
checkout_conflictdata *conflict;
size_t i;
int error = 0; int error = 0;
if (data->strategy & GIT_CHECKOUT_SKIP_UNMERGED) if (data->strategy & GIT_CHECKOUT_SKIP_UNMERGED)
return 0; return 0;
if ((error = checkout_conflicts_load(data, &conflicts)) < 0 || if ((error = checkout_conflicts_load(data, workdir, pathspec)) < 0 ||
(error = checkout_conflicts_coalesce_renames(data, &conflicts)) < 0 || (error = checkout_conflicts_coalesce_renames(data)) < 0 ||
(error = checkout_conflicts_mark_directoryfile(data, &conflicts)) < 0) (error = checkout_conflicts_mark_directoryfile(data)) < 0)
goto done; goto done;
git_vector_foreach(&conflicts, i, conflict) { done:
return error;
}
int git_checkout__conflicts(checkout_data *data)
{
git_vector conflicts = GIT_VECTOR_INIT;
checkout_conflictdata *conflict;
size_t i;
int error = 0;
git_vector_foreach(&data->conflicts, i, conflict) {
/* Both deleted: nothing to do */ /* Both deleted: nothing to do */
if (conflict->ours == NULL && conflict->theirs == NULL) if (conflict->ours == NULL && conflict->theirs == NULL)
error = 0; error = 0;
...@@ -621,13 +645,15 @@ int git_checkout__conflicts(checkout_data *data) ...@@ -621,13 +645,15 @@ int git_checkout__conflicts(checkout_data *data)
else else
error = checkout_write_merge(data, conflict); error = checkout_write_merge(data, conflict);
}
done: if (error)
git_vector_foreach(&conflicts, i, conflict) break;
git__free(conflict);
git_vector_free(&conflicts); data->completed_steps++;
git_checkout__report_progress(data,
conflict->ours ? conflict->ours->path :
(conflict->theirs ? conflict->theirs->path : conflict->ancestor->path));
}
return error; return error;
} }
...@@ -1022,3 +1022,103 @@ void test_checkout_conflict__update_only(void) ...@@ -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-one~ours"));
cl_assert(!git_path_exists("merge-resolve/directory_file-two~theirs")); 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment