From ecd60a56ebd6bdc347a486f53da7de0febef58cf Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 14 May 2015 11:52:48 -0400 Subject: [PATCH] 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. --- CHANGELOG.md | 2 ++ include/git2/index.h | 3 ++- src/index.c | 17 +++++++++++++- tests/index/conflicts.c | 50 +++++++++++++++++++++++++++++++++++++++++ tests/status/worktree.c | 2 +- 5 files changed, 71 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a0ae0e03..8e4bdf919 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 52032f7fd..1e1d5e748 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 561fe73c4..19432b18c 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 427351693..aed5dd1a9 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 8897bf9b5..a8d71477e 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); }