Commit 8321596a by Carlos Martín Nieto

Merge pull request #3444 from ethomson/add_preserves_conflict_mode

Preserve modes from a conflict in `git_index_insert`
parents d5f7aad8 21515f22
...@@ -154,13 +154,27 @@ typedef enum { ...@@ -154,13 +154,27 @@ typedef enum {
GIT_INDEX_ADD_CHECK_PATHSPEC = (1u << 2), GIT_INDEX_ADD_CHECK_PATHSPEC = (1u << 2),
} git_index_add_option_t; } git_index_add_option_t;
/** typedef enum {
* Match any index stage. /**
* * Match any index stage.
* Some index APIs take a stage to match; pass this value to match *
* any entry matching the path regardless of stage. * Some index APIs take a stage to match; pass this value to match
*/ * any entry matching the path regardless of stage.
#define GIT_INDEX_STAGE_ANY -1 */
GIT_INDEX_STAGE_ANY = -1,
/** A normal staged file in the index. */
GIT_INDEX_STAGE_NORMAL = 0,
/** The ancestor side of a conflict. */
GIT_INDEX_STAGE_ANCESTOR = 1,
/** The "ours" side of a conflict. */
GIT_INDEX_STAGE_OURS = 2,
/** The "theirs" side of a conflict. */
GIT_INDEX_STAGE_THEIRS = 3,
} git_index_stage_t;
/** @name Index File Functions /** @name Index File Functions
* *
......
...@@ -1114,7 +1114,9 @@ static int check_file_directory_collision(git_index *index, ...@@ -1114,7 +1114,9 @@ static int check_file_directory_collision(git_index *index,
} }
static int canonicalize_directory_path( static int canonicalize_directory_path(
git_index *index, git_index_entry *entry) git_index *index,
git_index_entry *entry,
git_index_entry *existing)
{ {
const git_index_entry *match, *best = NULL; const git_index_entry *match, *best = NULL;
char *search, *sep; char *search, *sep;
...@@ -1124,8 +1126,8 @@ static int canonicalize_directory_path( ...@@ -1124,8 +1126,8 @@ static int canonicalize_directory_path(
return 0; return 0;
/* item already exists in the index, simply re-use the existing case */ /* item already exists in the index, simply re-use the existing case */
if ((match = git_index_get_bypath(index, entry->path, 0)) != NULL) { if (existing) {
memcpy((char *)entry->path, match->path, strlen(entry->path)); memcpy((char *)entry->path, existing->path, strlen(existing->path));
return 0; return 0;
} }
...@@ -1190,6 +1192,52 @@ static int index_no_dups(void **old, void *new) ...@@ -1190,6 +1192,52 @@ static int index_no_dups(void **old, void *new)
return GIT_EEXISTS; return GIT_EEXISTS;
} }
static void index_existing_and_best(
const git_index_entry **existing,
size_t *existing_position,
const git_index_entry **best,
git_index *index,
const git_index_entry *entry)
{
const git_index_entry *e;
size_t pos;
int error;
error = index_find(&pos,
index, entry->path, 0, GIT_IDXENTRY_STAGE(entry), false);
if (error == 0) {
*existing = index->entries.contents[pos];
*existing_position = pos;
*best = index->entries.contents[pos];
return;
}
*existing = NULL;
*existing_position = 0;
*best = NULL;
if (GIT_IDXENTRY_STAGE(entry) == 0) {
for (; pos < index->entries.length; pos++) {
int (*strcomp)(const char *a, const char *b) =
index->ignore_case ? git__strcasecmp : git__strcmp;
e = index->entries.contents[pos];
if (strcomp(entry->path, e->path) != 0)
break;
if (GIT_IDXENTRY_STAGE(e) == GIT_INDEX_STAGE_ANCESTOR) {
*best = e;
continue;
} else {
*best = e;
break;
}
}
}
}
/* index_insert takes ownership of the new entry - if it can't insert /* index_insert takes ownership of the new entry - if it can't insert
* it, then it will return an error **and also free the entry**. When * it, then it will return an error **and also free the entry**. When
* it replaces an existing entry, it will update the entry_ptr with the * it replaces an existing entry, it will update the entry_ptr with the
...@@ -1208,7 +1256,7 @@ static int index_insert( ...@@ -1208,7 +1256,7 @@ static int index_insert(
{ {
int error = 0; int error = 0;
size_t path_length, position; size_t path_length, position;
git_index_entry *existing = NULL, *entry; git_index_entry *existing, *best, *entry;
assert(index && entry_ptr); assert(index && entry_ptr);
...@@ -1231,20 +1279,19 @@ static int index_insert( ...@@ -1231,20 +1279,19 @@ static int index_insert(
git_vector_sort(&index->entries); git_vector_sort(&index->entries);
/* look if an entry with this path already exists */ /* look if an entry with this path already exists, either staged, or (if
if (!index_find( * this entry is a regular staged item) as the "ours" side of a conflict.
&position, index, entry->path, 0, GIT_IDXENTRY_STAGE(entry), false)) { */
existing = index->entries.contents[position]; index_existing_and_best(&existing, &position, &best, index, entry);
/* update filemode to existing values if stat is not trusted */
if (trust_mode) /* update the file mode */
entry->mode = git_index__create_mode(entry->mode); entry->mode = trust_mode ?
else git_index__create_mode(entry->mode) :
entry->mode = index_merge_mode(index, existing, entry->mode); index_merge_mode(index, best, entry->mode);
}
/* canonicalize the directory name */ /* canonicalize the directory name */
if (!trust_path) if (!trust_path)
error = canonicalize_directory_path(index, entry); error = canonicalize_directory_path(index, entry, best);
/* look for tree / blob name collisions, removing conflicts if requested */ /* look for tree / blob name collisions, removing conflicts if requested */
if (!error) if (!error)
......
...@@ -240,3 +240,91 @@ void test_index_bypath__add_honors_existing_case_4(void) ...@@ -240,3 +240,91 @@ void test_index_bypath__add_honors_existing_case_4(void)
cl_assert_equal_s("just_a_dir/a/b/Z/y/X/foo.txt", entry->path); cl_assert_equal_s("just_a_dir/a/b/Z/y/X/foo.txt", entry->path);
} }
void test_index_bypath__add_honors_mode(void)
{
const git_index_entry *entry;
git_index_entry new_entry;
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
memcpy(&new_entry, entry, sizeof(git_index_entry));
new_entry.path = "README.txt";
new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
cl_must_pass(p_chmod("submod2/README.txt", GIT_FILEMODE_BLOB_EXECUTABLE));
cl_git_pass(git_index_add(g_idx, &new_entry));
cl_git_pass(git_index_write(g_idx));
cl_git_rewritefile("submod2/README.txt", "Modified but still executable");
cl_git_pass(git_index_add_bypath(g_idx, "README.txt"));
cl_git_pass(git_index_write(g_idx));
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, entry->mode);
}
void test_index_bypath__add_honors_conflict_mode(void)
{
const git_index_entry *entry;
git_index_entry new_entry;
int stage = 0;
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
memcpy(&new_entry, entry, sizeof(git_index_entry));
new_entry.path = "README.txt";
new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
cl_must_pass(p_chmod("submod2/README.txt", GIT_FILEMODE_BLOB_EXECUTABLE));
cl_git_pass(git_index_remove_bypath(g_idx, "README.txt"));
for (stage = 1; stage <= 3; stage++) {
new_entry.flags = stage << GIT_IDXENTRY_STAGESHIFT;
cl_git_pass(git_index_add(g_idx, &new_entry));
}
cl_git_pass(git_index_write(g_idx));
cl_git_rewritefile("submod2/README.txt", "Modified but still executable");
cl_git_pass(git_index_add_bypath(g_idx, "README.txt"));
cl_git_pass(git_index_write(g_idx));
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, entry->mode);
}
void test_index_bypath__add_honors_conflict_case(void)
{
const git_index_entry *entry;
git_index_entry new_entry;
int stage = 0;
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
memcpy(&new_entry, entry, sizeof(git_index_entry));
new_entry.path = "README.txt";
new_entry.mode = GIT_FILEMODE_BLOB_EXECUTABLE;
cl_must_pass(p_chmod("submod2/README.txt", GIT_FILEMODE_BLOB_EXECUTABLE));
cl_git_pass(git_index_remove_bypath(g_idx, "README.txt"));
for (stage = 1; stage <= 3; stage++) {
new_entry.flags = stage << GIT_IDXENTRY_STAGESHIFT;
cl_git_pass(git_index_add(g_idx, &new_entry));
}
cl_git_pass(git_index_write(g_idx));
cl_git_rewritefile("submod2/README.txt", "Modified but still executable");
cl_git_pass(git_index_add_bypath(g_idx, "README.txt"));
cl_git_pass(git_index_write(g_idx));
cl_assert((entry = git_index_get_bypath(g_idx, "README.txt", 0)) != NULL);
cl_assert_equal_i(GIT_FILEMODE_BLOB_EXECUTABLE, entry->mode);
}
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