Commit f45ec1a0 by Edward Thomson

index refactoring

parent 81eecc34
......@@ -371,7 +371,7 @@ int main (int argc, char** argv)
// All these properties are exported publicly in the `git_index_entry` struct
ecount = git_index_entrycount(index);
for (i = 0; i < ecount; ++i) {
git_index_entry *e = git_index_get(index, i);
git_index_entry *e = git_index_get_byindex(index, i);
printf("path: %s\n", e->path);
printf("mtime: %d\n", (int)e->mtime.seconds);
......
......@@ -19,12 +19,13 @@ int main (int argc, char** argv)
ecount = git_index_entrycount(index);
for (i = 0; i < ecount; ++i) {
git_index_entry *e = git_index_get(index, i);
git_index_entry *e = git_index_get_byindex(index, i);
oid = e->oid;
git_oid_fmt(out, &oid);
printf("File Path: %s\n", e->path);
printf(" Stage: %d\n", git_index_entry_stage(e));
printf(" Blob SHA: %s\n", out);
printf("File Size: %d\n", (int)e->file_size);
printf(" Device: %d\n", (int)e->dev);
......
......@@ -84,12 +84,12 @@ typedef struct git_index_entry {
char *path;
} git_index_entry;
/** Representation of an unmerged file entry in the index. */
typedef struct git_index_entry_unmerged {
/** Representation of a resolve undo entry in the index. */
typedef struct git_index_reuc_entry {
unsigned int mode[3];
git_oid oid[3];
char *path;
} git_index_entry_unmerged;
} git_index_reuc_entry;
/** Capabilities of system that affect index actions. */
enum {
......@@ -99,6 +99,12 @@ enum {
GIT_INDEXCAP_FROM_OWNER = ~0u
};
/** @name Index File Functions
*
* These functions work on the index file itself.
*/
/**@{*/
/**
* Create a new bare Git index object as a memory representation
* of the Git index file in 'index_path', without a repository
......@@ -120,20 +126,19 @@ enum {
GIT_EXTERN(int) git_index_open(git_index **index, const char *index_path);
/**
* Clear the contents (all the entries) of an index object.
* This clears the index object in memory; changes must be manually
* written to disk for them to take effect.
* Free an existing index object.
*
* @param index an existing index object
*/
GIT_EXTERN(void) git_index_clear(git_index *index);
GIT_EXTERN(void) git_index_free(git_index *index);
/**
* Free an existing index object.
* Get the repository this index relates to
*
* @param index an existing index object
* @param index The index
* @return A pointer to the repository
*/
GIT_EXTERN(void) git_index_free(git_index *index);
GIT_EXTERN(git_repository *) git_index_owner(const git_index *index);
/**
* Read index capabilities flags.
......@@ -175,44 +180,92 @@ GIT_EXTERN(int) git_index_read(git_index *index);
GIT_EXTERN(int) git_index_write(git_index *index);
/**
* Find the first index of any entries which point to given
* path in the Git index.
* Read a tree into the index file with stats
*
* The current index contents will be replaced by the specified tree.
*
* @param index an existing index object
* @param path path to search
* @return an index >= 0 if found, -1 otherwise
* @param tree tree to read
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_find(git_index *index, const char *path);
GIT_EXTERN(int) git_index_read_tree(git_index *index, git_tree *tree);
/**@}*/
/** @name Raw Index Entry Functions
*
* These functions work on index entries, and allow for raw manipulation
* of the entries.
*/
/**@{*/
/* Index entry manipulation */
/**
* Remove all entries with equal path except last added
* Get the count of entries currently in the index
*
* @param index an existing index object
* @return integer of count of current entries
*/
GIT_EXTERN(void) git_index_uniq(git_index *index);
GIT_EXTERN(unsigned int) git_index_entrycount(git_index *index);
/**
* Add or update an index entry from a file in disk
* Clear the contents (all the entries) of an index object.
* This clears the index object in memory; changes must be manually
* written to disk for them to take effect.
*
* The file `path` must be relative to the repository's
* working folder and must be readable.
* @param index an existing index object
*/
GIT_EXTERN(void) git_index_clear(git_index *index);
/**
* Get a pointer to one of the entries in the index
*
* This method will fail in bare index instances.
* The values of this entry can be modified (except the path)
* and the changes will be written back to disk on the next
* write() call.
*
* This forces the file to be added to the index, not looking
* at gitignore rules. Those rules can be evaluated through
* the git_status APIs (in status.h) before calling this.
* The entry should not be freed by the caller.
*
* @param index an existing index object
* @param path filename to add
* @param stage stage for the entry
* @param n the position of the entry
* @return a pointer to the entry; NULL if out of bounds
*/
GIT_EXTERN(git_index_entry *) git_index_get_byindex(git_index *index, size_t n);
/**
* Get a pointer to one of the entries in the index
*
* The values of this entry can be modified (except the path)
* and the changes will be written back to disk on the next
* write() call.
*
* The entry should not be freed by the caller.
*
* @param index an existing index object
* @param path path to search
* @param stage stage to search
* @return a pointer to the entry; NULL if it was not found
*/
GIT_EXTERN(git_index_entry *) git_index_get_bypath(git_index *index, const char *path, int stage);
/**
* Remove an entry from the index
*
* @param index an existing index object
* @param path path to search
* @param stage stage to search
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_add(git_index *index, const char *path, int stage);
GIT_EXTERN(int) git_index_remove(git_index *index, const char *path, int stage);
/**
* Add or update an index entry from an in-memory struct
*
* If a previous index entry exists that has the same path and stage
* as the given 'source_entry', it will be replaced. Otherwise, the
* 'source_entry' will be added.
*
* A full copy (including the 'path' string) of the given
* 'source_entry' will be inserted on the index.
*
......@@ -220,140 +273,207 @@ GIT_EXTERN(int) git_index_add(git_index *index, const char *path, int stage);
* @param source_entry new entry object
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_add2(git_index *index, const git_index_entry *source_entry);
GIT_EXTERN(int) git_index_add(git_index *index, const git_index_entry *source_entry);
/**
* Add (append) an index entry from a file in disk
* Return the stage number from a git index entry
*
* This entry is calculated from the entry's flag
* attribute like this:
*
* (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT
*
* A new entry will always be inserted into the index;
* if the index already contains an entry for such
* path, the old entry will **not** be replaced.
* @param entry The entry
* @returns the stage number
*/
GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry);
/**@}*/
/** @name Workdir Index Entry Functions
*
* These functions work on index entries specifically in the working
* directory (ie, stage 0).
*/
/**@{*/
/**
* Add or update an index entry from a file in disk
*
* The file `path` must be relative to the repository's
* working folder and must be readable.
*
* This method will fail in bare index instances.
*
* This forces the file to be added to the index, not looking
* at gitignore rules. Those rules can be evaluated through
* the git_status APIs (in status.h) before calling this.
*
* If this file currently is the result of a merge conflict, this
* file will no longer be marked as conflicting. The data about
* the conflict will be moved to the "resolve undo" (REUC) section.
*
* @param index an existing index object
* @param path filename to add
* @param stage stage for the entry
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_append(git_index *index, const char *path, int stage);
GIT_EXTERN(int) git_index_add_from_workdir(git_index *index, const char *path);
/**
* Add (append) an index entry from an in-memory struct
* Find the first index of any entries which point to given
* path in the Git index.
*
* A new entry will always be inserted into the index;
* if the index already contains an entry for the path
* in the `entry` struct, the old entry will **not** be
* replaced.
* @param index an existing index object
* @param path path to search
* @return an index >= 0 if found, -1 otherwise
*/
GIT_EXTERN(int) git_index_find(git_index *index, const char *path);
/**@}*/
/** @name Conflict Index Entry Functions
*
* A full copy (including the 'path' string) of the given
* 'source_entry' will be inserted on the index.
* These functions work on conflict index entries specifically (ie, stages 1-3)
*/
/**@{*/
/**
* Add or update index entries to represent a conflict
*
* 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
* trees during the merge. For example, ancestor_entry may be NULL to
* indicate that a file was added in both branches and must be resolved.
*
* @param index an existing index object
* @param source_entry new entry object
* @param ancestor_entry the entry data for the ancestor of the conflict
* @param our_entry the entry data for our side of the merge conflict
* @param their_entry the entry data for their side of the merge conflict
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_append2(git_index *index, const git_index_entry *source_entry);
GIT_EXTERN(int) git_index_conflict_add(git_index *index,
const git_index_entry *ancestor_entry,
const git_index_entry *our_entry,
const git_index_entry *their_entry);
/**
* Remove an entry from the index
* Get the index entries that represent a conflict of a single file.
*
* The values of this entry can be modified (except the paths)
* and the changes will be written back to disk on the next
* write() call.
*
* @param ancestor_out Pointer to store the ancestor entry
* @param our_out Pointer to store the our entry
* @param their_out Pointer to store the their entry
* @param index an existing index object
* @param position position of the entry to remove
* @return 0 or an error code
* @param path path to search
*/
GIT_EXTERN(int) git_index_remove(git_index *index, int position);
GIT_EXTERN(int) git_index_conflict_get(git_index_entry **ancestor_out, git_index_entry **our_out, git_index_entry **their_out, git_index *index, const char *path);
/**
* Get a pointer to one of the entries in the index
*
* This entry can be modified, and the changes will be written
* back to disk on the next write() call.
* Removes the index entries that represent a conflict of a single file.
*
* The entry should not be freed by the caller.
* @param index an existing index object
* @param path to search
*/
GIT_EXTERN(int) git_index_conflict_remove(git_index *index, const char *path);
/**
* Remove all conflicts in the index (entries with a stage greater than 0.)
*
* @param index an existing index object
* @param n the position of the entry
* @return a pointer to the entry; NULL if out of bounds
*/
GIT_EXTERN(git_index_entry *) git_index_get(git_index *index, size_t n);
GIT_EXTERN(void) git_index_conflict_cleanup(git_index *index);
/**@}*/
/** @name Resolve Undo (REUC) index entry manipulation.
*
* These functions work on the Resolve Undo index extension and contains
* data about the original files that led to a merge conflict.
*/
/**@{*/
/**
* Get the count of entries currently in the index
* Get the count of resolve undo entries currently in the index.
*
* @param index an existing index object
* @return integer of count of current entries
* @return integer of count of current resolve undo entries
*/
GIT_EXTERN(unsigned int) git_index_entrycount(git_index *index);
GIT_EXTERN(unsigned int) git_index_reuc_entrycount(git_index *index);
/**
* Get the count of unmerged entries currently in the index
* Finds the resolve undo entry that points to the given path in the Git
* index.
*
* @param index an existing index object
* @return integer of count of current unmerged entries
* @param path path to search
* @return an index >= 0 if found, -1 otherwise
*/
GIT_EXTERN(unsigned int) git_index_entrycount_unmerged(git_index *index);
GIT_EXTERN(int) git_index_reuc_find(git_index *index, const char *path);
/**
* Get an unmerged entry from the index.
* Get a resolve undo entry from the index.
*
* The returned entry is read-only and should not be modified
* of freed by the caller.
*
* @param index an existing index object
* @param path path to search
* @return the unmerged entry; NULL if not found
* @return the resolve undo entry; NULL if not found
*/
GIT_EXTERN(const git_index_entry_unmerged *) git_index_get_unmerged_bypath(git_index *index, const char *path);
GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_bypath(git_index *index, const char *path);
/**
* Get an unmerged entry from the index.
* Get a resolve undo entry from the index.
*
* The returned entry is read-only and should not be modified
* of freed by the caller.
*
* @param index an existing index object
* @param n the position of the entry
* @return a pointer to the unmerged entry; NULL if out of bounds
* @return a pointer to the resolve undo entry; NULL if out of bounds
*/
GIT_EXTERN(const git_index_entry_unmerged *) git_index_get_unmerged_byindex(git_index *index, size_t n);
GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_byindex(git_index *index, size_t n);
/**
* Return the stage number from a git index entry
* Adds an resolve undo entry for a file based on the given parameters.
*
* This entry is calculated from the entry's flag
* attribute like this:
* The resolve undo entry contains the OIDs of files that were involved
* in a merge conflict after the conflict has been resolved. This allows
* conflicts to be re-resolved later.
*
* (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT
* If there exists a resolve undo entry for the given path in the index,
* it will be removed.
*
* @param entry The entry
* @returns the stage number
*/
GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry);
/**
* Read a tree into the index file with stats
*
* The current index contents will be replaced by the specified tree. The total
* node count is collected in stats.
* This method will fail in bare index instances.
*
* @param index an existing index object
* @param tree tree to read
* @param path filename to add
* @param ancestor_mode mode of the ancestor file
* @param ancestor_oid oid of the ancestor file
* @param our_mode mode of our file
* @param our_oid oid of our file
* @param their_mode mode of their file
* @param their_oid oid of their file
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_read_tree(git_index *index, git_tree *tree);
GIT_EXTERN(int) git_index_reuc_add(git_index *index, const char *path,
int ancestor_mode, git_oid *ancestor_oid,
int our_mode, git_oid *our_oid,
int their_mode, git_oid *their_oid);
/**
* Get the repository this index relates to
* Remove an resolve undo entry from the index
*
* @param index The index
* @return A pointer to the repository
* @param index an existing index object
* @param position position of the resolve undo entry to remove
* @return 0 or an error code
*/
GIT_EXTERN(git_repository *) git_index_owner(const git_index *index);
GIT_EXTERN(int) git_index_reuc_remove(git_index *index, int position);
/**@}*/
/** @} */
GIT_END_DECL
......
......@@ -307,7 +307,7 @@ static int load_attr_blob_from_index(
(error = git_index_find(index, relfile)) < 0)
return error;
entry = git_index_get(index, error);
entry = git_index_get_byindex(index, error);
if (old_oid && git_oid_cmp(old_oid, &entry->oid) == 0)
return GIT_ENOTFOUND;
......
......@@ -81,6 +81,11 @@ struct entry_long {
char path[1]; /* arbitrary length */
};
struct entry_srch_key {
const char *path;
int stage;
};
/* local declarations */
static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size);
static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size);
......@@ -90,53 +95,126 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
static int is_index_extended(git_index *index);
static int write_index(git_index *index, git_filebuf *file);
static int index_find(git_index *index, const char *path, int stage);
static void index_entry_free(git_index_entry *entry);
static void index_entry_reuc_free(git_index_reuc_entry *reuc);
GIT_INLINE(int) index_entry_stage(const git_index_entry *entry)
{
return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT;
}
static int index_srch(const void *key, const void *array_member)
{
const struct entry_srch_key *srch_key = key;
const git_index_entry *entry = array_member;
int ret;
return strcmp(key, entry->path);
ret = strcmp(srch_key->path, entry->path);
if (ret == 0)
ret = srch_key->stage - index_entry_stage(entry);
return ret;
}
static int index_isrch(const void *key, const void *array_member)
{
const struct entry_srch_key *srch_key = key;
const git_index_entry *entry = array_member;
int ret;
ret = strcasecmp(srch_key->path, entry->path);
if (ret == 0)
ret = srch_key->stage - index_entry_stage(entry);
return ret;
}
static int index_cmp_path(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
static int index_icmp_path(const void *a, const void *b)
{
return strcasecmp((const char *)a, (const char *)b);
}
static int index_srch_path(const void *path, const void *array_member)
{
const git_index_entry *entry = array_member;
return strcasecmp(key, entry->path);
return strcmp((const char *)path, entry->path);
}
static int index_isrch_path(const void *path, const void *array_member)
{
const git_index_entry *entry = array_member;
return strcasecmp((const char *)path, entry->path);
}
static int index_cmp(const void *a, const void *b)
{
int diff;
const git_index_entry *entry_a = a;
const git_index_entry *entry_b = b;
return strcmp(entry_a->path, entry_b->path);
diff = strcmp(entry_a->path, entry_b->path);
if (diff == 0)
diff = (index_entry_stage(entry_a) - index_entry_stage(entry_b));
return diff;
}
static int index_icmp(const void *a, const void *b)
{
int diff;
const git_index_entry *entry_a = a;
const git_index_entry *entry_b = b;
return strcasecmp(entry_a->path, entry_b->path);
diff = strcasecmp(entry_a->path, entry_b->path);
if (diff == 0)
diff = (index_entry_stage(entry_a) - index_entry_stage(entry_b));
return diff;
}
static int reuc_srch(const void *key, const void *array_member)
{
const git_index_reuc_entry *reuc = array_member;
return strcmp(key, reuc->path);
}
static int unmerged_srch(const void *key, const void *array_member)
static int reuc_isrch(const void *key, const void *array_member)
{
const git_index_entry_unmerged *entry = array_member;
const git_index_reuc_entry *reuc = array_member;
return strcmp(key, entry->path);
return strcasecmp(key, reuc->path);
}
static int unmerged_cmp(const void *a, const void *b)
static int reuc_cmp(const void *a, const void *b)
{
const git_index_entry_unmerged *info_a = a;
const git_index_entry_unmerged *info_b = b;
const git_index_reuc_entry *info_a = a;
const git_index_reuc_entry *info_b = b;
return strcmp(info_a->path, info_b->path);
}
static int reuc_icmp(const void *a, const void *b)
{
const git_index_reuc_entry *info_a = a;
const git_index_reuc_entry *info_b = b;
return strcasecmp(info_a->path, info_b->path);
}
static unsigned int index_create_mode(unsigned int mode)
{
if (S_ISLNK(mode))
......@@ -165,9 +243,16 @@ static unsigned int index_merge_mode(
static void index_set_ignore_case(git_index *index, bool ignore_case)
{
index->entries._cmp = ignore_case ? index_icmp : index_cmp;
index->entries_cmp_path = ignore_case ? index_icmp_path : index_cmp_path;
index->entries_search = ignore_case ? index_isrch : index_srch;
index->entries_search_path = ignore_case ? index_isrch_path : index_srch_path;
index->entries.sorted = 0;
git_vector_sort(&index->entries);
index->reuc._cmp = ignore_case ? reuc_icmp : reuc_cmp;
index->reuc_search = ignore_case ? reuc_isrch : reuc_srch;
index->reuc.sorted = 0;
git_vector_sort(&index->reuc);
}
int git_index_open(git_index **index_out, const char *index_path)
......@@ -185,7 +270,10 @@ int git_index_open(git_index **index_out, const char *index_path)
if (git_vector_init(&index->entries, 32, index_cmp) < 0)
return -1;
index->entries_cmp_path = index_cmp_path;
index->entries_search = index_srch;
index->entries_search_path = index_srch_path;
index->reuc_search = reuc_srch;
/* Check if index file is stored on disk already */
if (git_path_exists(index->index_file_path) == true)
......@@ -199,6 +287,7 @@ int git_index_open(git_index **index_out, const char *index_path)
static void index_free(git_index *index)
{
git_index_entry *e;
git_index_reuc_entry *reuc;
unsigned int i;
git_index_clear(index);
......@@ -206,10 +295,10 @@ static void index_free(git_index *index)
index_entry_free(e);
}
git_vector_free(&index->entries);
git_vector_foreach(&index->unmerged, i, e) {
index_entry_free(e);
git_vector_foreach(&index->reuc, i, reuc) {
index_entry_reuc_free(reuc);
}
git_vector_free(&index->unmerged);
git_vector_free(&index->reuc);
git__free(index->index_file_path);
git__free(index);
......@@ -236,15 +325,15 @@ void git_index_clear(git_index *index)
git__free(e);
}
for (i = 0; i < index->unmerged.length; ++i) {
git_index_entry_unmerged *e;
e = git_vector_get(&index->unmerged, i);
for (i = 0; i < index->reuc.length; ++i) {
git_index_reuc_entry *e;
e = git_vector_get(&index->reuc, i);
git__free(e->path);
git__free(e);
}
git_vector_clear(&index->entries);
git_vector_clear(&index->unmerged);
git_vector_clear(&index->reuc);
index->last_modified = 0;
git_tree_cache_free(index->tree);
......@@ -340,6 +429,7 @@ int git_index_write(git_index *index)
int error;
git_vector_sort(&index->entries);
git_vector_sort(&index->reuc);
if ((error = git_filebuf_open(
&file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < 0)
......@@ -367,16 +457,25 @@ unsigned int git_index_entrycount(git_index *index)
return (unsigned int)index->entries.length;
}
unsigned int git_index_entrycount_unmerged(git_index *index)
git_index_entry *git_index_get_byindex(git_index *index, size_t n)
{
assert(index);
return (unsigned int)index->unmerged.length;
git_vector_sort(&index->entries);
return git_vector_get(&index->entries, n);
}
git_index_entry *git_index_get(git_index *index, size_t n)
git_index_entry *git_index_get_bypath(git_index *index, const char *path, int stage)
{
int pos;
assert(index);
git_vector_sort(&index->entries);
return git_vector_get(&index->entries, n);
if((pos = index_find(index, path, stage)) < 0)
return NULL;
return git_index_get_byindex(index, pos);
}
void git_index__init_entry_from_stat(struct stat *st, git_index_entry *entry)
......@@ -393,7 +492,7 @@ void git_index__init_entry_from_stat(struct stat *st, git_index_entry *entry)
entry->file_size = st->st_size;
}
static int index_entry_init(git_index_entry **entry_out, git_index *index, const char *rel_path, int stage)
static int index_entry_init(git_index_entry **entry_out, git_index *index, const char *rel_path)
{
git_index_entry *entry = NULL;
struct stat st;
......@@ -402,8 +501,6 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const
git_buf full_path = GIT_BUF_INIT;
int error;
assert(stage >= 0 && stage <= 3);
if (INDEX_OWNER(index) == NULL ||
(workdir = git_repository_workdir(INDEX_OWNER(index))) == NULL)
{
......@@ -436,7 +533,6 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const
git_index__init_entry_from_stat(&st, entry);
entry->oid = oid;
entry->flags |= (stage << GIT_IDXENTRY_STAGESHIFT);
entry->path = git__strdup(rel_path);
GITERR_CHECK_ALLOC(entry->path);
......@@ -444,6 +540,46 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const
return 0;
}
static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
const char *path,
int ancestor_mode, git_oid *ancestor_oid,
int our_mode, git_oid *our_oid, int their_mode, git_oid *their_oid)
{
git_index_reuc_entry *reuc = NULL;
assert(reuc_out && path);
*reuc_out = NULL;
reuc = git__calloc(1, sizeof(git_index_reuc_entry));
GITERR_CHECK_ALLOC(reuc);
reuc->path = git__strdup(path);
if (reuc->path == NULL)
return -1;
reuc->mode[0] = ancestor_mode;
git_oid_cpy(&reuc->oid[0], ancestor_oid);
reuc->mode[1] = our_mode;
git_oid_cpy(&reuc->oid[1], our_oid);
reuc->mode[2] = their_mode;
git_oid_cpy(&reuc->oid[2], their_oid);
*reuc_out = reuc;
return 0;
}
static void index_entry_reuc_free(git_index_reuc_entry *reuc)
{
if (!reuc)
return;
git__free(reuc->path);
git__free(reuc);
}
static git_index_entry *index_entry_dup(const git_index_entry *source_entry)
{
git_index_entry *entry;
......@@ -486,10 +622,10 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
if (path_length < GIT_IDXENTRY_NAMEMASK)
entry->flags |= path_length & GIT_IDXENTRY_NAMEMASK;
else
entry->flags |= GIT_IDXENTRY_NAMEMASK;;
entry->flags |= GIT_IDXENTRY_NAMEMASK;
/* look if an entry with this path already exists */
if ((position = git_index_find(index, entry->path)) >= 0) {
if ((position = index_find(index, entry->path, index_entry_stage(entry))) >= 0) {
existing = (git_index_entry **)&index->entries.contents[position];
/* update filemode to existing values if stat is not trusted */
......@@ -510,34 +646,56 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace)
return 0;
}
static int index_add(git_index *index, const char *path, int stage, int replace)
static int index_conflict_to_reuc(git_index *index, const char *path)
{
git_index_entry *entry = NULL;
git_index_entry *conflict_entries[3];
int ancestor_mode, our_mode, their_mode;
git_oid *ancestor_oid, *our_oid, *their_oid;
int ret;
if ((ret = index_entry_init(&entry, index, path, stage)) < 0 ||
(ret = index_insert(index, entry, replace)) < 0)
{
index_entry_free(entry);
if ((ret = git_index_conflict_get(&conflict_entries[0],
&conflict_entries[1], &conflict_entries[2], index, path)) < 0)
return ret;
}
git_tree_cache_invalidate_path(index->tree, entry->path);
return 0;
}
ancestor_mode = conflict_entries[0] == NULL ? 0 : conflict_entries[0]->mode;
our_mode = conflict_entries[1] == NULL ? 0 : conflict_entries[1]->mode;
their_mode = conflict_entries[2] == NULL ? 0 : conflict_entries[2]->mode;
int git_index_add(git_index *index, const char *path, int stage)
{
return index_add(index, path, stage, 1);
ancestor_oid = conflict_entries[0] == NULL ? NULL : &conflict_entries[0]->oid;
our_oid = conflict_entries[1] == NULL ? NULL : &conflict_entries[1]->oid;
their_oid = conflict_entries[2] == NULL ? NULL : &conflict_entries[2]->oid;
if ((ret = git_index_reuc_add(index, path, ancestor_mode, ancestor_oid,
our_mode, our_oid, their_mode, their_oid)) >= 0)
ret = git_index_conflict_remove(index, path);
return ret;
}
int git_index_append(git_index *index, const char *path, int stage)
int git_index_add_from_workdir(git_index *index, const char *path)
{
return index_add(index, path, stage, 0);
git_index_entry *entry = NULL;
int ret;
assert(index && path);
if ((ret = index_entry_init(&entry, index, path)) < 0 ||
(ret = index_insert(index, entry, 1)) < 0)
goto on_error;
/* Adding implies conflict was resolved, move conflict entries to REUC */
if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND)
goto on_error;
git_tree_cache_invalidate_path(index->tree, entry->path);
return 0;
on_error:
index_entry_free(entry);
return ret;
}
static int index_add2(
git_index *index, const git_index_entry *source_entry, int replace)
int git_index_add(git_index *index, const git_index_entry *source_entry)
{
git_index_entry *entry = NULL;
int ret;
......@@ -546,7 +704,7 @@ static int index_add2(
if (entry == NULL)
return -1;
if ((ret = index_insert(index, entry, replace)) < 0) {
if ((ret = index_insert(index, entry, 1)) < 0) {
index_entry_free(entry);
return ret;
}
......@@ -555,23 +713,17 @@ static int index_add2(
return 0;
}
int git_index_add2(git_index *index, const git_index_entry *source_entry)
{
return index_add2(index, source_entry, 1);
}
int git_index_append2(git_index *index, const git_index_entry *source_entry)
{
return index_add2(index, source_entry, 0);
}
int git_index_remove(git_index *index, int position)
int git_index_remove(git_index *index, const char *path, int stage)
{
int position;
int error;
git_index_entry *entry;
git_vector_sort(&index->entries);
if ((position = index_find(index, path, stage)) < 0)
return position;
entry = git_vector_get(&index->entries, position);
if (entry != NULL)
git_tree_cache_invalidate_path(index->tree, entry->path);
......@@ -584,45 +736,277 @@ int git_index_remove(git_index *index, int position)
return error;
}
static int index_find(git_index *index, const char *path, int stage)
{
struct entry_srch_key srch_key;
assert(path);
srch_key.path = path;
srch_key.stage = stage;
return git_vector_bsearch2(&index->entries, index->entries_search, &srch_key);
}
int git_index_find(git_index *index, const char *path)
{
return git_vector_bsearch2(&index->entries, index->entries_search, path);
int pos;
assert(index && path);
if ((pos = git_vector_bsearch2(&index->entries, index->entries_search_path, path)) < 0)
return pos;
/* Since our binary search only looked at path, we may be in the
* middle of a list of stages. */
while (pos > 0) {
git_index_entry *prev = git_vector_get(&index->entries, pos-1);
if (index->entries_cmp_path(prev->path, path) != 0)
break;
--pos;
}
return pos;
}
unsigned int git_index__prefix_position(git_index *index, const char *path)
{
struct entry_srch_key srch_key;
unsigned int pos;
git_vector_bsearch3(&pos, &index->entries, index->entries_search, path);
srch_key.path = path;
srch_key.stage = 0;
git_vector_bsearch3(&pos, &index->entries, index->entries_search, &srch_key);
return pos;
}
void git_index_uniq(git_index *index)
int git_index_conflict_add(git_index *index,
const git_index_entry *ancestor_entry,
const git_index_entry *our_entry,
const git_index_entry *their_entry)
{
git_index_entry *entries[3] = { 0 };
size_t i;
int ret = 0;
assert (index);
if ((ancestor_entry != NULL && (entries[0] = index_entry_dup(ancestor_entry)) == NULL) ||
(our_entry != NULL && (entries[1] = index_entry_dup(our_entry)) == NULL) ||
(their_entry != NULL && (entries[2] = index_entry_dup(their_entry)) == NULL))
return -1;
for (i = 0; i < 3; i++) {
if (entries[i] == NULL)
continue;
/* Make sure stage is correct */
entries[i]->flags = (entries[i]->flags & ~GIT_IDXENTRY_STAGEMASK) |
((i+1) << GIT_IDXENTRY_STAGESHIFT);
if ((ret = index_insert(index, entries[i], 1)) < 0)
goto on_error;
}
return 0;
on_error:
for (i = 0; i < 3; i++) {
if (entries[i] != NULL)
index_entry_free(entries[i]);
}
return ret;
}
int git_index_conflict_get(git_index_entry **ancestor_out,
git_index_entry **our_out,
git_index_entry **their_out,
git_index *index, const char *path)
{
int pos, stage;
git_index_entry *conflict_entry;
int error = GIT_ENOTFOUND;
assert(ancestor_out && our_out && their_out && index && path);
*ancestor_out = NULL;
*our_out = NULL;
*their_out = NULL;
if ((pos = git_index_find(index, path)) < 0)
return pos;
while ((unsigned int)pos < git_index_entrycount(index)) {
conflict_entry = git_vector_get(&index->entries, pos);
if (index->entries_cmp_path(conflict_entry->path, path) != 0)
break;
stage = index_entry_stage(conflict_entry);
switch (stage) {
case 3:
*their_out = conflict_entry;
error = 0;
break;
case 2:
*our_out = conflict_entry;
error = 0;
break;
case 1:
*ancestor_out = conflict_entry;
error = 0;
break;
default:
break;
};
++pos;
}
return error;
}
int git_index_conflict_remove(git_index *index, const char *path)
{
int pos;
git_index_entry *conflict_entry;
assert(index && path);
if ((pos = git_index_find(index, path)) < 0)
return pos;
while ((unsigned int)pos < git_index_entrycount(index)) {
conflict_entry = git_vector_get(&index->entries, pos);
if (index->entries_cmp_path(conflict_entry->path, path) != 0)
break;
if (index_entry_stage(conflict_entry) == 0) {
pos++;
continue;
}
git_vector_remove(&index->entries, (unsigned int)pos);
}
return 0;
}
static int index_conflicts_match(git_vector *v, size_t idx)
{
git_index_entry *entry = git_vector_get(v, idx);
if (index_entry_stage(entry) > 0)
return 1;
return 0;
}
void git_index_conflict_cleanup(git_index *index)
{
assert(index);
git_vector_remove_matching(&index->entries, index_conflicts_match);
}
unsigned int git_index_reuc_entrycount(git_index *index)
{
assert(index);
return (unsigned int)index->reuc.length;
}
static int index_reuc_insert(git_index *index, git_index_reuc_entry *reuc, int replace)
{
git_index_reuc_entry **existing = NULL;
int position;
assert(index && reuc && reuc->path != NULL);
if ((position = git_index_reuc_find(index, reuc->path)) >= 0)
existing = (git_index_reuc_entry **)&index->reuc.contents[position];
if (!replace || !existing)
return git_vector_insert(&index->reuc, reuc);
/* exists, replace it */
git__free((*existing)->path);
git__free(*existing);
*existing = reuc;
return 0;
}
int git_index_reuc_add(git_index *index, const char *path,
int ancestor_mode, git_oid *ancestor_oid,
int our_mode, git_oid *our_oid,
int their_mode, git_oid *their_oid)
{
git_index_reuc_entry *reuc = NULL;
int error = 0;
assert(index && path);
if ((error = index_entry_reuc_init(&reuc, path, ancestor_mode, ancestor_oid, our_mode, our_oid, their_mode, their_oid)) < 0 ||
(error = index_reuc_insert(index, reuc, 1)) < 0)
{
index_entry_reuc_free(reuc);
return error;
}
return error;
}
int git_index_reuc_find(git_index *index, const char *path)
{
git_vector_uniq(&index->entries);
return git_vector_bsearch2(&index->reuc, index->reuc_search, path);
}
const git_index_entry_unmerged *git_index_get_unmerged_bypath(
const git_index_reuc_entry *git_index_reuc_get_bypath(
git_index *index, const char *path)
{
int pos;
assert(index && path);
if (!index->unmerged.length)
if (!index->reuc.length)
return NULL;
if ((pos = git_vector_bsearch2(&index->unmerged, unmerged_srch, path)) < 0)
git_vector_sort(&index->reuc);
if ((pos = git_index_reuc_find(index, path)) < 0)
return NULL;
return git_vector_get(&index->unmerged, pos);
return git_vector_get(&index->reuc, pos);
}
const git_index_entry_unmerged *git_index_get_unmerged_byindex(
const git_index_reuc_entry *git_index_reuc_get_byindex(
git_index *index, size_t n)
{
assert(index);
return git_vector_get(&index->unmerged, n);
git_vector_sort(&index->reuc);
return git_vector_get(&index->reuc, n);
}
int git_index_reuc_remove(git_index *index, int position)
{
int error;
git_index_reuc_entry *reuc;
git_vector_sort(&index->reuc);
reuc = git_vector_get(&index->reuc, position);
error = git_vector_remove(&index->reuc, (unsigned int)position);
if (!error)
index_entry_reuc_free(reuc);
return error;
}
static int index_error_invalid(const char *message)
......@@ -631,26 +1015,26 @@ static int index_error_invalid(const char *message)
return -1;
}
static int read_unmerged(git_index *index, const char *buffer, size_t size)
static int read_reuc(git_index *index, const char *buffer, size_t size)
{
const char *endptr;
size_t len;
int i;
if (git_vector_init(&index->unmerged, 16, unmerged_cmp) < 0)
if (git_vector_init(&index->reuc, 16, reuc_cmp) < 0)
return -1;
while (size) {
git_index_entry_unmerged *lost;
git_index_reuc_entry *lost;
len = strlen(buffer) + 1;
if (size <= len)
return index_error_invalid("reading unmerged entries");
return index_error_invalid("reading reuc entries");
lost = git__malloc(sizeof(git_index_entry_unmerged));
lost = git__malloc(sizeof(git_index_reuc_entry));
GITERR_CHECK_ALLOC(lost);
if (git_vector_insert(&index->unmerged, lost) < 0)
if (git_vector_insert(&index->reuc, lost) < 0)
return -1;
/* read NUL-terminated pathname for entry */
......@@ -667,13 +1051,13 @@ static int read_unmerged(git_index *index, const char *buffer, size_t size)
if (git__strtol32(&tmp, buffer, &endptr, 8) < 0 ||
!endptr || endptr == buffer || *endptr ||
(unsigned)tmp > UINT_MAX)
return index_error_invalid("reading unmerged entry stage");
return index_error_invalid("reading reuc entry stage");
lost->mode[i] = tmp;
len = (endptr + 1) - buffer;
if (size <= len)
return index_error_invalid("reading unmerged entry stage");
return index_error_invalid("reading reuc entry stage");
size -= len;
buffer += len;
......@@ -684,7 +1068,7 @@ static int read_unmerged(git_index *index, const char *buffer, size_t size)
if (!lost->mode[i])
continue;
if (size < 20)
return index_error_invalid("reading unmerged entry oid");
return index_error_invalid("reading reuc entry oid");
git_oid_fromraw(&lost->oid[i], (const unsigned char *) buffer);
size -= 20;
......@@ -692,6 +1076,9 @@ static int read_unmerged(git_index *index, const char *buffer, size_t size)
}
}
/* entries are guaranteed to be sorted on-disk */
index->reuc.sorted = 1;
return 0;
}
......@@ -797,7 +1184,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer
if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size) < 0)
return 0;
} else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) {
if (read_unmerged(index, buffer + 8, dest.extension_size) < 0)
if (read_reuc(index, buffer + 8, dest.extension_size) < 0)
return 0;
}
/* else, unsupported extension. We cannot parse this, but we can skip
......@@ -996,6 +1383,69 @@ static int write_entries(git_index *index, git_filebuf *file)
return error;
}
static int write_extension(git_filebuf *file, struct index_extension *header, git_buf *data)
{
struct index_extension ondisk;
int error = 0;
memset(&ondisk, 0x0, sizeof(struct index_extension));
memcpy(&ondisk, header, 4);
ondisk.extension_size = htonl(header->extension_size);
if ((error = git_filebuf_write(file, &ondisk, sizeof(struct index_extension))) == 0)
error = git_filebuf_write(file, data->ptr, data->size);
return error;
}
static int create_reuc_extension_data(git_buf *reuc_buf, git_index_reuc_entry *reuc)
{
int i;
int error = 0;
if ((error = git_buf_put(reuc_buf, reuc->path, strlen(reuc->path) + 1)) < 0)
return error;
for (i = 0; i < 3; i++) {
if ((error = git_buf_printf(reuc_buf, "%o", reuc->mode[i])) < 0 ||
(error = git_buf_put(reuc_buf, "\0", 1)) < 0)
return error;
}
for (i = 0; i < 3; i++) {
if (reuc->mode[i] && (error = git_buf_put(reuc_buf, (char *)&reuc->oid[i].id, GIT_OID_RAWSZ)) < 0)
return error;
}
return 0;
}
static int write_reuc_extension(git_index *index, git_filebuf *file)
{
git_buf reuc_buf = GIT_BUF_INIT;
git_vector *out = &index->reuc;
git_index_reuc_entry *reuc;
struct index_extension extension;
unsigned int i;
int error = 0;
git_vector_foreach(out, i, reuc) {
if ((error = create_reuc_extension_data(&reuc_buf, reuc)) < 0)
goto done;
}
memset(&extension, 0x0, sizeof(struct index_extension));
memcpy(&extension.signature, INDEX_EXT_UNMERGED_SIG, 4);
extension.extension_size = reuc_buf.size;
error = write_extension(file, &extension, &reuc_buf);
git_buf_free(&reuc_buf);
done:
return error;
}
static int write_index(git_index *index, git_filebuf *file)
{
git_oid hash_final;
......@@ -1018,7 +1468,11 @@ static int write_index(git_index *index, git_filebuf *file)
if (write_entries(index, file) < 0)
return -1;
/* TODO: write extensions (tree cache) */
/* TODO: write tree cache extension */
/* write the reuc extension */
if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0)
return -1;
/* get out the hash for all the contents we've appended to the file */
git_filebuf_hash(&hash_final, file);
......@@ -1029,7 +1483,7 @@ static int write_index(git_index *index, git_filebuf *file)
int git_index_entry_stage(const git_index_entry *entry)
{
return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT;
return index_entry_stage(entry);
}
typedef struct read_tree_data {
......
......@@ -33,9 +33,12 @@ struct git_index {
git_tree_cache *tree;
git_vector unmerged;
git_vector reuc;
git_vector_cmp entries_cmp_path;
git_vector_cmp entries_search;
git_vector_cmp entries_search_path;
git_vector_cmp reuc_search;
};
extern void git_index__init_entry_from_stat(struct stat *st, git_index_entry *entry);
......
......@@ -336,7 +336,7 @@ static int index_iterator__current(
git_iterator *self, const git_index_entry **entry)
{
index_iterator *ii = (index_iterator *)self;
git_index_entry *ie = git_index_get(ii->index, ii->current);
git_index_entry *ie = git_index_get_byindex(ii->index, ii->current);
if (ie != NULL &&
ii->base.end != NULL &&
......
......@@ -183,13 +183,13 @@ static int update_index_cb(
if (!data->include_ignored)
break;
return git_index_add(data->index, delta->new_file.path, 0);
return git_index_add_from_workdir(data->index, delta->new_file.path);
case GIT_DELTA_UNTRACKED:
if (!data->include_untracked)
break;
return git_index_add(data->index, delta->new_file.path, 0);
return git_index_add_from_workdir(data->index, delta->new_file.path);
case GIT_DELTA_ADDED:
/* Fall through */
......@@ -197,7 +197,7 @@ static int update_index_cb(
if (!data->include_changed)
break;
return git_index_add(data->index, delta->new_file.path, 0);
return git_index_add_from_workdir(data->index, delta->new_file.path);
case GIT_DELTA_DELETED:
if (!data->include_changed)
......@@ -206,7 +206,7 @@ static int update_index_cb(
if ((pos = git_index_find(data->index, delta->new_file.path)) < 0)
return -1;
if (git_index_remove(data->index, pos) < 0)
if (git_index_remove(data->index, delta->new_file.path, 0) < 0)
return -1;
default:
......
......@@ -332,7 +332,7 @@ int git_submodule_add_finalize(git_submodule *sm)
assert(sm);
if ((error = git_repository_index__weakptr(&index, sm->owner)) < 0 ||
(error = git_index_add(index, GIT_MODULES_FILE, 0)) < 0)
(error = git_index_add_from_workdir(index, GIT_MODULES_FILE)) < 0)
return error;
return git_submodule_add_to_index(sm, true);
......@@ -393,7 +393,7 @@ int git_submodule_add_to_index(git_submodule *sm, int write_index)
git_commit_free(head);
/* add it */
error = git_index_add2(index, &entry);
error = git_index_add(index, &entry);
/* write it, if requested */
if (!error && write_index) {
......@@ -733,7 +733,7 @@ int git_submodule_reload(git_submodule *submodule)
pos = git_index_find(index, submodule->path);
if (pos >= 0) {
git_index_entry *entry = git_index_get(index, pos);
git_index_entry *entry = git_index_get_byindex(index, pos);
if (S_ISGITLINK(entry->mode)) {
if ((error = submodule_load_from_index(repo, entry)) < 0)
......
......@@ -353,7 +353,7 @@ static unsigned int find_next_dir(const char *dirname, git_index *index, unsigne
dirlen = strlen(dirname);
for (i = start; i < entries; ++i) {
git_index_entry *entry = git_index_get(index, i);
git_index_entry *entry = git_index_get_byindex(index, i);
if (strlen(entry->path) < dirlen ||
memcmp(entry->path, dirname, dirlen) ||
(dirlen > 0 && entry->path[dirlen] != '/')) {
......@@ -415,7 +415,7 @@ static int write_tree(
* need to keep track of the current position.
*/
for (i = start; i < entries; ++i) {
git_index_entry *entry = git_index_get(index, i);
git_index_entry *entry = git_index_get_byindex(index, i);
char *filename, *next_slash;
/*
......
......@@ -223,6 +223,20 @@ void git_vector_uniq(git_vector *v)
v->length -= j - i - 1;
}
void git_vector_remove_matching(git_vector *v, int (*match)(git_vector *v, size_t idx))
{
unsigned int i, j;
for (i = 0, j = 0; j < v->length; ++j) {
v->contents[i] = v->contents[j];
if (!match(v, i))
i++;
}
v->length = i;
}
void git_vector_clear(git_vector *v)
{
assert(v);
......
......@@ -75,5 +75,6 @@ int git_vector_insert_sorted(git_vector *v, void *element,
int git_vector_remove(git_vector *v, unsigned int idx);
void git_vector_pop(git_vector *v);
void git_vector_uniq(git_vector *v);
void git_vector_remove_matching(git_vector *v, int (*match)(git_vector *v, size_t idx));
#endif
......@@ -270,12 +270,12 @@ static void assert_proper_normalization(git_index *index, const char *filename,
git_index_entry *entry;
add_to_workdir(filename, CONTENT);
cl_git_pass(git_index_add(index, filename, 0));
cl_git_pass(git_index_add_from_workdir(index, filename));
index_pos = git_index_find(index, filename);
cl_assert(index_pos >= 0);
entry = git_index_get(index, index_pos);
entry = git_index_get_byindex(index, index_pos);
cl_assert_equal_i(0, git_oid_streq(&entry->oid, expected_sha));
}
......
......@@ -189,3 +189,87 @@ void test_core_vector__5(void)
git_vector_free(&x);
}
static int remove_ones(git_vector *v, size_t idx)
{
return (git_vector_get(v, idx) == (void *)0x001);
}
/* Test removal based on callback */
void test_core_vector__remove_matching(void)
{
git_vector x;
size_t i;
void *compare;
git_vector_init(&x, 1, NULL);
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 1);
git_vector_remove_matching(&x, remove_ones);
cl_assert(x.length == 0);
git_vector_insert(&x, (void*) 0x001);
git_vector_insert(&x, (void*) 0x001);
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 3);
git_vector_remove_matching(&x, remove_ones);
cl_assert(x.length == 0);
git_vector_insert(&x, (void*) 0x002);
git_vector_insert(&x, (void*) 0x001);
git_vector_insert(&x, (void*) 0x002);
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4);
git_vector_remove_matching(&x, remove_ones);
cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) {
cl_assert(compare != (void *)0x001);
}
git_vector_clear(&x);
git_vector_insert(&x, (void*) 0x001);
git_vector_insert(&x, (void*) 0x002);
git_vector_insert(&x, (void*) 0x002);
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4);
git_vector_remove_matching(&x, remove_ones);
cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) {
cl_assert(compare != (void *)0x001);
}
git_vector_clear(&x);
git_vector_insert(&x, (void*) 0x002);
git_vector_insert(&x, (void*) 0x001);
git_vector_insert(&x, (void*) 0x002);
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4);
git_vector_remove_matching(&x, remove_ones);
cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) {
cl_assert(compare != (void *)0x001);
}
git_vector_clear(&x);
git_vector_insert(&x, (void*) 0x002);
git_vector_insert(&x, (void*) 0x003);
git_vector_insert(&x, (void*) 0x002);
git_vector_insert(&x, (void*) 0x003);
cl_assert(x.length == 4);
git_vector_remove_matching(&x, remove_ones);
cl_assert(x.length == 4);
git_vector_free(&x);
}
#include "clar_libgit2.h"
#include "index.h"
#include "git2/repository.h"
static git_repository *repo;
static git_index *repo_index;
#define TEST_REPO_PATH "mergedrepo"
#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
#define CONFLICTS_ONE_ANCESTOR_OID "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81"
#define CONFLICTS_ONE_OUR_OID "6aea5f295304c36144ad6e9247a291b7f8112399"
#define CONFLICTS_ONE_THEIR_OID "516bd85f78061e09ccc714561d7b504672cb52da"
#define CONFLICTS_TWO_ANCESTOR_OID "84af62840be1b1c47b778a8a249f3ff45155038c"
#define CONFLICTS_TWO_OUR_OID "8b3f43d2402825c200f835ca1762413e386fd0b2"
#define CONFLICTS_TWO_THEIR_OID "220bd62631c8cf7a83ef39c6b94595f00517211e"
#define TEST_ANCESTOR_OID "f00ff00ff00ff00ff00ff00ff00ff00ff00ff00f"
#define TEST_OUR_OID "b44bb44bb44bb44bb44bb44bb44bb44bb44bb44b"
#define TEST_THEIR_OID "0123456789abcdef0123456789abcdef01234567"
// Fixture setup and teardown
void test_index_conflicts__initialize(void)
{
repo = cl_git_sandbox_init("mergedrepo");
git_repository_index(&repo_index, repo);
}
void test_index_conflicts__cleanup(void)
{
git_index_free(repo_index);
cl_git_sandbox_cleanup();
}
void test_index_conflicts__add(void)
{
git_index_entry ancestor_entry, our_entry, their_entry;
cl_assert(git_index_entrycount(repo_index) == 8);
memset(&ancestor_entry, 0x0, sizeof(git_index_entry));
memset(&our_entry, 0x0, sizeof(git_index_entry));
memset(&their_entry, 0x0, sizeof(git_index_entry));
ancestor_entry.path = "test-one.txt";
ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT);
git_oid_fromstr(&ancestor_entry.oid, TEST_ANCESTOR_OID);
our_entry.path = "test-one.txt";
ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT);
git_oid_fromstr(&our_entry.oid, TEST_OUR_OID);
their_entry.path = "test-one.txt";
ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT);
git_oid_fromstr(&their_entry.oid, 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);
}
void test_index_conflicts__add_fixes_incorrect_stage(void)
{
git_index_entry ancestor_entry, our_entry, their_entry;
git_index_entry *conflict_entry[3];
cl_assert(git_index_entrycount(repo_index) == 8);
memset(&ancestor_entry, 0x0, sizeof(git_index_entry));
memset(&our_entry, 0x0, sizeof(git_index_entry));
memset(&their_entry, 0x0, sizeof(git_index_entry));
ancestor_entry.path = "test-one.txt";
ancestor_entry.flags |= (3 << GIT_IDXENTRY_STAGESHIFT);
git_oid_fromstr(&ancestor_entry.oid, TEST_ANCESTOR_OID);
our_entry.path = "test-one.txt";
ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT);
git_oid_fromstr(&our_entry.oid, TEST_OUR_OID);
their_entry.path = "test-one.txt";
ancestor_entry.flags |= (2 << GIT_IDXENTRY_STAGESHIFT);
git_oid_fromstr(&their_entry.oid, 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_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], repo_index, "test-one.txt"));
cl_assert(git_index_entry_stage(conflict_entry[0]) == 1);
cl_assert(git_index_entry_stage(conflict_entry[1]) == 2);
cl_assert(git_index_entry_stage(conflict_entry[2]) == 3);
}
void test_index_conflicts__get(void)
{
git_index_entry *conflict_entry[3];
git_oid oid;
cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1],
&conflict_entry[2], repo_index, "conflicts-one.txt"));
cl_assert(strcmp(conflict_entry[0]->path, "conflicts-one.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_ONE_ANCESTOR_OID);
cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0);
git_oid_fromstr(&oid, CONFLICTS_ONE_OUR_OID);
cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0);
git_oid_fromstr(&oid, CONFLICTS_ONE_THEIR_OID);
cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0);
cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1],
&conflict_entry[2], repo_index, "conflicts-two.txt"));
cl_assert(strcmp(conflict_entry[0]->path, "conflicts-two.txt") == 0);
git_oid_fromstr(&oid, CONFLICTS_TWO_ANCESTOR_OID);
cl_assert(git_oid_cmp(&conflict_entry[0]->oid, &oid) == 0);
git_oid_fromstr(&oid, CONFLICTS_TWO_OUR_OID);
cl_assert(git_oid_cmp(&conflict_entry[1]->oid, &oid) == 0);
git_oid_fromstr(&oid, CONFLICTS_TWO_THEIR_OID);
cl_assert(git_oid_cmp(&conflict_entry[2]->oid, &oid) == 0);
}
void test_index_conflicts__remove(void)
{
git_index_entry *entry;
size_t i;
cl_assert(git_index_entrycount(repo_index) == 8);
cl_git_pass(git_index_conflict_remove(repo_index, "conflicts-one.txt"));
cl_assert(git_index_entrycount(repo_index) == 5);
for (i = 0; i < git_index_entrycount(repo_index); i++) {
cl_assert(entry = git_index_get_byindex(repo_index, i));
cl_assert(strcmp(entry->path, "conflicts-one.txt") != 0);
}
cl_git_pass(git_index_conflict_remove(repo_index, "conflicts-two.txt"));
cl_assert(git_index_entrycount(repo_index) == 2);
for (i = 0; i < git_index_entrycount(repo_index); i++) {
cl_assert(entry = git_index_get_byindex(repo_index, i));
cl_assert(strcmp(entry->path, "conflicts-two.txt") != 0);
}
}
void test_index_conflicts__moved_to_reuc(void)
{
git_index_entry *entry;
size_t i;
cl_assert(git_index_entrycount(repo_index) == 8);
cl_git_mkfile("./mergedrepo/conflicts-one.txt", "new-file\n");
cl_git_pass(git_index_add_from_workdir(repo_index, "conflicts-one.txt"));
cl_assert(git_index_entrycount(repo_index) == 6);
for (i = 0; i < git_index_entrycount(repo_index); i++) {
cl_assert(entry = git_index_get_byindex(repo_index, i));
if (strcmp(entry->path, "conflicts-one.txt") == 0)
cl_assert(git_index_entry_stage(entry) == 0);
}
}
void test_index_conflicts__remove_all_conflicts(void)
{
size_t i;
git_index_entry *entry;
cl_assert(git_index_entrycount(repo_index) == 8);
git_index_conflict_cleanup(repo_index);
cl_assert(git_index_entrycount(repo_index) == 2);
for (i = 0; i < git_index_entrycount(repo_index); i++) {
cl_assert(entry = git_index_get_byindex(repo_index, i));
cl_assert(git_index_entry_stage(entry) == 0);
}
}
void test_index_conflicts__partial(void)
{
git_index_entry ancestor_entry, our_entry, their_entry;
git_index_entry *conflict_entry[3];
cl_assert(git_index_entrycount(repo_index) == 8);
memset(&ancestor_entry, 0x0, sizeof(git_index_entry));
memset(&our_entry, 0x0, sizeof(git_index_entry));
memset(&their_entry, 0x0, sizeof(git_index_entry));
ancestor_entry.path = "test-one.txt";
ancestor_entry.flags |= (1 << GIT_IDXENTRY_STAGESHIFT);
git_oid_fromstr(&ancestor_entry.oid, TEST_ANCESTOR_OID);
cl_git_pass(git_index_conflict_add(repo_index, &ancestor_entry, NULL, NULL));
cl_assert(git_index_entrycount(repo_index) == 9);
cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1],
&conflict_entry[2], repo_index, "test-one.txt"));
cl_assert(git_oid_cmp(&ancestor_entry.oid, &conflict_entry[0]->oid) == 0);
cl_assert(conflict_entry[1] == NULL);
cl_assert(conflict_entry[2] == NULL);
}
......@@ -25,7 +25,7 @@ void test_index_filemodes__read(void)
cl_assert_equal_i(6, git_index_entrycount(index));
for (i = 0; i < 6; ++i) {
git_index_entry *entry = git_index_get(index, i);
git_index_entry *entry = git_index_get_byindex(index, i);
cl_assert(entry != NULL);
cl_assert(((entry->mode & 0100) ? 1 : 0) == expected[i]);
}
......@@ -56,35 +56,15 @@ static void add_and_check_mode(
int pos;
git_index_entry *entry;
cl_git_pass(git_index_add(index, filename, 0));
cl_git_pass(git_index_add_from_workdir(index, filename));
pos = git_index_find(index, filename);
cl_assert(pos >= 0);
entry = git_index_get(index, pos);
entry = git_index_get_byindex(index, pos);
cl_assert(entry->mode == expect_mode);
}
static void append_and_check_mode(
git_index *index, const char *filename, unsigned int expect_mode)
{
unsigned int before, after;
git_index_entry *entry;
before = git_index_entrycount(index);
cl_git_pass(git_index_append(index, filename, 0));
after = git_index_entrycount(index);
cl_assert_equal_i(before + 1, after);
/* bypass git_index_get since that resorts the index */
entry = (git_index_entry *)git_vector_get(&index->entries, after - 1);
cl_assert_equal_s(entry->path, filename);
cl_assert(expect_mode == entry->mode);
}
void test_index_filemodes__untrusted(void)
{
git_config *cfg;
......@@ -114,23 +94,7 @@ void test_index_filemodes__untrusted(void)
replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
/* 5 - append 0644 over existing 0644 -> expect 0644 */
replace_file_with_mode("exec_off", "filemodes/exec_off.2", 0644);
append_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
/* 6 - append 0644 over existing 0755 -> expect 0755 */
replace_file_with_mode("exec_on", "filemodes/exec_on.2", 0644);
append_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
/* 7 - append 0755 over existing 0644 -> expect 0644 */
replace_file_with_mode("exec_off", "filemodes/exec_off.3", 0755);
append_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
/* 8 - append 0755 over existing 0755 -> expect 0755 */
replace_file_with_mode("exec_on", "filemodes/exec_on.3", 0755);
append_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
/* 9 - add new 0644 -> expect 0644 */
/* 5 - add new 0644 -> expect 0644 */
cl_git_write2file("filemodes/new_off", "blah",
O_WRONLY | O_CREAT | O_TRUNC, 0644);
add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
......@@ -139,7 +103,7 @@ void test_index_filemodes__untrusted(void)
* that doesn't support filemodes correctly, so skip it.
*/
if (can_filemode) {
/* 10 - add 0755 -> expect 0755 */
/* 6 - add 0755 -> expect 0755 */
cl_git_write2file("filemodes/new_on", "blah",
O_WRONLY | O_CREAT | O_TRUNC, 0755);
add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE);
......@@ -182,28 +146,12 @@ void test_index_filemodes__trusted(void)
replace_file_with_mode("exec_on", "filemodes/exec_on.1", 0755);
add_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
/* 5 - append 0644 over existing 0644 -> expect 0644 */
replace_file_with_mode("exec_off", "filemodes/exec_off.2", 0644);
append_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB);
/* 6 - append 0644 over existing 0755 -> expect 0644 */
replace_file_with_mode("exec_on", "filemodes/exec_on.2", 0644);
append_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB);
/* 7 - append 0755 over existing 0644 -> expect 0755 */
replace_file_with_mode("exec_off", "filemodes/exec_off.3", 0755);
append_and_check_mode(index, "exec_off", GIT_FILEMODE_BLOB_EXECUTABLE);
/* 8 - append 0755 over existing 0755 -> expect 0755 */
replace_file_with_mode("exec_on", "filemodes/exec_on.3", 0755);
append_and_check_mode(index, "exec_on", GIT_FILEMODE_BLOB_EXECUTABLE);
/* 9 - add new 0644 -> expect 0644 */
/* 5 - add new 0644 -> expect 0644 */
cl_git_write2file("filemodes/new_off", "blah",
O_WRONLY | O_CREAT | O_TRUNC, 0644);
add_and_check_mode(index, "new_off", GIT_FILEMODE_BLOB);
/* 10 - add 0755 -> expect 0755 */
/* 6 - add 0755 -> expect 0755 */
cl_git_write2file("filemodes/new_on", "blah",
O_WRONLY | O_CREAT | O_TRUNC, 0755);
add_and_check_mode(index, "new_on", GIT_FILEMODE_BLOB_EXECUTABLE);
......
......@@ -24,9 +24,9 @@ void test_index_read_tree__read_write_involution(void)
cl_git_mkfile("./read_tree/abc/d", NULL);
cl_git_mkfile("./read_tree/abc_d", NULL);
cl_git_pass(git_index_add(index, "abc-d", 0));
cl_git_pass(git_index_add(index, "abc_d", 0));
cl_git_pass(git_index_add(index, "abc/d", 0));
cl_git_pass(git_index_add_from_workdir(index, "abc-d"));
cl_git_pass(git_index_add_from_workdir(index, "abc_d"));
cl_git_pass(git_index_add_from_workdir(index, "abc/d"));
/* write-tree */
cl_git_pass(git_tree_create_fromindex(&expected, index));
......
......@@ -19,28 +19,28 @@ void test_index_rename__single_file(void)
cl_git_mkfile("./rename/lame.name.txt", "new_file\n");
/* This should add a new blob to the object database in 'd4/fa8600b4f37d7516bef4816ae2c64dbf029e3a' */
cl_git_pass(git_index_add(index, "lame.name.txt", 0));
cl_git_pass(git_index_add_from_workdir(index, "lame.name.txt"));
cl_assert(git_index_entrycount(index) == 1);
cl_git_pass(git_oid_fromstr(&expected, "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a"));
position = git_index_find(index, "lame.name.txt");
entry = git_index_get(index, position);
entry = git_index_get_byindex(index, position);
cl_assert(git_oid_cmp(&expected, &entry->oid) == 0);
/* This removes the entry from the index, but not from the object database */
cl_git_pass(git_index_remove(index, position));
cl_git_pass(git_index_remove(index, "lame.name.txt", 0));
cl_assert(git_index_entrycount(index) == 0);
p_rename("./rename/lame.name.txt", "./rename/fancy.name.txt");
cl_git_pass(git_index_add(index, "fancy.name.txt", 0));
cl_git_pass(git_index_add_from_workdir(index, "fancy.name.txt"));
cl_assert(git_index_entrycount(index) == 1);
position = git_index_find(index, "fancy.name.txt");
entry = git_index_get(index, position);
entry = git_index_get_byindex(index, position);
cl_assert(git_oid_cmp(&expected, &entry->oid) == 0);
git_index_free(index);
......
#include "clar_libgit2.h"
#include "index.h"
#include "git2/repository.h"
static git_repository *repo;
static git_index *repo_index;
#define TEST_REPO_PATH "mergedrepo"
#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
#define ONE_ANCESTOR_OID "478871385b9cd03908c5383acfd568bef023c6b3"
#define ONE_OUR_OID "4458b8bc9e72b6c8755ae456f60e9844d0538d8c"
#define ONE_THEIR_OID "8b72416545c7e761b64cecad4f1686eae4078aa8"
#define TWO_ANCESTOR_OID "9d81f82fccc7dcd7de7a1ffead1815294c2e092c"
#define TWO_OUR_OID "8f3c06cff9a83757cec40c80bc9bf31a2582bde9"
#define TWO_THEIR_OID "887b153b165d32409c70163e0f734c090f12f673"
// Fixture setup and teardown
void test_index_reuc__initialize(void)
{
repo = cl_git_sandbox_init("mergedrepo");
git_repository_index(&repo_index, repo);
}
void test_index_reuc__cleanup(void)
{
git_index_free(repo_index);
cl_git_sandbox_cleanup();
}
void test_index_reuc__read_bypath(void)
{
const git_index_reuc_entry *reuc;
git_oid oid;
cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index));
cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "two.txt"));
cl_assert(strcmp(reuc->path, "two.txt") == 0);
cl_assert(reuc->mode[0] == 0100644);
cl_assert(reuc->mode[1] == 0100644);
cl_assert(reuc->mode[2] == 0100644);
git_oid_fromstr(&oid, TWO_ANCESTOR_OID);
cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0);
git_oid_fromstr(&oid, TWO_OUR_OID);
cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0);
cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "one.txt"));
cl_assert(strcmp(reuc->path, "one.txt") == 0);
cl_assert(reuc->mode[0] == 0100644);
cl_assert(reuc->mode[1] == 0100644);
cl_assert(reuc->mode[2] == 0100644);
git_oid_fromstr(&oid, ONE_ANCESTOR_OID);
cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0);
git_oid_fromstr(&oid, ONE_OUR_OID);
cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0);
git_oid_fromstr(&oid, ONE_THEIR_OID);
cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0);
}
void test_index_reuc__ignore_case(void)
{
const git_index_reuc_entry *reuc;
git_oid oid;
int index_caps;
index_caps = git_index_caps(repo_index);
index_caps &= ~GIT_INDEXCAP_IGNORE_CASE;
cl_git_pass(git_index_set_caps(repo_index, index_caps));
cl_assert(!git_index_reuc_get_bypath(repo_index, "TWO.txt"));
index_caps |= GIT_INDEXCAP_IGNORE_CASE;
cl_git_pass(git_index_set_caps(repo_index, index_caps));
cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index));
cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "TWO.txt"));
cl_assert(strcmp(reuc->path, "two.txt") == 0);
cl_assert(reuc->mode[0] == 0100644);
cl_assert(reuc->mode[1] == 0100644);
cl_assert(reuc->mode[2] == 0100644);
git_oid_fromstr(&oid, TWO_ANCESTOR_OID);
cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0);
git_oid_fromstr(&oid, TWO_OUR_OID);
cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0);
}
void test_index_reuc__read_byindex(void)
{
const git_index_reuc_entry *reuc;
git_oid oid;
cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index));
cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0));
cl_assert(strcmp(reuc->path, "one.txt") == 0);
cl_assert(reuc->mode[0] == 0100644);
cl_assert(reuc->mode[1] == 0100644);
cl_assert(reuc->mode[2] == 0100644);
git_oid_fromstr(&oid, ONE_ANCESTOR_OID);
cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0);
git_oid_fromstr(&oid, ONE_OUR_OID);
cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0);
git_oid_fromstr(&oid, ONE_THEIR_OID);
cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0);
cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 1));
cl_assert(strcmp(reuc->path, "two.txt") == 0);
cl_assert(reuc->mode[0] == 0100644);
cl_assert(reuc->mode[1] == 0100644);
cl_assert(reuc->mode[2] == 0100644);
git_oid_fromstr(&oid, TWO_ANCESTOR_OID);
cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0);
git_oid_fromstr(&oid, TWO_OUR_OID);
cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0);
}
void test_index_reuc__updates_existing(void)
{
const git_index_reuc_entry *reuc;
git_oid ancestor_oid, our_oid, their_oid, oid;
int index_caps;
git_index_clear(repo_index);
index_caps = git_index_caps(repo_index);
index_caps |= GIT_INDEXCAP_IGNORE_CASE;
cl_git_pass(git_index_set_caps(repo_index, index_caps));
git_oid_fromstr(&ancestor_oid, TWO_ANCESTOR_OID);
git_oid_fromstr(&our_oid, TWO_OUR_OID);
git_oid_fromstr(&their_oid, TWO_THEIR_OID);
cl_git_pass(git_index_reuc_add(repo_index, "two.txt",
0100644, &ancestor_oid,
0100644, &our_oid,
0100644, &their_oid));
cl_git_pass(git_index_reuc_add(repo_index, "TWO.txt",
0100644, &our_oid,
0100644, &their_oid,
0100644, &ancestor_oid));
cl_assert_equal_i(1, git_index_reuc_entrycount(repo_index));
cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0));
cl_assert(strcmp(reuc->path, "TWO.txt") == 0);
git_oid_fromstr(&oid, TWO_OUR_OID);
cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0);
git_oid_fromstr(&oid, TWO_ANCESTOR_OID);
cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0);
}
void test_index_reuc__remove(void)
{
git_oid oid;
const git_index_reuc_entry *reuc;
cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index));
cl_git_pass(git_index_reuc_remove(repo_index, 0));
cl_git_fail(git_index_reuc_remove(repo_index, 1));
cl_assert_equal_i(1, git_index_reuc_entrycount(repo_index));
cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0));
cl_assert(strcmp(reuc->path, "two.txt") == 0);
cl_assert(reuc->mode[0] == 0100644);
cl_assert(reuc->mode[1] == 0100644);
cl_assert(reuc->mode[2] == 0100644);
git_oid_fromstr(&oid, TWO_ANCESTOR_OID);
cl_assert(git_oid_cmp(&reuc->oid[0], &oid) == 0);
git_oid_fromstr(&oid, TWO_OUR_OID);
cl_assert(git_oid_cmp(&reuc->oid[1], &oid) == 0);
git_oid_fromstr(&oid, TWO_THEIR_OID);
cl_assert(git_oid_cmp(&reuc->oid[2], &oid) == 0);
}
void test_index_reuc__write(void)
{
git_oid ancestor_oid, our_oid, their_oid;
const git_index_reuc_entry *reuc;
git_index_clear(repo_index);
/* Write out of order to ensure sorting is correct */
git_oid_fromstr(&ancestor_oid, TWO_ANCESTOR_OID);
git_oid_fromstr(&our_oid, TWO_OUR_OID);
git_oid_fromstr(&their_oid, TWO_THEIR_OID);
cl_git_pass(git_index_reuc_add(repo_index, "two.txt",
0100644, &ancestor_oid,
0100644, &our_oid,
0100644, &their_oid));
git_oid_fromstr(&ancestor_oid, ONE_ANCESTOR_OID);
git_oid_fromstr(&our_oid, ONE_OUR_OID);
git_oid_fromstr(&their_oid, ONE_THEIR_OID);
cl_git_pass(git_index_reuc_add(repo_index, "one.txt",
0100644, &ancestor_oid,
0100644, &our_oid,
0100644, &their_oid));
cl_git_pass(git_index_write(repo_index));
cl_git_pass(git_index_read(repo_index));
cl_assert_equal_i(2, git_index_reuc_entrycount(repo_index));
/* ensure sort order was round-tripped correct */
cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 0));
cl_assert(strcmp(reuc->path, "one.txt") == 0);
cl_assert(reuc = git_index_reuc_get_byindex(repo_index, 1));
cl_assert(strcmp(reuc->path, "two.txt") == 0);
}
#include "clar_libgit2.h"
#include "index.h"
#include "git2/repository.h"
static git_repository *repo;
static git_index *repo_index;
#define TEST_REPO_PATH "mergedrepo"
#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
// Fixture setup and teardown
void test_index_stage__initialize(void)
{
repo = cl_git_sandbox_init("mergedrepo");
git_repository_index(&repo_index, repo);
}
void test_index_stage__cleanup(void)
{
git_index_free(repo_index);
cl_git_sandbox_cleanup();
}
void test_index_stage__add_always_adds_stage_0(void)
{
int entry_idx;
git_index_entry *entry;
cl_git_mkfile("./mergedrepo/new-file.txt", "new-file\n");
cl_git_pass(git_index_add_from_workdir(repo_index, "new-file.txt"));
cl_assert((entry_idx = git_index_find(repo_index, "new-file.txt")) >= 0);
cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL);
cl_assert(git_index_entry_stage(entry) == 0);
}
void test_index_stage__find_gets_first_stage(void)
{
int entry_idx;
git_index_entry *entry;
cl_assert((entry_idx = git_index_find(repo_index, "one.txt")) >= 0);
cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL);
cl_assert(git_index_entry_stage(entry) == 0);
cl_assert((entry_idx = git_index_find(repo_index, "two.txt")) >= 0);
cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL);
cl_assert(git_index_entry_stage(entry) == 0);
cl_assert((entry_idx = git_index_find(repo_index, "conflicts-one.txt")) >= 0);
cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL);
cl_assert(git_index_entry_stage(entry) == 1);
cl_assert((entry_idx = git_index_find(repo_index, "conflicts-two.txt")) >= 0);
cl_assert((entry = git_index_get_byindex(repo_index, entry_idx)) != NULL);
cl_assert(git_index_entry_stage(entry) == 1);
}
......@@ -231,15 +231,19 @@ void test_index_tests__add(void)
cl_git_pass(git_oid_fromstr(&id1, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"));
/* Add the new file to the index */
cl_git_pass(git_index_add(index, "test.txt", 0));
cl_git_pass(git_index_add_from_workdir(index, "test.txt"));
/* Wow... it worked! */
cl_assert(git_index_entrycount(index) == 1);
entry = git_index_get(index, 0);
entry = git_index_get_byindex(index, 0);
/* And the built-in hashing mechanism worked as expected */
cl_assert(git_oid_cmp(&id1, &entry->oid) == 0);
/* Test access by path instead of index */
cl_assert((entry = git_index_get_bypath(index, "test.txt", 0)) != NULL);
cl_assert(git_oid_cmp(&id1, &entry->oid) == 0);
git_index_free(index);
git_repository_free(repo);
}
......
......@@ -71,9 +71,9 @@ void test_object_commit_commitstagedfile__generate_predictable_object_ids(void)
*/
cl_git_mkfile("treebuilder/test.txt", "test\n");
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_add(index, "test.txt", 0));
cl_git_pass(git_index_add_from_workdir(index, "test.txt"));
entry = git_index_get(index, 0);
entry = git_index_get_byindex(index, 0);
cl_assert(git_oid_cmp(&expected_blob_oid, &entry->oid) == 0);
......
e2809157a7766f272e4cfe26e61ef2678a5357ff
Merge branch 'branch'
Conflicts:
conflicts-one.txt
conflicts-two.txt
3a34580a35add43a4cf361e8e9a30060a905c876
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
Unnamed repository; edit this file 'description' to name the repository.
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
0000000000000000000000000000000000000000 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson <ethomson@edwardthomson.com> 1351371828 -0500 commit (initial): initial
9a05ccb4e0f948de03128e095f39dae6976751c5 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson <ethomson@edwardthomson.com> 1351371835 -0500 checkout: moving from master to branch
9a05ccb4e0f948de03128e095f39dae6976751c5 e2809157a7766f272e4cfe26e61ef2678a5357ff Edward Thomson <ethomson@edwardthomson.com> 1351371872 -0500 commit: branch
e2809157a7766f272e4cfe26e61ef2678a5357ff 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson <ethomson@edwardthomson.com> 1351371873 -0500 checkout: moving from branch to master
9a05ccb4e0f948de03128e095f39dae6976751c5 3a34580a35add43a4cf361e8e9a30060a905c876 Edward Thomson <ethomson@edwardthomson.com> 1351372106 -0500 commit: master
0000000000000000000000000000000000000000 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson <ethomson@edwardthomson.com> 1351371835 -0500 branch: Created from HEAD
9a05ccb4e0f948de03128e095f39dae6976751c5 e2809157a7766f272e4cfe26e61ef2678a5357ff Edward Thomson <ethomson@edwardthomson.com> 1351371872 -0500 commit: branch
0000000000000000000000000000000000000000 9a05ccb4e0f948de03128e095f39dae6976751c5 Edward Thomson <ethomson@edwardthomson.com> 1351371828 -0500 commit (initial): initial
9a05ccb4e0f948de03128e095f39dae6976751c5 3a34580a35add43a4cf361e8e9a30060a905c876 Edward Thomson <ethomson@edwardthomson.com> 1351372106 -0500 commit: master
e2809157a7766f272e4cfe26e61ef2678a5357ff
3a34580a35add43a4cf361e8e9a30060a905c876
<<<<<<< HEAD
This is most certainly a conflict!
=======
This is a conflict!!!
>>>>>>> branch
<<<<<<< HEAD
This is without question another conflict!
=======
This is another conflict!!!
>>>>>>> branch
This is file one!
This is file one.
This is file one.
This is file one.
This is file one.
This is file one.
This is file one.
This is file one.
This is file one.
This is file one!
This is file two!
This is file two.
This is file two.
This is file two.
This is file two.
This is file two.
This is file two.
This is file two.
This is file two.
This is file two.
This is file two.
This is file two!
......@@ -30,7 +30,7 @@ static void push_three_states(void)
cl_git_mkfile("stash/zero.txt", "content\n");
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_add(index, "zero.txt", 0));
cl_git_pass(git_index_add_from_workdir(index, "zero.txt"));
commit_staged_files(&oid, index, signature);
cl_git_mkfile("stash/one.txt", "content\n");
......
......@@ -246,8 +246,8 @@ void test_stash_save__cannot_stash_when_there_are_no_local_change(void)
* 'what' and 'who' are being committed.
* 'when' remain untracked.
*/
git_index_add(index, "what", 0);
git_index_add(index, "who", 0);
git_index_add_from_workdir(index, "what");
git_index_add_from_workdir(index, "who");
cl_git_pass(git_index_write(index));
commit_staged_files(&commit_oid, index, signature);
git_index_free(index);
......
......@@ -44,10 +44,10 @@ void setup_stash(git_repository *repo, git_signature *signature)
cl_git_mkfile("stash/.gitignore", "*.ignore\n");
cl_git_pass(git_index_add(index, "what", 0));
cl_git_pass(git_index_add(index, "how", 0));
cl_git_pass(git_index_add(index, "who", 0));
cl_git_pass(git_index_add(index, ".gitignore", 0));
cl_git_pass(git_index_add_from_workdir(index, "what"));
cl_git_pass(git_index_add_from_workdir(index, "how"));
cl_git_pass(git_index_add_from_workdir(index, "who"));
cl_git_pass(git_index_add_from_workdir(index, ".gitignore"));
cl_git_pass(git_index_write(index));
commit_staged_files(&commit_oid, index, signature);
......@@ -56,8 +56,8 @@ void setup_stash(git_repository *repo, git_signature *signature)
cl_git_rewritefile("stash/how", "not so small and\n"); /* e6d64adb2c7f3eb8feb493b556cc8070dca379a3 */
cl_git_rewritefile("stash/who", "funky world\n"); /* a0400d4954659306a976567af43125a0b1aa8595 */
cl_git_pass(git_index_add(index, "what", 0));
cl_git_pass(git_index_add(index, "how", 0));
cl_git_pass(git_index_add_from_workdir(index, "what"));
cl_git_pass(git_index_add_from_workdir(index, "how"));
cl_git_pass(git_index_write(index));
cl_git_rewritefile("stash/what", "see you later\n"); /* bc99dc98b3eba0e9157e94769cd4d49cb49de449 */
......
......@@ -438,7 +438,7 @@ void test_status_worktree__first_commit_in_progress(void)
cl_assert(result.status == GIT_STATUS_WT_NEW);
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_add(index, "testfile.txt", 0));
cl_git_pass(git_index_add_from_workdir(index, "testfile.txt"));
cl_git_pass(git_index_write(index));
memset(&result, 0, sizeof(result));
......@@ -570,7 +570,7 @@ void test_status_worktree__bracket_in_filename(void)
/* add the file to the index */
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_add(index, FILE_WITH_BRACKET, 0));
cl_git_pass(git_index_add_from_workdir(index, FILE_WITH_BRACKET));
cl_git_pass(git_index_write(index));
memset(&result, 0, sizeof(result));
......@@ -648,7 +648,7 @@ void test_status_worktree__space_in_filename(void)
/* add the file to the index */
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_add(index, FILE_WITH_SPACE, 0));
cl_git_pass(git_index_add_from_workdir(index, FILE_WITH_SPACE));
cl_git_pass(git_index_write(index));
memset(&result, 0, sizeof(result));
......@@ -816,7 +816,7 @@ void test_status_worktree__new_staged_file_must_handle_crlf(void)
cl_git_mkfile("getting_started/testfile.txt", "content\r\n"); // Content with CRLF
cl_git_pass(git_repository_index(&index, repo));
cl_git_pass(git_index_add(index, "testfile.txt", 0));
cl_git_pass(git_index_add_from_workdir(index, "testfile.txt"));
cl_git_pass(git_index_write(index));
cl_git_pass(git_status_file(&status, repo, "testfile.txt"));
......
......@@ -105,7 +105,7 @@ void test_submodule_status__ignore_none(void)
cl_git_pass(git_repository_index(&index, g_repo));
pos = git_index_find(index, "sm_changed_head");
cl_assert(pos >= 0);
cl_git_pass(git_index_remove(index, pos));
cl_git_pass(git_index_remove(index, "sm_changed_head", 0));
cl_git_pass(git_index_write(index));
git_index_free(index);
......
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