mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 20:42:23 +00:00
Merge pull request #3444 from ethomson/add_preserves_conflict_mode
Preserve modes from a conflict in `git_index_insert`
This commit is contained in:
commit
8321596a49
@ -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
|
||||||
*
|
*
|
||||||
|
77
src/index.c
77
src/index.c
@ -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(
|
|||||||
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)
|
|||||||
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(
|
|||||||
{
|
{
|
||||||
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(
|
|||||||
|
|
||||||
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)
|
|||||||
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);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user