Commit ff8d635a by Carlos Martín Nieto

Merge pull request #3139 from ethomson/diff_conflicts

Include conflicts when diffing
parents fb92b48d 9b3e41f7
......@@ -49,6 +49,13 @@ support for HTTPS connections insead of OpenSSL.
the error message, which allows you to get the "repository not
found" messages.
* `git_index_conflict_add()` will remove staged entries that exist for
conflicted paths.
* The flags for a `git_diff_file` will now have the `GIT_DIFF_FLAG_EXISTS`
bit set when a file exists on that side of the diff. This is useful
for understanding whether a side of the diff exists in the presence of
a conflict.
### API additions
......@@ -98,6 +105,18 @@ support for HTTPS connections insead of OpenSSL.
configuration of the server, and tools can use this to show messages
about failing to communicate with the server.
* `git_diff_index_to_workdir()` and `git_diff_tree_to_index()` will now
produce deltas of type `GIT_DELTA_CONFLICTED` to indicate that the index
side of the delta is a conflict.
* The `git_status` family of functions will now produce status of type
`GIT_STATUS_CONFLICTED` to indicate that a conflict exists for that file
in the index.
* `git_index_entry_is_conflict()` is a utility function to determine if
a given index entry has a non-zero stage entry, indicating that it is
one side of a conflict.
### API removals
* `git_remote_save()` and `git_remote_clear_refspecs()` have been
......
......@@ -226,6 +226,7 @@ typedef enum {
GIT_DIFF_FLAG_BINARY = (1u << 0), /**< file(s) treated as binary data */
GIT_DIFF_FLAG_NOT_BINARY = (1u << 1), /**< file(s) treated as text data */
GIT_DIFF_FLAG_VALID_ID = (1u << 2), /**< `id` value is known correct */
GIT_DIFF_FLAG_EXISTS = (1u << 3), /**< file exists at this side of the delta */
} git_diff_flag_t;
/**
......@@ -239,16 +240,17 @@ typedef enum {
* DELETED pairs).
*/
typedef enum {
GIT_DELTA_UNMODIFIED = 0, /**< no changes */
GIT_DELTA_ADDED = 1, /**< entry does not exist in old version */
GIT_DELTA_DELETED = 2, /**< entry does not exist in new version */
GIT_DELTA_MODIFIED = 3, /**< entry content changed between old and new */
GIT_DELTA_RENAMED = 4, /**< entry was renamed between old and new */
GIT_DELTA_COPIED = 5, /**< entry was copied from another old entry */
GIT_DELTA_IGNORED = 6, /**< entry is ignored item in workdir */
GIT_DELTA_UNTRACKED = 7, /**< entry is untracked item in workdir */
GIT_DELTA_TYPECHANGE = 8, /**< type of entry changed between old and new */
GIT_DELTA_UNREADABLE = 9, /**< entry is unreadable */
GIT_DELTA_UNMODIFIED = 0, /**< no changes */
GIT_DELTA_ADDED = 1, /**< entry does not exist in old version */
GIT_DELTA_DELETED = 2, /**< entry does not exist in new version */
GIT_DELTA_MODIFIED = 3, /**< entry content changed between old and new */
GIT_DELTA_RENAMED = 4, /**< entry was renamed between old and new */
GIT_DELTA_COPIED = 5, /**< entry was copied from another old entry */
GIT_DELTA_IGNORED = 6, /**< entry is ignored item in workdir */
GIT_DELTA_UNTRACKED = 7, /**< entry is untracked item in workdir */
GIT_DELTA_TYPECHANGE = 8, /**< type of entry changed between old and new */
GIT_DELTA_UNREADABLE = 9, /**< entry is unreadable */
GIT_DELTA_CONFLICTED = 10, /**< entry in the index is conflicted */
} git_delta_t;
/**
......
......@@ -430,6 +430,15 @@ GIT_EXTERN(int) git_index_add(git_index *index, const git_index_entry *source_en
*/
GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry);
/**
* Return whether the given index entry is a conflict (has a high stage
* entry). This is simply shorthand for `git_index_entry_stage > 0`.
*
* @param entry The entry
* @return 1 if the entry is a conflict entry, 0 otherwise
*/
GIT_EXTERN(int) git_index_entry_is_conflict(const git_index_entry *entry);
/**@}*/
/** @name Workdir Index Entry Functions
......@@ -631,7 +640,8 @@ GIT_EXTERN(int) git_index_find(size_t *at_pos, git_index *index, const char *pat
/**@{*/
/**
* Add or update index entries to represent a conflict
* Add or update index entries to represent a conflict. Any staged
* entries that exist at the given paths will be removed.
*
* The entries are the entries from the tree included in the merge. Any
* entry may be null to indicate that that file was not present in the
......
......@@ -46,6 +46,7 @@ typedef enum {
GIT_STATUS_WT_UNREADABLE = (1u << 12),
GIT_STATUS_IGNORED = (1u << 14),
GIT_STATUS_CONFLICTED = (1u << 15),
} git_status_t;
/**
......
......@@ -1173,6 +1173,9 @@ int git_index_remove_bypath(git_index *index, const char *path)
ret != GIT_ENOTFOUND))
return ret;
if (ret == GIT_ENOTFOUND)
giterr_clear();
return 0;
}
......@@ -1314,6 +1317,30 @@ int git_index_conflict_add(git_index *index,
(ret = index_entry_dup(&entries[2], INDEX_OWNER(index), their_entry)) < 0)
goto on_error;
/* Validate entries */
for (i = 0; i < 3; i++) {
if (entries[i] && !valid_filemode(entries[i]->mode)) {
giterr_set(GITERR_INDEX, "invalid filemode for stage %d entry",
i);
return -1;
}
}
/* Remove existing index entries for each path */
for (i = 0; i < 3; i++) {
if (entries[i] == NULL)
continue;
if ((ret = git_index_remove(index, entries[i]->path, 0)) != 0) {
if (ret != GIT_ENOTFOUND)
goto on_error;
giterr_clear();
ret = 0;
}
}
/* Add the conflict entries */
for (i = 0; i < 3; i++) {
if (entries[i] == NULL)
continue;
......@@ -1321,7 +1348,7 @@ int git_index_conflict_add(git_index *index,
/* Make sure stage is correct */
GIT_IDXENTRY_STAGE_SET(entries[i], i + 1);
if ((ret = index_insert(index, &entries[i], 1, true)) < 0)
if ((ret = index_insert(index, &entries[i], 0, true)) < 0)
goto on_error;
entries[i] = NULL; /* don't free if later entry fails */
......@@ -1510,7 +1537,7 @@ int git_index_conflict_next(
while (iterator->cur < iterator->index->entries.length) {
entry = git_index_get_byindex(iterator->index, iterator->cur);
if (git_index_entry_stage(entry) > 0) {
if (git_index_entry_is_conflict(entry)) {
if ((len = index_conflict__get_byindex(
ancestor_out,
our_out,
......@@ -2356,6 +2383,11 @@ int git_index_entry_stage(const git_index_entry *entry)
return GIT_IDXENTRY_STAGE(entry);
}
int git_index_entry_is_conflict(const git_index_entry *entry)
{
return (GIT_IDXENTRY_STAGE(entry) > 0);
}
typedef struct read_tree_data {
git_index *index;
git_vector *old_entries;
......@@ -2638,7 +2670,8 @@ static int apply_each_file(const git_diff_delta *delta, float progress, void *pa
if (error < 0) /* actual error */
return error;
if (delta->status == GIT_DELTA_DELETED)
/* If the workdir item does not exist, remove it from the index. */
if ((delta->new_file.flags & GIT_DIFF_FLAG_EXISTS) == 0)
error = git_index_remove_bypath(data->index, path);
else
error = git_index_add_bypath(data->index, delta->new_file.path);
......
......@@ -46,6 +46,7 @@
#define iterator__include_trees(I) iterator__flag(I,INCLUDE_TREES)
#define iterator__dont_autoexpand(I) iterator__flag(I,DONT_AUTOEXPAND)
#define iterator__do_autoexpand(I) !iterator__flag(I,DONT_AUTOEXPAND)
#define iterator__include_conflicts(I) iterator__flag(I, INCLUDE_CONFLICTS)
#define GIT_ITERATOR_FIRST_ACCESS (1 << 15)
#define iterator__has_been_accessed(I) iterator__flag(I,FIRST_ACCESS)
......@@ -668,13 +669,16 @@ static const git_index_entry *index_iterator__index_entry(index_iterator *ii)
return ie;
}
static const git_index_entry *index_iterator__skip_conflicts(index_iterator *ii)
static const git_index_entry *index_iterator__advance_over_conflicts(index_iterator *ii)
{
const git_index_entry *ie;
const git_index_entry *ie = index_iterator__index_entry(ii);
while ((ie = index_iterator__index_entry(ii)) != NULL &&
git_index_entry_stage(ie) != 0)
ii->current++;
if (!iterator__include_conflicts(ii)) {
while (ie && git_index_entry_is_conflict(ie)) {
ii->current++;
ie = index_iterator__index_entry(ii);
}
}
return ie;
}
......@@ -702,7 +706,7 @@ static void index_iterator__next_prefix_tree(index_iterator *ii)
static int index_iterator__first_prefix_tree(index_iterator *ii)
{
const git_index_entry *ie = index_iterator__skip_conflicts(ii);
const git_index_entry *ie = index_iterator__advance_over_conflicts(ii);
const char *scan, *prior, *slash;
if (!ie || !iterator__include_trees(ii))
......@@ -825,7 +829,7 @@ static int index_iterator__reset(
git_index_snapshot_find(
&ii->current, &ii->entries, ii->entry_srch, ii->base.start, 0, 0);
if ((ie = index_iterator__skip_conflicts(ii)) == NULL)
if ((ie = index_iterator__advance_over_conflicts(ii)) == NULL)
return 0;
if (git_buf_sets(&ii->partial, ie->path) < 0)
......
......@@ -33,6 +33,8 @@ typedef enum {
GIT_ITERATOR_DONT_AUTOEXPAND = (1u << 3),
/** convert precomposed unicode to decomposed unicode */
GIT_ITERATOR_PRECOMPOSE_UNICODE = (1u << 4),
/** include conflicts */
GIT_ITERATOR_INCLUDE_CONFLICTS = (1u << 5),
} git_iterator_flag_t;
typedef struct {
......
......@@ -2492,7 +2492,7 @@ int git_merge__check_result(git_repository *repo, git_index *index_new)
for (i = 0; i < git_index_entrycount(index_new); i++) {
e = git_index_get_byindex(index_new, i);
if (git_index_entry_stage(e) != 0 &&
if (git_index_entry_is_conflict(e) &&
(git_vector_last(&paths) == NULL ||
strcmp(git_vector_last(&paths), e->path) != 0)) {
......@@ -2544,7 +2544,7 @@ int git_merge__append_conflicts_to_merge_msg(
for (i = 0; i < git_index_entrycount(index); i++) {
const git_index_entry *e = git_index_get_byindex(index, i);
if (git_index_entry_stage(e) == 0)
if (!git_index_entry_is_conflict(e))
continue;
if (last == NULL || strcmp(e->path, last) != 0)
......
......@@ -63,6 +63,7 @@ int git_reset_default(
assert(delta->status == GIT_DELTA_ADDED ||
delta->status == GIT_DELTA_MODIFIED ||
delta->status == GIT_DELTA_CONFLICTED ||
delta->status == GIT_DELTA_DELETED);
error = git_index_conflict_remove(index, delta->old_file.path);
......
......@@ -44,6 +44,9 @@ static unsigned int index_delta2status(const git_diff_delta *head2idx)
case GIT_DELTA_TYPECHANGE:
st = GIT_STATUS_INDEX_TYPECHANGE;
break;
case GIT_DELTA_CONFLICTED:
st = GIT_STATUS_CONFLICTED;
break;
default:
break;
}
......@@ -102,6 +105,9 @@ static unsigned int workdir_delta2status(
case GIT_DELTA_TYPECHANGE:
st = GIT_STATUS_WT_TYPECHANGE;
break;
case GIT_DELTA_CONFLICTED:
st = GIT_STATUS_CONFLICTED;
break;
default:
break;
}
......
......@@ -102,7 +102,7 @@ static void create_index(struct checkout_index_entry *entries, size_t entries_le
memset(&entry, 0x0, sizeof(git_index_entry));
entry.mode = entries[i].mode;
entry.flags = entries[i].stage << GIT_IDXENTRY_STAGESHIFT;
GIT_IDXENTRY_STAGE_SET(&entry, entries[i].stage);
git_oid_fromstr(&entry.id, entries[i].oid_str);
entry.path = entries[i].path;
......
......@@ -685,15 +685,15 @@ static void add_conflict(git_index *index, const char *path)
entry.path = path;
git_oid_fromstr(&entry.id, "d427e0b2e138501a3d15cc376077a3631e15bd46");
entry.flags = (1 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&entry, 1);
cl_git_pass(git_index_add(index, &entry));
git_oid_fromstr(&entry.id, "4e886e602529caa9ab11d71f86634bd1b6e0de10");
entry.flags = (2 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&entry, 2);
cl_git_pass(git_index_add(index, &entry));
git_oid_fromstr(&entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863");
entry.flags = (3 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&entry, 3);
cl_git_pass(git_index_add(index, &entry));
}
......
......@@ -893,16 +893,16 @@ static void create_conflict(const char *path)
memset(&entry, 0x0, sizeof(git_index_entry));
entry.mode = 0100644;
entry.flags = 1 << GIT_IDXENTRY_STAGESHIFT;
GIT_IDXENTRY_STAGE_SET(&entry, 1);
git_oid_fromstr(&entry.id, "d427e0b2e138501a3d15cc376077a3631e15bd46");
entry.path = path;
cl_git_pass(git_index_add(index, &entry));
entry.flags = 2 << GIT_IDXENTRY_STAGESHIFT;
GIT_IDXENTRY_STAGE_SET(&entry, 2);
git_oid_fromstr(&entry.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
cl_git_pass(git_index_add(index, &entry));
entry.flags = 3 << GIT_IDXENTRY_STAGESHIFT;
GIT_IDXENTRY_STAGE_SET(&entry, 3);
git_oid_fromstr(&entry.id, "2bd0a343aeef7a2cf0d158478966a6e587ff3863");
cl_git_pass(git_index_add(index, &entry));
......
......@@ -197,6 +197,14 @@ git_repository *cl_git_sandbox_init(const char *sandbox)
return _cl_repo;
}
git_repository *cl_git_sandbox_init_new(const char *sandbox)
{
cl_git_pass(git_repository_init(&_cl_repo, sandbox, false));
_cl_sandbox = sandbox;
return _cl_repo;
}
git_repository *cl_git_sandbox_reopen(void)
{
if (_cl_repo) {
......
......@@ -127,6 +127,7 @@ int cl_rename(const char *source, const char *dest);
/* Git sandbox setup helpers */
git_repository *cl_git_sandbox_init(const char *sandbox);
git_repository *cl_git_sandbox_init_new(const char *name);
void cl_git_sandbox_cleanup(void);
git_repository *cl_git_sandbox_reopen(void);
......
......@@ -68,7 +68,7 @@ int diff_file_cb(
if ((delta->flags & GIT_DIFF_FLAG_BINARY) != 0)
e->files_binary++;
cl_assert(delta->status <= GIT_DELTA_TYPECHANGE);
cl_assert(delta->status <= GIT_DELTA_CONFLICTED);
e->file_status[delta->status] += 1;
......
......@@ -8,7 +8,7 @@ typedef struct {
int files;
int files_binary;
int file_status[10]; /* indexed by git_delta_t value */
int file_status[11]; /* indexed by git_delta_t value */
int hunks;
int hunk_new_lines;
......
......@@ -163,3 +163,79 @@ void test_diff_index__checks_options_version(void)
git_tree_free(a);
}
static void do_conflicted_diff(diff_expects *exp, unsigned long flags)
{
const char *a_commit = "26a125ee1bf"; /* the current HEAD */
git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit);
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_index_entry ancestor = {0}, ours = {0}, theirs = {0};
git_diff *diff = NULL;
git_index *index;
cl_assert(a);
opts.context_lines = 1;
opts.interhunk_lines = 1;
opts.flags |= flags;
memset(exp, 0, sizeof(diff_expects));
cl_git_pass(git_repository_index(&index, g_repo));
ancestor.path = ours.path = theirs.path = "staged_changes";
ancestor.mode = ours.mode = theirs.mode = 0100644;
git_oid_fromstr(&ancestor.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
git_oid_fromstr(&ours.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
git_oid_fromstr(&theirs.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
cl_git_pass(git_index_conflict_add(index, &ancestor, &ours, &theirs));
cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, index, &opts));
cl_git_pass(git_diff_foreach(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, exp));
git_diff_free(diff);
git_tree_free(a);
git_index_free(index);
}
void test_diff_index__reports_conflicts(void)
{
diff_expects exp;
do_conflicted_diff(&exp, 0);
cl_assert_equal_i(8, exp.files);
cl_assert_equal_i(3, exp.file_status[GIT_DELTA_ADDED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_CONFLICTED]);
cl_assert_equal_i(7, exp.hunks);
cl_assert_equal_i(9, exp.lines);
cl_assert_equal_i(2, exp.line_ctxt);
cl_assert_equal_i(5, exp.line_adds);
cl_assert_equal_i(2, exp.line_dels);
}
void test_diff_index__reports_conflicts_when_reversed(void)
{
diff_expects exp;
do_conflicted_diff(&exp, GIT_DIFF_REVERSE);
cl_assert_equal_i(8, exp.files);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_ADDED]);
cl_assert_equal_i(3, exp.file_status[GIT_DELTA_DELETED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_CONFLICTED]);
cl_assert_equal_i(7, exp.hunks);
cl_assert_equal_i(9, exp.lines);
cl_assert_equal_i(2, exp.line_ctxt);
cl_assert_equal_i(2, exp.line_adds);
cl_assert_equal_i(5, exp.line_dels);
}
......@@ -68,6 +68,51 @@ void test_diff_workdir__to_index(void)
git_diff_free(diff);
}
void test_diff_workdir__to_index_with_conflicts(void)
{
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff *diff = NULL;
git_index *index;
git_index_entry our_entry = {0}, their_entry = {0};
diff_expects exp = {0};
g_repo = cl_git_sandbox_init("status");
opts.context_lines = 3;
opts.interhunk_lines = 1;
/* Adding an entry that represents a rename gets two files in conflict */
our_entry.path = "subdir/modified_file";
our_entry.mode = 0100644;
their_entry.path = "subdir/rename_conflict";
their_entry.mode = 0100644;
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_conflict_add(index, NULL, &our_entry, &their_entry));
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, index, &opts));
cl_git_pass(diff_foreach_via_iterator(
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
cl_assert_equal_i(9, exp.files);
cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]);
cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(2, exp.file_status[GIT_DELTA_CONFLICTED]);
cl_assert_equal_i(7, exp.hunks);
cl_assert_equal_i(12, exp.lines);
cl_assert_equal_i(4, exp.line_ctxt);
cl_assert_equal_i(3, exp.line_adds);
cl_assert_equal_i(5, exp.line_dels);
git_diff_free(diff);
git_index_free(index);
}
void test_diff_workdir__to_index_with_assume_unchanged(void)
{
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
......
......@@ -57,7 +57,7 @@ void test_index_collision__add_with_highstage_1(void)
git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391");
entry.path = "a/b";
entry.flags = (2 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&entry, 2);
cl_git_pass(git_index_add(index, &entry));
/* create a blob beneath the previous tree entry */
......@@ -67,7 +67,7 @@ void test_index_collision__add_with_highstage_1(void)
/* create another tree entry above the blob */
entry.path = "a/b";
entry.flags = (1 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&entry, 1);
cl_git_pass(git_index_add(index, &entry));
git_index_free(index);
......@@ -89,17 +89,17 @@ void test_index_collision__add_with_highstage_2(void)
git_oid_fromstr(&entry.id, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391");
entry.path = "a/b/c";
entry.flags = (1 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&entry, 1);
cl_git_pass(git_index_add(index, &entry));
/* create a blob beneath the previous tree entry */
entry.path = "a/b/c";
entry.flags = (2 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&entry, 2);
cl_git_pass(git_index_add(index, &entry));
/* create another tree entry above the blob */
entry.path = "a/b";
entry.flags = (3 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&entry, 3);
cl_git_pass(git_index_add(index, &entry));
git_index_free(index);
......
......@@ -16,6 +16,7 @@ static git_index *repo_index;
#define CONFLICTS_TWO_OUR_OID "8b3f43d2402825c200f835ca1762413e386fd0b2"
#define CONFLICTS_TWO_THEIR_OID "220bd62631c8cf7a83ef39c6b94595f00517211e"
#define TEST_STAGED_OID "beefdadafeedabedcafedeedbabedeadbeaddeaf"
#define TEST_ANCESTOR_OID "f00ff00ff00ff00ff00ff00ff00ff00ff00ff00f"
#define TEST_OUR_OID "b44bb44bb44bb44bb44bb44bb44bb44bb44bb44b"
#define TEST_THEIR_OID "0123456789abcdef0123456789abcdef01234567"
......@@ -46,15 +47,18 @@ void test_index_conflicts__add(void)
memset(&their_entry, 0x0, sizeof(git_index_entry));
ancestor_entry.path = "test-one.txt";
ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT);
ancestor_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&ancestor_entry, 1);
git_oid_fromstr(&ancestor_entry.id, TEST_ANCESTOR_OID);
our_entry.path = "test-one.txt";
ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT);
our_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&our_entry, 2);
git_oid_fromstr(&our_entry.id, TEST_OUR_OID);
their_entry.path = "test-one.txt";
ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT);
their_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&ancestor_entry, 2);
git_oid_fromstr(&their_entry.id, TEST_THEIR_OID);
cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry));
......@@ -74,15 +78,18 @@ void test_index_conflicts__add_fixes_incorrect_stage(void)
memset(&their_entry, 0x0, sizeof(git_index_entry));
ancestor_entry.path = "test-one.txt";
ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT);
ancestor_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&ancestor_entry, 3);
git_oid_fromstr(&ancestor_entry.id, TEST_ANCESTOR_OID);
our_entry.path = "test-one.txt";
ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT);
our_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&our_entry, 1);
git_oid_fromstr(&our_entry.id, TEST_OUR_OID);
their_entry.path = "test-one.txt";
ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT);
their_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&their_entry, 2);
git_oid_fromstr(&their_entry.id, TEST_THEIR_OID);
cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry));
......@@ -96,6 +103,55 @@ void test_index_conflicts__add_fixes_incorrect_stage(void)
cl_assert(git_index_entry_stage(conflict_entry[2]) == 3);
}
void test_index_conflicts__add_removes_stage_zero(void)
{
git_index_entry staged, ancestor_entry, our_entry, their_entry;
const git_index_entry *conflict_entry[3];
cl_assert(git_index_entrycount(repo_index) == 8);
memset(&staged, 0x0, sizeof(git_index_entry));
memset(&ancestor_entry, 0x0, sizeof(git_index_entry));
memset(&our_entry, 0x0, sizeof(git_index_entry));
memset(&their_entry, 0x0, sizeof(git_index_entry));
staged.path = "test-one.txt";
staged.mode = 0100644;
git_oid_fromstr(&staged.id, TEST_STAGED_OID);
cl_git_pass(git_index_add(repo_index, &staged));
cl_assert(git_index_entrycount(repo_index) == 9);
ancestor_entry.path = "test-one.txt";
ancestor_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&ancestor_entry, 3);
git_oid_fromstr(&ancestor_entry.id, TEST_ANCESTOR_OID);
our_entry.path = "test-one.txt";
our_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&our_entry, 1);
git_oid_fromstr(&our_entry.id, TEST_OUR_OID);
their_entry.path = "test-one.txt";
their_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&their_entry, 2);
git_oid_fromstr(&their_entry.id, TEST_THEIR_OID);
cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, &our_entry, &their_entry));
cl_assert(git_index_entrycount(repo_index) == 11);
cl_assert_equal_p(NULL, git_index_get_bypath(repo_index, "test-one.txt", 0));
cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], repo_index, "test-one.txt"));
cl_assert_equal_oid(&ancestor_entry.id, &conflict_entry[0]->id);
cl_assert_equal_i(1, git_index_entry_stage(conflict_entry[0]));
cl_assert_equal_oid(&our_entry.id, &conflict_entry[1]->id);
cl_assert_equal_i(2, git_index_entry_stage(conflict_entry[1]));
cl_assert_equal_oid(&their_entry.id, &conflict_entry[2]->id);
cl_assert_equal_i(3, git_index_entry_stage(conflict_entry[2]));
}
void test_index_conflicts__get(void)
{
const git_index_entry *conflict_entry[3];
......@@ -216,7 +272,7 @@ void test_index_conflicts__moved_to_reuc_on_add(void)
cl_assert(entry = git_index_get_byindex(repo_index, i));
if (strcmp(entry->path, "conflicts-one.txt") == 0)
cl_assert(git_index_entry_stage(entry) == 0);
cl_assert(!git_index_entry_is_conflict(entry));
}
}
......@@ -256,7 +312,7 @@ void test_index_conflicts__remove_all_conflicts(void)
for (i = 0; i < git_index_entrycount(repo_index); i++) {
cl_assert(entry = git_index_get_byindex(repo_index, i));
cl_assert(git_index_entry_stage(entry) == 0);
cl_assert(!git_index_entry_is_conflict(entry));
}
}
......@@ -272,7 +328,8 @@ void test_index_conflicts__partial(void)
memset(&their_entry, 0x0, sizeof(git_index_entry));
ancestor_entry.path = "test-one.txt";
ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT);
ancestor_entry.mode = 0100644;
GIT_IDXENTRY_STAGE_SET(&ancestor_entry, 1);
git_oid_fromstr(&ancestor_entry.id, TEST_ANCESTOR_OID);
cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, NULL, NULL));
......
......@@ -71,7 +71,7 @@ static int merge_trivial_conflict_entrycount(git_index *index)
for (i = 0; i < git_index_entrycount(index); i++) {
cl_assert(entry = git_index_get_byindex(index, i));
if (git_index_entry_stage(entry) > 0)
if (git_index_entry_is_conflict(entry))
count++;
}
......
......@@ -66,7 +66,7 @@ static size_t merge_trivial_conflict_entrycount(void)
for (i = 0; i < git_index_entrycount(repo_index); i++) {
cl_assert(entry = git_index_get_byindex(repo_index, i));
if (git_index_entry_stage(entry) > 0)
if (git_index_entry_is_conflict(entry))
count++;
}
......
......@@ -126,17 +126,17 @@ static void add_fake_conflicts(git_index *index)
ancestor_entry.path = "duplicate";
ancestor_entry.mode = GIT_FILEMODE_BLOB;
ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&ancestor_entry, 1);
git_oid_fromstr(&ancestor_entry.id, "a8233120f6ad708f843d861ce2b7228ec4e3dec6");
our_entry.path = "duplicate";
our_entry.mode = GIT_FILEMODE_BLOB;
ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&our_entry, 2);
git_oid_fromstr(&our_entry.id, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057");
their_entry.path = "duplicate";
their_entry.mode = GIT_FILEMODE_BLOB;
ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&their_entry, 3);
git_oid_fromstr(&their_entry.id, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd");
cl_git_pass(git_index_conflict_add(index, &ancestor_entry, &our_entry, &their_entry));
......
......@@ -108,7 +108,7 @@ static void index_entry_init(git_index *index, int side, git_oid *oid)
memset(&entry, 0x0, sizeof(git_index_entry));
entry.path = "conflicting_file";
entry.flags = (side << GIT_IDXENTRY_STAGESHIFT);
GIT_IDXENTRY_STAGE_SET(&entry, side);
entry.mode = 0100644;
git_oid_cpy(&entry.id, oid);
......
......@@ -461,14 +461,17 @@ void test_status_worktree__conflict_with_diff3(void)
memset(&their_entry, 0x0, sizeof(git_index_entry));
ancestor_entry.path = "modified_file";
ancestor_entry.mode = 0100644;
git_oid_fromstr(&ancestor_entry.id,
"452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
our_entry.path = "modified_file";
our_entry.mode = 0100644;
git_oid_fromstr(&our_entry.id,
"452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
their_entry.path = "modified_file";
their_entry.mode = 0100644;
git_oid_fromstr(&their_entry.id,
"452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
......@@ -484,7 +487,7 @@ void test_status_worktree__conflict_with_diff3(void)
cl_git_pass(git_status_file(&status, repo, "modified_file"));
cl_assert_equal_i(GIT_STATUS_INDEX_DELETED | GIT_STATUS_WT_NEW, status);
cl_assert_equal_i(GIT_STATUS_CONFLICTED, status);
}
static const char *filemode_paths[] = {
......@@ -614,14 +617,17 @@ void test_status_worktree__conflicted_item(void)
memset(&our_entry, 0x0, sizeof(git_index_entry));
memset(&their_entry, 0x0, sizeof(git_index_entry));
ancestor_entry.mode = 0100644;
ancestor_entry.path = "modified_file";
git_oid_fromstr(&ancestor_entry.id,
"452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
our_entry.mode = 0100644;
our_entry.path = "modified_file";
git_oid_fromstr(&our_entry.id,
"452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
their_entry.mode = 0100644;
their_entry.path = "modified_file";
git_oid_fromstr(&their_entry.id,
"452e4244b5d083ddf0460acf1ecc74db9dcfa11a");
......@@ -634,9 +640,55 @@ void test_status_worktree__conflicted_item(void)
&our_entry, &their_entry));
cl_git_pass(git_status_file(&status, repo, "modified_file"));
cl_assert_equal_i(GIT_STATUS_WT_MODIFIED, status);
cl_assert_equal_i(GIT_STATUS_CONFLICTED, status);
git_index_free(index);
}
void test_status_worktree__conflict_has_no_oid(void)
{
git_repository *repo = cl_git_sandbox_init("status");
git_index *index;
git_index_entry entry = {0};
git_status_list *statuslist;
const git_status_entry *status;
git_oid zero_id = {0};
entry.mode = 0100644;
entry.path = "modified_file";
git_oid_fromstr(&entry.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_conflict_add(index, &entry, &entry, &entry));
git_status_list_new(&statuslist, repo, NULL);
cl_assert_equal_i(16, git_status_list_entrycount(statuslist));
status = git_status_byindex(statuslist, 2);
cl_assert_equal_i(GIT_STATUS_CONFLICTED, status->status);
cl_assert_equal_s("modified_file", status->head_to_index->old_file.path);
cl_assert(!git_oid_equal(&zero_id, &status->head_to_index->old_file.id));
cl_assert(0 != status->head_to_index->old_file.mode);
cl_assert_equal_s("modified_file", status->head_to_index->new_file.path);
cl_assert_equal_oid(&zero_id, &status->head_to_index->new_file.id);
cl_assert_equal_i(0, status->head_to_index->new_file.mode);
cl_assert_equal_i(0, status->head_to_index->new_file.size);
cl_assert_equal_s("modified_file", status->index_to_workdir->old_file.path);
cl_assert_equal_oid(&zero_id, &status->index_to_workdir->old_file.id);
cl_assert_equal_i(0, status->index_to_workdir->old_file.mode);
cl_assert_equal_i(0, status->index_to_workdir->old_file.size);
cl_assert_equal_s("modified_file", status->index_to_workdir->new_file.path);
cl_assert(
!git_oid_equal(&zero_id, &status->index_to_workdir->new_file.id) ||
!(status->index_to_workdir->new_file.flags & GIT_DIFF_FLAG_VALID_ID));
cl_assert(0 != status->index_to_workdir->new_file.mode);
cl_assert(0 != status->index_to_workdir->new_file.size);
git_index_free(index);
git_status_list_free(statuslist);
}
static void stage_and_commit(git_repository *repo, const char *path)
......
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