diff conflicts: don't include incorrect ID Since a diff entry only concerns a single entry, zero the information for the index side of a conflict. (The index entry would otherwise erroneously include the lowest-stage index entry - generally the ancestor of a conflict.) Test that during status, the index side of the conflict is empty.
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
diff --git a/src/diff.c b/src/diff.c
index c061a90..abe0de0 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -149,9 +149,10 @@ static int diff_delta__from_two(
uint32_t old_mode,
const git_index_entry *new_entry,
uint32_t new_mode,
- git_oid *new_oid,
+ const git_oid *new_id,
const char *matched_pathspec)
{
+ const git_oid *old_id = &old_entry->id;
git_diff_delta *delta;
const char *canonical_path = old_entry->path;
@@ -159,38 +160,42 @@ static int diff_delta__from_two(
DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_UNMODIFIED))
return 0;
+ if (!new_id)
+ new_id = &new_entry->id;
+
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) {
uint32_t temp_mode = old_mode;
const git_index_entry *temp_entry = old_entry;
+ const git_oid *temp_id = old_id;
+
old_entry = new_entry;
new_entry = temp_entry;
old_mode = new_mode;
new_mode = temp_mode;
+ old_id = new_id;
+ new_id = temp_id;
}
delta = diff_delta__alloc(diff, status, canonical_path);
GITERR_CHECK_ALLOC(delta);
delta->nfiles = 2;
- git_oid_cpy(&delta->old_file.id, &old_entry->id);
- delta->old_file.size = old_entry->file_size;
- delta->old_file.mode = old_mode;
- delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
+ if (!git_index_entry_stage(old_entry)) {
+ delta->old_file.size = old_entry->file_size;
+ delta->old_file.mode = old_mode;
+ git_oid_cpy(&delta->old_file.id, old_id);
+ delta->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
+ }
- git_oid_cpy(&delta->new_file.id, &new_entry->id);
- delta->new_file.size = new_entry->file_size;
- delta->new_file.mode = new_mode;
+ if (!git_index_entry_stage(new_entry)) {
+ git_oid_cpy(&delta->new_file.id, new_id);
+ delta->new_file.size = new_entry->file_size;
+ delta->new_file.mode = new_mode;
- if (new_oid) {
- if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE))
- git_oid_cpy(&delta->old_file.id, new_oid);
- else
- git_oid_cpy(&delta->new_file.id, new_oid);
+ if (!git_oid_iszero(&new_entry->id))
+ delta->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
}
- if (new_oid || !git_oid_iszero(&new_entry->id))
- delta->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
-
return diff_insert_delta(diff, delta, matched_pathspec);
}
diff --git a/tests/status/worktree.c b/tests/status/worktree.c
index 9be0a41..e272c0a 100644
--- a/tests/status/worktree.c
+++ b/tests/status/worktree.c
@@ -645,6 +645,52 @@ void test_status_worktree__conflicted_item(void)
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)
{
git_index *index;