conflicts: when adding conflicts, remove staged When adding a conflict for some path, remove the staged entry. Otherwise, an illegal index (with both stage 0 and high-stage entries) would result.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8a0ae0e..8e4bdf9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -49,6 +49,8 @@ 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.
### API additions
diff --git a/include/git2/index.h b/include/git2/index.h
index 52032f7..1e1d5e7 100644
--- a/include/git2/index.h
+++ b/include/git2/index.h
@@ -631,7 +631,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
diff --git a/src/index.c b/src/index.c
index 561fe73..19432b1 100644
--- a/src/index.c
+++ b/src/index.c
@@ -1314,6 +1314,21 @@ int git_index_conflict_add(git_index *index,
(ret = index_entry_dup(&entries[2], INDEX_OWNER(index), their_entry)) < 0)
goto on_error;
+ /* 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 +1336,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 */
diff --git a/tests/index/conflicts.c b/tests/index/conflicts.c
index 4273516..aed5dd1 100644
--- a/tests/index/conflicts.c
+++ b/tests/index/conflicts.c
@@ -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"
@@ -96,6 +97,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.mode = 0100644;
+ staged.path = "test-one.txt";
+ 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;
+ ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT);
+ git_oid_fromstr(&ancestor_entry.id, TEST_ANCESTOR_OID);
+
+ our_entry.path = "test-one.txt";
+ our_entry.mode = 0100644;
+ our_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT);
+ git_oid_fromstr(&our_entry.id, TEST_OUR_OID);
+
+ their_entry.path = "test-one.txt";
+ their_entry.mode = 0100644;
+ their_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT);
+ 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];
diff --git a/tests/status/worktree.c b/tests/status/worktree.c
index 8897bf9..a8d7147 100644
--- a/tests/status/worktree.c
+++ b/tests/status/worktree.c
@@ -634,7 +634,7 @@ 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_INDEX_DELETED|GIT_STATUS_WT_NEW, status);
git_index_free(index);
}