From 5d7c940b07bfd2bc14ef67ef8a00fb03de59b97c Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Tue, 16 Apr 2013 13:25:38 -0700 Subject: [PATCH 001/134] /mailmap me --- .mailmap | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index 582dae0b9..fb44eb826 100644 --- a/.mailmap +++ b/.mailmap @@ -1,3 +1,5 @@ -Vicent Martí Vicent Marti +Vicent Martí Vicent Marti Vicent Martí Vicent Martí Michael Schubert schu +Ben Straub Ben Straub +Ben Straub Ben Straub From a442ed687d4c01a68de9aa7b0e50902f17a1ea84 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 17 Apr 2013 04:46:37 +0200 Subject: [PATCH 002/134] repository: Add `git_repository_open_bare` --- include/git2/repository.h | 15 +++++++++++++++ src/repository.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/include/git2/repository.h b/include/git2/repository.h index e75c8b136..e3320975c 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -123,6 +123,21 @@ GIT_EXTERN(int) git_repository_open_ext( unsigned int flags, const char *ceiling_dirs); +/** + * Open a bare repository on the serverside. + * + * This is a fast open for bare repositories that will come in handy + * if you're e.g. hosting git repositories and need to access them + * efficiently + * + * @param out Pointer to the repo which will be opened. + * @param bare_path Direct path to the bare repository + * @return 0 on success, or an error code + */ +GIT_EXTERN(int) git_repository_open_bare( + git_repository **out, + const char *bare_path); + /** * Free a previously allocated repository * diff --git a/src/repository.c b/src/repository.c index 0ad7449ba..64ab2f4db 100644 --- a/src/repository.c +++ b/src/repository.c @@ -368,6 +368,37 @@ static int find_repo( return error; } +int git_repository_open_bare( + git_repository **repo_ptr, + const char *bare_path) +{ + int error; + git_buf path = GIT_BUF_INIT; + git_repository *repo = NULL; + + if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0) + return error; + + if (!valid_repository_path(&path)) { + git_buf_free(&path); + giterr_set(GITERR_REPOSITORY, "Path is not a repository: %s", bare_path); + return GIT_ENOTFOUND; + } + + repo = repository_alloc(); + GITERR_CHECK_ALLOC(repo); + + repo->path_repository = git_buf_detach(&path); + GITERR_CHECK_ALLOC(repo->path_repository); + + /* of course we're bare! */ + repo->is_bare = 1; + repo->workdir = NULL; + + *repo_ptr = repo; + return 0; +} + int git_repository_open_ext( git_repository **repo_ptr, const char *start_path, From 6edad4d8a4c5e20544eb3b1daa926413518dd020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 17 Apr 2013 11:03:18 +0200 Subject: [PATCH 003/134] Add mailmap entries for me --- .mailmap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mailmap b/.mailmap index fb44eb826..a8b171908 100644 --- a/.mailmap +++ b/.mailmap @@ -3,3 +3,5 @@ Vicent Martí Vicent Martí Michael Schubert schu Ben Straub Ben Straub Ben Straub Ben Straub +Carlos Martín Nieto +Carlos Martín Nieto From 1cfaaa9e48655c4a5b4ebc4f8c20fcb8c6537e49 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Wed, 17 Apr 2013 13:48:26 +0200 Subject: [PATCH 004/134] Update link to Perl bindings --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 790e202d7..fdddc5ca1 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ Here are the bindings to libgit2 that are currently available: * Parrot Virtual Machine * parrot-libgit2 * Perl - * git-xs-pm + * Git-Raw * PHP * php-git * Python From 3be933b143731bbe3a5cadcdf70b8ab205a629c0 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 17 Apr 2013 17:33:51 +0200 Subject: [PATCH 005/134] refs: Add `git_referene_target_peel` --- include/git2/refdb.h | 7 +- include/git2/refs.h | 11 +++ src/refdb_fs.c | 7 +- src/refs.c | 169 +++++++++++++++++++++++------------- src/refs.h | 7 +- tests-clar/refdb/inmemory.c | 4 +- tests-clar/refdb/testdb.c | 16 ++-- 7 files changed, 149 insertions(+), 72 deletions(-) diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 0586b119e..76b8fda0d 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -35,7 +35,12 @@ GIT_EXTERN(git_reference *) git_reference__alloc( git_refdb *refdb, const char *name, const git_oid *oid, - const char *symbolic); + const git_oid *peel); + +GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( + git_refdb *refdb, + const char *name, + const char *target); /** * Create a new reference database with no backends. diff --git a/include/git2/refs.h b/include/git2/refs.h index e0451ba82..1ff0d4544 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -132,6 +132,17 @@ GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, */ GIT_EXTERN(const git_oid *) git_reference_target(const git_reference *ref); +/** + * Return the peeled OID target of this reference. + * + * This peeled OID only applies to direct references that point to + * a hard Tag object: it is the result of peeling such Tag. + * + * @param ref The reference + * @return a pointer to the oid if available, NULL otherwise + */ +GIT_EXTERN(const git_oid *) git_reference_target_peel(const git_reference *ref); + /** * Get full name to the reference pointed to by a symbolic reference. * diff --git a/src/refdb_fs.c b/src/refdb_fs.c index f00bd72a0..730148a8f 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -430,7 +430,7 @@ static int loose_lookup( goto done; } - *out = git_reference__alloc(backend->refdb, ref_name, NULL, target); + *out = git_reference__alloc_symbolic(backend->refdb, ref_name, target); } else { if ((error = loose_parse_oid(&oid, &ref_file)) < 0) goto done; @@ -484,7 +484,8 @@ static int packed_lookup( if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0) return error; - if ((*out = git_reference__alloc(backend->refdb, ref_name, &entry->oid, NULL)) == NULL) + if ((*out = git_reference__alloc(backend->refdb, ref_name, + &entry->oid, &entry->peel)) == NULL) return -1; return 0; @@ -644,7 +645,7 @@ static int loose_write(refdb_fs_backend *backend, const git_reference *ref) if (ref->type == GIT_REF_OID) { char oid[GIT_OID_HEXSZ + 1]; - git_oid_fmt(oid, &ref->target.oid); + git_oid_fmt(oid, &ref->target.direct.oid); oid[GIT_OID_HEXSZ] = '\0'; git_filebuf_printf(&file, "%s\n", oid); diff --git a/src/refs.c b/src/refs.c index b1f679632..290b89b41 100644 --- a/src/refs.c +++ b/src/refs.c @@ -31,37 +31,62 @@ enum { GIT_PACKREF_WAS_LOOSE = 2 }; +static git_reference *alloc_ref(git_refdb *refdb, const char *name) +{ + git_reference *ref; + size_t namelen = strlen(name); + + if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL) + return NULL; + + ref->db = refdb; + memcpy(ref->name, name, namelen + 1); + + return ref; +} + +git_reference *git_reference__alloc_symbolic( + git_refdb *refdb, + const char *name, + const char *target) +{ + git_reference *ref; + + assert(refdb && name && target); + + ref = alloc_ref(refdb, name); + if (!ref) + return NULL; + + ref->type = GIT_REF_SYMBOLIC; + + if ((ref->target.symbolic = git__strdup(target)) == NULL) { + git__free(ref); + return NULL; + } + + return ref; +} git_reference *git_reference__alloc( git_refdb *refdb, const char *name, const git_oid *oid, - const char *symbolic) + const git_oid *peel) { git_reference *ref; - size_t namelen; - assert(refdb && name && ((oid && !symbolic) || (!oid && symbolic))); + assert(refdb && name && oid); - namelen = strlen(name); - - if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL) + ref = alloc_ref(refdb, name); + if (!ref) return NULL; - if (oid) { - ref->type = GIT_REF_OID; - git_oid_cpy(&ref->target.oid, oid); - } else { - ref->type = GIT_REF_SYMBOLIC; + ref->type = GIT_REF_OID; + git_oid_cpy(&ref->target.direct.oid, oid); - if ((ref->target.symbolic = git__strdup(symbolic)) == NULL) { - git__free(ref); - return NULL; - } - } - - ref->db = refdb; - memcpy(ref->name, name, namelen + 1); + if (peel != NULL) + git_oid_cpy(&ref->target.direct.peel, peel); return ref; } @@ -71,13 +96,8 @@ void git_reference_free(git_reference *reference) if (reference == NULL) return; - if (reference->type == GIT_REF_SYMBOLIC) { + if (reference->type == GIT_REF_SYMBOLIC) git__free(reference->target.symbolic); - reference->target.symbolic = NULL; - } - - reference->db = NULL; - reference->type = GIT_REF_INVALID; git__free(reference); } @@ -302,7 +322,17 @@ const git_oid *git_reference_target(const git_reference *ref) if (ref->type != GIT_REF_OID) return NULL; - return &ref->target.oid; + return &ref->target.direct.oid; +} + +const git_oid *git_reference_target_peel(const git_reference *ref) +{ + assert(ref); + + if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->target.direct.peel)) + return NULL; + + return &ref->target.direct.peel; } const char *git_reference_symbolic_target(const git_reference *ref) @@ -335,8 +365,15 @@ static int reference__create( (error = reference_can_write(repo, normalized, NULL, force)) < 0 || (error = git_repository_refdb__weakptr(&refdb, repo)) < 0) return error; + + if (oid != NULL) { + assert(symbolic == NULL); + ref = git_reference__alloc(refdb, name, oid, NULL); + } else { + ref = git_reference__alloc_symbolic(refdb, name, symbolic); + } - if ((ref = git_reference__alloc(refdb, name, oid, symbolic)) == NULL) + if (ref == NULL) return -1; if ((error = git_refdb_write(refdb, ref)) < 0) { @@ -437,8 +474,6 @@ int git_reference_rename( char normalized[GIT_REFNAME_MAX]; bool should_head_be_updated = false; git_reference *result = NULL; - git_oid *oid; - const char *symbolic; int error = 0; int reference_has_log; @@ -447,7 +482,8 @@ int git_reference_rename( normalization_flags = ref->type == GIT_REF_SYMBOLIC ? GIT_REF_FORMAT_ALLOW_ONELEVEL : GIT_REF_FORMAT_NORMAL; - if ((error = git_reference_normalize_name(normalized, sizeof(normalized), new_name, normalization_flags)) < 0 || + if ((error = git_reference_normalize_name( + normalized, sizeof(normalized), new_name, normalization_flags)) < 0 || (error = reference_can_write(ref->db->repo, normalized, ref->name, force)) < 0) return error; @@ -455,14 +491,15 @@ int git_reference_rename( * Create the new reference. */ if (ref->type == GIT_REF_OID) { - oid = &ref->target.oid; - symbolic = NULL; + result = git_reference__alloc(ref->db, new_name, + &ref->target.direct.oid, &ref->target.direct.peel); + } else if (ref->type == GIT_REF_SYMBOLIC) { + result = git_reference__alloc_symbolic(ref->db, new_name, ref->target.symbolic); } else { - oid = NULL; - symbolic = ref->target.symbolic; + assert(0); } - - if ((result = git_reference__alloc(ref->db, new_name, oid, symbolic)) == NULL) + + if (result == NULL) return -1; /* Check if we have to update HEAD. */ @@ -509,11 +546,17 @@ on_error: int git_reference_resolve(git_reference **ref_out, const git_reference *ref) { - if (ref->type == GIT_REF_OID) + switch (git_reference_type(ref)) { + case GIT_REF_OID: return git_reference_lookup(ref_out, ref->db->repo, ref->name); - else - return git_reference_lookup_resolved(ref_out, ref->db->repo, - ref->target.symbolic, -1); + + case GIT_REF_SYMBOLIC: + return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1); + + default: + giterr_set(GITERR_REFERENCE, "Invalid reference"); + return -1; + } } int git_reference_foreach( @@ -778,16 +821,20 @@ int git_reference__normalize_name_lax( int git_reference_cmp(git_reference *ref1, git_reference *ref2) { + git_ref_t type1, type2; assert(ref1 && ref2); - /* let's put symbolic refs before OIDs */ - if (ref1->type != ref2->type) - return (ref1->type == GIT_REF_SYMBOLIC) ? -1 : 1; + type1 = git_reference_type(ref1); + type2 = git_reference_type(ref2); - if (ref1->type == GIT_REF_SYMBOLIC) + /* let's put symbolic refs before OIDs */ + if (type1 != type2) + return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1; + + if (type1 == GIT_REF_SYMBOLIC) return strcmp(ref1->target.symbolic, ref2->target.symbolic); - return git_oid_cmp(&ref1->target.oid, &ref2->target.oid); + return git_oid_cmp(&ref1->target.direct.oid, &ref2->target.direct.oid); } static int reference__update_terminal( @@ -905,15 +952,6 @@ static int peel_error(int error, git_reference *ref, const char* msg) return error; } -static int reference_target(git_object **object, git_reference *ref) -{ - const git_oid *oid; - - oid = git_reference_target(ref); - - return git_object_lookup(object, git_reference_owner(ref), oid, GIT_OBJ_ANY); -} - int git_reference_peel( git_object **peeled, git_reference *ref, @@ -925,10 +963,22 @@ int git_reference_peel( assert(ref); - if ((error = git_reference_resolve(&resolved, ref)) < 0) - return peel_error(error, ref, "Cannot resolve reference"); + if (ref->type == GIT_REF_OID) { + resolved = ref; + } else { + if ((error = git_reference_resolve(&resolved, ref)) < 0) + return peel_error(error, ref, "Cannot resolve reference"); + } - if ((error = reference_target(&target, resolved)) < 0) { + if (!git_oid_iszero(&resolved->target.direct.peel)) { + error = git_object_lookup(&target, + git_reference_owner(ref), &resolved->target.direct.peel, GIT_OBJ_ANY); + } else { + error = git_object_lookup(&target, + git_reference_owner(ref), &resolved->target.direct.oid, GIT_OBJ_ANY); + } + + if (error < 0) { peel_error(error, ref, "Cannot retrieve reference target"); goto cleanup; } @@ -940,7 +990,10 @@ int git_reference_peel( cleanup: git_object_free(target); - git_reference_free(resolved); + + if (resolved != ref) + git_reference_free(resolved); + return error; } diff --git a/src/refs.h b/src/refs.h index 7d63c3fbd..b0aa56a54 100644 --- a/src/refs.h +++ b/src/refs.h @@ -49,11 +49,14 @@ struct git_reference { git_refdb *db; - git_ref_t type; union { - git_oid oid; + struct { + git_oid oid; + git_oid peel; + } direct; + char *symbolic; } target; diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index 6f5651964..2cccd8eb2 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -135,7 +135,7 @@ int foreach_test(const char *ref_name, void *payload) else if (*i == 2) cl_git_pass(git_oid_fromstr(&expected, "763d71aadf09a7951596c9746c024e7eece7c7af")); - cl_assert(git_oid_cmp(&expected, &ref->target.oid) == 0); + cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0); ++(*i); @@ -176,7 +176,7 @@ int delete_test(const char *ref_name, void *payload) cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d")); - cl_assert(git_oid_cmp(&expected, &ref->target.oid) == 0); + cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0); ++(*i); diff --git a/tests-clar/refdb/testdb.c b/tests-clar/refdb/testdb.c index a8e7ba5fe..e60f6790e 100644 --- a/tests-clar/refdb/testdb.c +++ b/tests-clar/refdb/testdb.c @@ -98,12 +98,16 @@ static int refdb_test_backend__lookup( git_vector_foreach(&backend->refs, i, entry) { if (strcmp(entry->name, ref_name) == 0) { - const git_oid *oid = - entry->type == GIT_REF_OID ? &entry->target.oid : NULL; - const char *symbolic = - entry->type == GIT_REF_SYMBOLIC ? entry->target.symbolic : NULL; - - if ((*out = git_reference__alloc(backend->refdb, ref_name, oid, symbolic)) == NULL) + + if (entry->type == GIT_REF_OID) { + *out = git_reference__alloc(backend->refdb, ref_name, + &entry->target.oid, NULL); + } else if (entry->type == GIT_REF_SYMBOLIC) { + *out = git_reference__alloc_symbolic(backend->refdb, ref_name, + entry->target.symbolic); + } + + if (*out == NULL) return -1; return 0; From 0da62c5cf094394e7d9a4f7ef0832f8459ab3d40 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 17 Apr 2013 10:52:49 -0500 Subject: [PATCH 006/134] checkout: use cache when possible to determine if workdir item is dirty If the on-disk file has been staged (it's stat data matches the stat data in the cache) then we need not hash the file to determine whether it differs from the checkout target; instead we can simply use the oid in the index. This prevents recomputing a file's hash unnecessarily, prevents loading the file (when filtering) and prevents edge cases where filters suggest that a file is dirty immediately after git writes the file. --- src/checkout.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/checkout.c b/src/checkout.c index 24fa21024..81dc5e3da 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -119,6 +119,7 @@ static bool checkout_is_workdir_modified( const git_index_entry *wditem) { git_oid oid; + const git_index_entry *ie; /* handle "modified" submodule */ if (wditem->mode == GIT_FILEMODE_COMMIT) { @@ -140,6 +141,17 @@ static bool checkout_is_workdir_modified( return (git_oid_cmp(&baseitem->oid, sm_oid) != 0); } + /* Look at the cache to decide if the workdir is modified. If not, + * we can simply compare the oid in the cache to the baseitem instead + * of hashing the file. + */ + if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) { + if (wditem->mtime.seconds == ie->mtime.seconds && + wditem->mtime.nanoseconds == ie->mtime.nanoseconds && + wditem->file_size == ie->file_size) + return (git_oid_cmp(&baseitem->oid, &ie->oid) != 0); + } + /* depending on where base is coming from, we may or may not know * the actual size of the data, so we can't rely on this shortcut. */ From 13421eee1ac89a90f45524d8158ace98aae3d0b9 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 17 Apr 2013 22:32:39 +0200 Subject: [PATCH 007/134] refs: Check alloc is cleaner --- src/refs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/refs.c b/src/refs.c index 290b89b41..982cd05b7 100644 --- a/src/refs.c +++ b/src/refs.c @@ -373,8 +373,7 @@ static int reference__create( ref = git_reference__alloc_symbolic(refdb, name, symbolic); } - if (ref == NULL) - return -1; + GITERR_CHECK_ALLOC(ref); if ((error = git_refdb_write(refdb, ref)) < 0) { git_reference_free(ref); From fedd0f9e90e3046a8c50f6209c37d3b4566bab10 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 17 Apr 2013 23:29:34 +0200 Subject: [PATCH 008/134] refs: Do not union the peel --- src/refdb_fs.c | 2 +- src/refs.c | 20 ++++++++++---------- src/refs.h | 9 +++------ 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 730148a8f..784749fd3 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -645,7 +645,7 @@ static int loose_write(refdb_fs_backend *backend, const git_reference *ref) if (ref->type == GIT_REF_OID) { char oid[GIT_OID_HEXSZ + 1]; - git_oid_fmt(oid, &ref->target.direct.oid); + git_oid_fmt(oid, &ref->target.oid); oid[GIT_OID_HEXSZ] = '\0'; git_filebuf_printf(&file, "%s\n", oid); diff --git a/src/refs.c b/src/refs.c index 982cd05b7..29d1c4fa9 100644 --- a/src/refs.c +++ b/src/refs.c @@ -83,10 +83,10 @@ git_reference *git_reference__alloc( return NULL; ref->type = GIT_REF_OID; - git_oid_cpy(&ref->target.direct.oid, oid); + git_oid_cpy(&ref->target.oid, oid); if (peel != NULL) - git_oid_cpy(&ref->target.direct.peel, peel); + git_oid_cpy(&ref->peel, peel); return ref; } @@ -322,17 +322,17 @@ const git_oid *git_reference_target(const git_reference *ref) if (ref->type != GIT_REF_OID) return NULL; - return &ref->target.direct.oid; + return &ref->target.oid; } const git_oid *git_reference_target_peel(const git_reference *ref) { assert(ref); - if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->target.direct.peel)) + if (ref->type != GIT_REF_OID || git_oid_iszero(&ref->peel)) return NULL; - return &ref->target.direct.peel; + return &ref->peel; } const char *git_reference_symbolic_target(const git_reference *ref) @@ -491,7 +491,7 @@ int git_reference_rename( */ if (ref->type == GIT_REF_OID) { result = git_reference__alloc(ref->db, new_name, - &ref->target.direct.oid, &ref->target.direct.peel); + &ref->target.oid, &ref->peel); } else if (ref->type == GIT_REF_SYMBOLIC) { result = git_reference__alloc_symbolic(ref->db, new_name, ref->target.symbolic); } else { @@ -833,7 +833,7 @@ int git_reference_cmp(git_reference *ref1, git_reference *ref2) if (type1 == GIT_REF_SYMBOLIC) return strcmp(ref1->target.symbolic, ref2->target.symbolic); - return git_oid_cmp(&ref1->target.direct.oid, &ref2->target.direct.oid); + return git_oid_cmp(&ref1->target.oid, &ref2->target.oid); } static int reference__update_terminal( @@ -969,12 +969,12 @@ int git_reference_peel( return peel_error(error, ref, "Cannot resolve reference"); } - if (!git_oid_iszero(&resolved->target.direct.peel)) { + if (!git_oid_iszero(&resolved->peel)) { error = git_object_lookup(&target, - git_reference_owner(ref), &resolved->target.direct.peel, GIT_OBJ_ANY); + git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY); } else { error = git_object_lookup(&target, - git_reference_owner(ref), &resolved->target.direct.oid, GIT_OBJ_ANY); + git_reference_owner(ref), &resolved->target.oid, GIT_OBJ_ANY); } if (error < 0) { diff --git a/src/refs.h b/src/refs.h index b0aa56a54..97d4d2eb5 100644 --- a/src/refs.h +++ b/src/refs.h @@ -52,14 +52,11 @@ struct git_reference { git_ref_t type; union { - struct { - git_oid oid; - git_oid peel; - } direct; - + git_oid oid; char *symbolic; } target; - + + git_oid peel; char name[0]; }; From 437d36662e7bf9680b8eaeec626cfba5f4d68bd9 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 18 Apr 2013 00:15:08 +0200 Subject: [PATCH 009/134] repository: Doc fix --- include/git2/repository.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index e3320975c..ed837b359 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -134,9 +134,7 @@ GIT_EXTERN(int) git_repository_open_ext( * @param bare_path Direct path to the bare repository * @return 0 on success, or an error code */ -GIT_EXTERN(int) git_repository_open_bare( - git_repository **out, - const char *bare_path); +GIT_EXTERN(int) git_repository_open_bare(git_repository **out, const char *bare_path); /** * Free a previously allocated repository From 8023b83a945eaf3be7baad4fa74d93f4a079be0f Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 17 Apr 2013 17:21:17 -0500 Subject: [PATCH 010/134] use a longer string for dummy data in test to avoid conflicting w/ index --- tests-clar/checkout/typechange.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-clar/checkout/typechange.c b/tests-clar/checkout/typechange.c index b92cc23fa..6cf99ac15 100644 --- a/tests-clar/checkout/typechange.c +++ b/tests-clar/checkout/typechange.c @@ -187,7 +187,7 @@ static void force_create_file(const char *file) GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS); cl_assert(!error || error == GIT_ENOTFOUND); cl_git_pass(git_futils_mkpath2file(file, 0777)); - cl_git_rewritefile(file, "yowza!"); + cl_git_rewritefile(file, "yowza!!"); } void test_checkout_typechange__checkout_with_conflicts(void) From 9e46f6761891dbf05b733baae48e8c7161a213b5 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 18 Apr 2013 00:55:20 -0400 Subject: [PATCH 011/134] Return error for empty name/email --- src/signature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/signature.c b/src/signature.c index 164e8eb67..649dbcd3d 100644 --- a/src/signature.c +++ b/src/signature.c @@ -69,7 +69,7 @@ int git_signature_new(git_signature **sig_out, const char *name, const char *ema if (p->name == NULL || p->email == NULL || p->name[0] == '\0' || p->email[0] == '\0') { git_signature_free(p); - return -1; + return signature_error("Empty name or email"); } p->when.time = time; From f90391ea5fdcd5ef972958ac375d8223a5045cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 18 Apr 2013 14:47:54 +0200 Subject: [PATCH 012/134] treebuilder: don't overwrite the error message --- src/tree.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tree.c b/src/tree.c index 17b3c378d..d2db84055 100644 --- a/src/tree.c +++ b/src/tree.c @@ -525,7 +525,6 @@ static int write_tree( /* Write out the subtree */ written = write_tree(&sub_oid, repo, index, subdir, i); if (written < 0) { - tree_error("Failed to write subtree", subdir); git__free(subdir); goto on_error; } else { From ff0ddfa4bbec2e27491c822cf6b882c54d8675c8 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Wed, 17 Apr 2013 15:56:31 -0700 Subject: [PATCH 013/134] Add filesystem iterator variant This adds a new variant iterator that is a raw filesystem iterator for scanning directories from a root. There is still more work to do to blend this with the working directory iterator. --- src/iterator.c | 301 +++++++++++++++++++++++++++++++++++++ src/iterator.h | 11 ++ tests-clar/repo/iterator.c | 44 ++++++ 3 files changed, 356 insertions(+) diff --git a/src/iterator.c b/src/iterator.c index 5b5ed9525..dd8a6133d 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -833,6 +833,307 @@ int git_iterator_for_index( } +typedef struct fs_iterator_frame fs_iterator_frame; +struct fs_iterator_frame { + fs_iterator_frame *next; + git_vector entries; + size_t index; +}; + +typedef struct { + git_iterator base; + git_iterator_callbacks cb; + fs_iterator_frame *stack; + git_index_entry entry; + git_buf path; + size_t root_len; + int depth; +} fs_iterator; + +#define FS_MAX_DEPTH 100 + +static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) +{ + fs_iterator_frame *ff = git__calloc(1, sizeof(fs_iterator_frame)); + git_vector_cmp entry_compare = CASESELECT( + iterator__ignore_case(fi), + git_path_with_stat_cmp_icase, git_path_with_stat_cmp); + + if (ff && git_vector_init(&ff->entries, 0, entry_compare) < 0) { + git__free(ff); + ff = NULL; + } + + return ff; +} + +static void fs_iterator__free_frame(fs_iterator_frame *ff) +{ + size_t i; + git_path_with_stat *path; + + git_vector_foreach(&ff->entries, i, path) + git__free(path); + git_vector_free(&ff->entries); + git__free(ff); +} + +static int fs_iterator__update_entry(fs_iterator *fi); + +static int fs_iterator__entry_cmp(const void *i, const void *item) +{ + const fs_iterator *fi = (const fs_iterator *)i; + const git_path_with_stat *ps = item; + return fi->base.prefixcomp(fi->base.start, ps->path); +} + +static void fs_iterator__seek_frame_start( + fs_iterator *fi, fs_iterator_frame *ff) +{ + if (!ff) + return; + + if (fi->base.start) + git_vector_bsearch2( + &ff->index, &ff->entries, fs_iterator__entry_cmp, fi); + else + ff->index = 0; +} + +static int fs_iterator__expand_dir(fs_iterator *fi) +{ + int error; + fs_iterator_frame *ff; + + ff = fs_iterator__alloc_frame(fi); + GITERR_CHECK_ALLOC(ff); + + error = git_path_dirload_with_stat( + fi->path.ptr, fi->root_len, iterator__ignore_case(fi), + fi->base.start, fi->base.end, &ff->entries); + + if (error < 0 || ff->entries.length == 0) { + fs_iterator__free_frame(ff); + return GIT_ENOTFOUND; + } + + if (++(fi->depth) > FS_MAX_DEPTH) { + giterr_set(GITERR_REPOSITORY, + "Directory nesting is too deep (%d)", fi->depth); + fs_iterator__free_frame(ff); + return -1; + } + + fs_iterator__seek_frame_start(fi, ff); + + ff->next = fi->stack; + fi->stack = ff; + + return fs_iterator__update_entry(fi); +} + +static int fs_iterator__current( + const git_index_entry **entry, git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + if (entry) + *entry = (fi->entry.path == NULL) ? NULL : &fi->entry; + return 0; +} + +static int fs_iterator__at_end(git_iterator *self) +{ + return (((fs_iterator *)self)->entry.path == NULL); +} + +static int fs_iterator__advance_into( + const git_index_entry **entry, git_iterator *iter) +{ + int error = 0; + fs_iterator *fi = (fs_iterator *)iter; + + iterator__clear_entry(entry); + + /* Allow you to explicitly advance into a commit/submodule (as well as a + * tree) to avoid cases where an entry is mislabeled as a submodule in + * the working directory. The fs iterator will never have COMMMIT + * entries on it's own, but a wrapper might add them. + */ + if (fi->entry.path != NULL && + (fi->entry.mode == GIT_FILEMODE_TREE || + fi->entry.mode == GIT_FILEMODE_COMMIT)) + /* returns GIT_ENOTFOUND if the directory is empty */ + error = fs_iterator__expand_dir(fi); + + if (!error && entry) + error = fs_iterator__current(entry, iter); + + return error; +} + +static int fs_iterator__advance( + const git_index_entry **entry, git_iterator *self) +{ + int error = 0; + fs_iterator *fi = (fs_iterator *)self; + fs_iterator_frame *ff; + git_path_with_stat *next; + + /* given include_trees & autoexpand, we might have to go into a tree */ + if (iterator__do_autoexpand(fi) && + fi->entry.path != NULL && + fi->entry.mode == GIT_FILEMODE_TREE) + { + error = fs_iterator__advance_into(entry, self); + + /* continue silently past empty directories if autoexpanding */ + if (error != GIT_ENOTFOUND) + return error; + giterr_clear(); + error = 0; + } + + if (entry != NULL) + *entry = NULL; + + while (fi->entry.path != NULL) { + ff = fi->stack; + next = git_vector_get(&ff->entries, ++ff->index); + + if (next != NULL) + break; + + /* pop stack if anything is left to pop */ + if (!ff->next) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return 0; + } + + fi->stack = ff->next; + fi->depth--; + fs_iterator__free_frame(ff); + } + + error = fs_iterator__update_entry(fi); + + if (!error && entry != NULL) + error = fs_iterator__current(entry, self); + + return error; +} + +static int fs_iterator__seek(git_iterator *self, const char *prefix) +{ + GIT_UNUSED(self); + GIT_UNUSED(prefix); + /* pop stack until matching prefix */ + /* find prefix item in current frame */ + /* push subdirectories as deep as possible while matching */ + return 0; +} + +static int fs_iterator__reset( + git_iterator *self, const char *start, const char *end) +{ + fs_iterator *fi = (fs_iterator *)self; + + while (fi->stack != NULL && fi->stack->next != NULL) { + fs_iterator_frame *ff = fi->stack; + fi->stack = ff->next; + fs_iterator__free_frame(ff); + } + fi->depth = 0; + + if (iterator__reset_range(self, start, end) < 0) + return -1; + + fs_iterator__seek_frame_start(fi, fi->stack); + + return fs_iterator__update_entry(fi); +} + +static void fs_iterator__free(git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + + while (fi->stack != NULL) { + fs_iterator_frame *ff = fi->stack; + fi->stack = ff->next; + fs_iterator__free_frame(ff); + } + + git_buf_free(&fi->path); +} + +static int fs_iterator__update_entry(fs_iterator *fi) +{ + git_path_with_stat *ps = + git_vector_get(&fi->stack->entries, fi->stack->index); + + git_buf_truncate(&fi->path, fi->root_len); + memset(&fi->entry, 0, sizeof(fi->entry)); + + if (!ps) + return 0; + + if (git_buf_put(&fi->path, ps->path, ps->path_len) < 0) + return -1; + + if (iterator__past_end(fi, fi->path.ptr + fi->root_len)) + return 0; + + fi->entry.path = ps->path; + git_index_entry__init_from_stat(&fi->entry, &ps->st); + + /* need different mode here to keep directories during iteration */ + fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); + + /* if this isn't a tree, then we're done */ + if (fi->entry.mode != GIT_FILEMODE_TREE) + return 0; + + if (iterator__include_trees(fi)) + return 0; + + return fs_iterator__advance(NULL, (git_iterator *)fi); +} + +int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end) +{ + int error; + fs_iterator *fi; + + ITERATOR_BASE_INIT(fi, fs, FS, NULL); + + if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) + fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; + + if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { + git__free(fi); + return -1; + } + fi->root_len = fi->path.size; + + if ((error = fs_iterator__expand_dir(fi)) < 0) { + if (error != GIT_ENOTFOUND) + goto fail; + giterr_clear(); + } + + *out = (git_iterator *)fi; + return 0; + +fail: + git_iterator_free((git_iterator *)fi); + return error; +} + + #define WORKDIR_MAX_DEPTH 100 typedef struct workdir_iterator_frame workdir_iterator_frame; diff --git a/src/iterator.h b/src/iterator.h index 4a4e6a9d8..7998f7c6b 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -19,6 +19,7 @@ typedef enum { GIT_ITERATOR_TYPE_TREE = 1, GIT_ITERATOR_TYPE_INDEX = 2, GIT_ITERATOR_TYPE_WORKDIR = 3, + GIT_ITERATOR_TYPE_FS = 4, } git_iterator_type_t; typedef enum { @@ -88,6 +89,16 @@ extern int git_iterator_for_workdir( const char *start, const char *end); +/* for filesystem iterators, you have to explicitly pass in the ignore_case + * behavior that you desire + */ +extern int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end); + extern void git_iterator_free(git_iterator *iter); /* Return a git_index_entry structure for the current value the iterator diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 00c46d6b1..ef9bfc33d 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -808,3 +808,47 @@ void test_repo_iterator__workdir_depth(void) expect_iterator_items(iter, 337, NULL, 337, NULL); git_iterator_free(iter); } + +void test_repo_iterator__fs(void) +{ + git_iterator *i; + static const char *expect_subdir[] = { + "current_file", + "modified_file", + "new_file", + NULL, + }; + + g_repo = cl_git_sandbox_init("status"); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", 0, NULL, NULL)); + expect_iterator_items(i, 3, expect_subdir, 3, expect_subdir); + git_iterator_free(i); +} + +void test_repo_iterator__fs2(void) +{ + git_iterator *i; + static const char *expect_subdir[] = { + "heads/br2", + "heads/dir", + "heads/master", + "heads/packed-test", + "heads/subtrees", + "heads/test", + "tags/e90810b", + "tags/foo/bar", + "tags/foo/foo/bar", + "tags/point_to_blob", + "tags/test", + NULL, + }; + + g_repo = cl_git_sandbox_init("testrepo"); + + cl_git_pass(git_iterator_for_filesystem( + &i, "testrepo/.git/refs", 0, NULL, NULL)); + expect_iterator_items(i, 11, expect_subdir, 11, expect_subdir); + git_iterator_free(i); +} From 71f85226eb5c2ef9e8c8ddb1943fc7fc1e6615ff Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 11:11:38 -0700 Subject: [PATCH 014/134] Make workdir iterator use filesystem iterator This adds some hooks into the filesystem iterator so that the workdir iterator can just become a wrapper around it. Then we remove most of the workdir iterator code and just have it augment the filesystem iterator with skipping .git entries, updating the ignore stack, and checking for submodules. --- src/iterator.c | 557 ++++++++++++++----------------------------------- 1 file changed, 160 insertions(+), 397 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index dd8a6133d..6eee5a805 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -26,8 +26,6 @@ (GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_DONT_IGNORE_CASE) #define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC,REPO) do { \ - (P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \ - GITERR_CHECK_ALLOC(P); \ (P)->base.type = GIT_ITERATOR_TYPE_ ## NAME_UC; \ (P)->base.cb = &(P)->cb; \ ITERATOR_SET_CB(P,NAME_LC); \ @@ -148,7 +146,8 @@ int git_iterator_for_nothing( const char *start, const char *end) { - empty_iterator *i; + empty_iterator *i = git__calloc(1, sizeof(empty_iterator)); + GITERR_CHECK_ALLOC(i); #define empty_iterator__current empty_iterator__noop #define empty_iterator__advance empty_iterator__noop @@ -581,6 +580,9 @@ int git_iterator_for_tree( if ((error = git_object_dup((git_object **)&tree, (git_object *)tree)) < 0) return error; + ti = git__calloc(1, sizeof(tree_iterator)); + GITERR_CHECK_ALLOC(ti); + ITERATOR_BASE_INIT(ti, tree, TREE, git_tree_owner(tree)); if ((error = iterator__update_ignore_case((git_iterator *)ti, flags)) < 0) @@ -810,7 +812,8 @@ int git_iterator_for_index( const char *start, const char *end) { - index_iterator *ii; + index_iterator *ii = git__calloc(1, sizeof(index_iterator)); + GITERR_CHECK_ALLOC(ii); ITERATOR_BASE_INIT(ii, index, INDEX, git_index_owner(index)); @@ -840,7 +843,8 @@ struct fs_iterator_frame { size_t index; }; -typedef struct { +typedef struct fs_iterator fs_iterator; +struct fs_iterator { git_iterator base; git_iterator_callbacks cb; fs_iterator_frame *stack; @@ -848,7 +852,11 @@ typedef struct { git_buf path; size_t root_len; int depth; -} fs_iterator; + + int (*frame_added)(fs_iterator *self); + int (*frame_removed)(fs_iterator *self); + int (*entry_updated)(fs_iterator *self); +}; #define FS_MAX_DEPTH 100 @@ -867,15 +875,31 @@ static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) return ff; } -static void fs_iterator__free_frame(fs_iterator_frame *ff) +static void fs_iterator__pop_frame( + fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) { size_t i; git_path_with_stat *path; + fs_iterator_frame *ff_next = ff->next; + + if (fi && !ff_next && !pop_last) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return; + } git_vector_foreach(&ff->entries, i, path) git__free(path); git_vector_free(&ff->entries); git__free(ff); + + if (!fi || fi->stack != ff) + return; + + fi->stack = ff_next; + fi->depth--; + + if (fi->frame_removed) + fi->frame_removed(fi); } static int fs_iterator__update_entry(fs_iterator *fi); @@ -913,14 +937,14 @@ static int fs_iterator__expand_dir(fs_iterator *fi) fi->base.start, fi->base.end, &ff->entries); if (error < 0 || ff->entries.length == 0) { - fs_iterator__free_frame(ff); + fs_iterator__pop_frame(NULL, ff, true); return GIT_ENOTFOUND; } if (++(fi->depth) > FS_MAX_DEPTH) { giterr_set(GITERR_REPOSITORY, "Directory nesting is too deep (%d)", fi->depth); - fs_iterator__free_frame(ff); + fs_iterator__pop_frame(NULL, ff, true); return -1; } @@ -929,6 +953,9 @@ static int fs_iterator__expand_dir(fs_iterator *fi) ff->next = fi->stack; fi->stack = ff; + if (fi->frame_added && (error = fi->frame_added(fi)) < 0) + return error; + return fs_iterator__update_entry(fi); } @@ -971,7 +998,7 @@ static int fs_iterator__advance_into( return error; } -static int fs_iterator__advance( +static int fs_iterator__advance_over( const git_index_entry **entry, git_iterator *self) { int error = 0; @@ -979,20 +1006,6 @@ static int fs_iterator__advance( fs_iterator_frame *ff; git_path_with_stat *next; - /* given include_trees & autoexpand, we might have to go into a tree */ - if (iterator__do_autoexpand(fi) && - fi->entry.path != NULL && - fi->entry.mode == GIT_FILEMODE_TREE) - { - error = fs_iterator__advance_into(entry, self); - - /* continue silently past empty directories if autoexpanding */ - if (error != GIT_ENOTFOUND) - return error; - giterr_clear(); - error = 0; - } - if (entry != NULL) *entry = NULL; @@ -1003,15 +1016,7 @@ static int fs_iterator__advance( if (next != NULL) break; - /* pop stack if anything is left to pop */ - if (!ff->next) { - memset(&fi->entry, 0, sizeof(fi->entry)); - return 0; - } - - fi->stack = ff->next; - fi->depth--; - fs_iterator__free_frame(ff); + fs_iterator__pop_frame(fi, ff, false); } error = fs_iterator__update_entry(fi); @@ -1022,6 +1027,26 @@ static int fs_iterator__advance( return error; } +static int fs_iterator__advance( + const git_index_entry **entry, git_iterator *self) +{ + fs_iterator *fi = (fs_iterator *)self; + + /* given include_trees & autoexpand, we might have to go into a tree */ + if (iterator__do_autoexpand(fi) && + fi->entry.path != NULL && + fi->entry.mode == GIT_FILEMODE_TREE) + { + int error = fs_iterator__advance_into(entry, self); + if (error != GIT_ENOTFOUND) + return error; + /* continue silently past empty directories if autoexpanding */ + giterr_clear(); + } + + return fs_iterator__advance_over(entry, self); +} + static int fs_iterator__seek(git_iterator *self, const char *prefix) { GIT_UNUSED(self); @@ -1037,11 +1062,8 @@ static int fs_iterator__reset( { fs_iterator *fi = (fs_iterator *)self; - while (fi->stack != NULL && fi->stack->next != NULL) { - fs_iterator_frame *ff = fi->stack; - fi->stack = ff->next; - fs_iterator__free_frame(ff); - } + while (fi->stack != NULL && fi->stack->next != NULL) + fs_iterator__pop_frame(fi, fi->stack, false); fi->depth = 0; if (iterator__reset_range(self, start, end) < 0) @@ -1056,11 +1078,8 @@ static void fs_iterator__free(git_iterator *self) { fs_iterator *fi = (fs_iterator *)self; - while (fi->stack != NULL) { - fs_iterator_frame *ff = fi->stack; - fi->stack = ff->next; - fs_iterator__free_frame(ff); - } + while (fi->stack != NULL) + fs_iterator__pop_frame(fi, fi->stack, true); git_buf_free(&fi->path); } @@ -1075,10 +1094,8 @@ static int fs_iterator__update_entry(fs_iterator *fi) if (!ps) return 0; - if (git_buf_put(&fi->path, ps->path, ps->path_len) < 0) return -1; - if (iterator__past_end(fi, fi->path.ptr + fi->root_len)) return 0; @@ -1088,14 +1105,41 @@ static int fs_iterator__update_entry(fs_iterator *fi) /* need different mode here to keep directories during iteration */ fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); - /* if this isn't a tree, then we're done */ - if (fi->entry.mode != GIT_FILEMODE_TREE) - return 0; + /* allow wrapper to check/update the entry (can force skip) */ + if (fi->entry_updated && + fi->entry_updated(fi) == GIT_ENOTFOUND) + return fs_iterator__advance_over(NULL, (git_iterator *)fi); - if (iterator__include_trees(fi)) - return 0; + /* if this is a tree and trees aren't included, then skip */ + if (fi->entry.mode == GIT_FILEMODE_TREE && !iterator__include_trees(fi)) + return git_iterator_advance(NULL, (git_iterator *)fi); - return fs_iterator__advance(NULL, (git_iterator *)fi); + return 0; +} + +static int fs_iterator__initialize( + git_iterator **out, fs_iterator *fi, const char *root) +{ + int error; + + if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { + git__free(fi); + return -1; + } + + fi->root_len = fi->path.size; + + if ((error = fs_iterator__expand_dir(fi)) == GIT_ENOTFOUND) { + giterr_clear(); + error = 0; + } + if (error) { + git_iterator_free((git_iterator *)fi); + fi = NULL; + } + + *out = (git_iterator *)fi; + return error; } int git_iterator_for_filesystem( @@ -1105,372 +1149,97 @@ int git_iterator_for_filesystem( const char *start, const char *end) { - int error; - fs_iterator *fi; + fs_iterator *fi = git__calloc(1, sizeof(fs_iterator)); + GITERR_CHECK_ALLOC(fi); ITERATOR_BASE_INIT(fi, fs, FS, NULL); if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; - if (git_buf_sets(&fi->path, root) < 0 || git_path_to_dir(&fi->path) < 0) { - git__free(fi); - return -1; - } - fi->root_len = fi->path.size; - - if ((error = fs_iterator__expand_dir(fi)) < 0) { - if (error != GIT_ENOTFOUND) - goto fail; - giterr_clear(); - } - - *out = (git_iterator *)fi; - return 0; - -fail: - git_iterator_free((git_iterator *)fi); - return error; + return fs_iterator__initialize(out, fi, root); } -#define WORKDIR_MAX_DEPTH 100 - -typedef struct workdir_iterator_frame workdir_iterator_frame; -struct workdir_iterator_frame { - workdir_iterator_frame *next; - git_vector entries; - size_t index; -}; - typedef struct { - git_iterator base; - git_iterator_callbacks cb; - workdir_iterator_frame *stack; + fs_iterator fi; git_ignores ignores; - git_index_entry entry; - git_buf path; - size_t root_len; int is_ignored; - int depth; } workdir_iterator; -GIT_INLINE(bool) path_is_dotgit(const git_path_with_stat *ps) +GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) { - if (!ps) + size_t len; + + if (!path || (len = path->size) < 4) return false; - else { - const char *path = ps->path; - size_t len = ps->path_len; - if (len < 4) - return false; - if (path[len - 1] == '/') - len--; - if (tolower(path[len - 1]) != 't' || - tolower(path[len - 2]) != 'i' || - tolower(path[len - 3]) != 'g' || - tolower(path[len - 4]) != '.') - return false; - return (len == 4 || path[len - 5] == '/'); - } + if (path->ptr[len - 1] == '/') + len--; + + if (tolower(path->ptr[len - 1]) != 't' || + tolower(path->ptr[len - 2]) != 'i' || + tolower(path->ptr[len - 3]) != 'g' || + tolower(path->ptr[len - 4]) != '.') + return false; + + return (len == 4 || path->ptr[len - 5] == '/'); } -static workdir_iterator_frame *workdir_iterator__alloc_frame( - workdir_iterator *wi) +static int workdir_iterator__frame_added(fs_iterator *fi) { - workdir_iterator_frame *wf = git__calloc(1, sizeof(workdir_iterator_frame)); - git_vector_cmp entry_compare = CASESELECT( - iterator__ignore_case(wi), - git_path_with_stat_cmp_icase, git_path_with_stat_cmp); - - if (wf == NULL) - return NULL; - - if (git_vector_init(&wf->entries, 0, entry_compare) != 0) { - git__free(wf); - return NULL; - } - - return wf; -} - -static void workdir_iterator__free_frame(workdir_iterator_frame *wf) -{ - unsigned int i; - git_path_with_stat *path; - - git_vector_foreach(&wf->entries, i, path) - git__free(path); - git_vector_free(&wf->entries); - git__free(wf); -} - -static int workdir_iterator__update_entry(workdir_iterator *wi); - -static int workdir_iterator__entry_cmp(const void *i, const void *item) -{ - const workdir_iterator *wi = (const workdir_iterator *)i; - const git_path_with_stat *ps = item; - return wi->base.prefixcomp(wi->base.start, ps->path); -} - -static void workdir_iterator__seek_frame_start( - workdir_iterator *wi, workdir_iterator_frame *wf) -{ - if (!wf) - return; - - if (wi->base.start) - git_vector_bsearch2( - &wf->index, &wf->entries, workdir_iterator__entry_cmp, wi); - else - wf->index = 0; - - if (path_is_dotgit(git_vector_get(&wf->entries, wf->index))) - wf->index++; -} - -static int workdir_iterator__expand_dir(workdir_iterator *wi) -{ - int error; - workdir_iterator_frame *wf; - - wf = workdir_iterator__alloc_frame(wi); - GITERR_CHECK_ALLOC(wf); - - error = git_path_dirload_with_stat( - wi->path.ptr, wi->root_len, iterator__ignore_case(wi), - wi->base.start, wi->base.end, &wf->entries); - - if (error < 0 || wf->entries.length == 0) { - workdir_iterator__free_frame(wf); - return GIT_ENOTFOUND; - } - - if (++(wi->depth) > WORKDIR_MAX_DEPTH) { - giterr_set(GITERR_REPOSITORY, - "Working directory is too deep (%d)", wi->depth); - workdir_iterator__free_frame(wf); - return -1; - } - - workdir_iterator__seek_frame_start(wi, wf); - /* only push new ignores if this is not top level directory */ - if (wi->stack != NULL) { - ssize_t slash_pos = git_buf_rfind_next(&wi->path, '/'); - (void)git_ignore__push_dir(&wi->ignores, &wi->path.ptr[slash_pos + 1]); + if (fi->stack->next != NULL) { + workdir_iterator *wi = (workdir_iterator *)fi; + ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/'); + + (void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]); } - wf->next = wi->stack; - wi->stack = wf; - - return workdir_iterator__update_entry(wi); -} - -static int workdir_iterator__current( - const git_index_entry **entry, git_iterator *self) -{ - workdir_iterator *wi = (workdir_iterator *)self; - if (entry) - *entry = (wi->entry.path == NULL) ? NULL : &wi->entry; return 0; } -static int workdir_iterator__at_end(git_iterator *self) +static int workdir_iterator__frame_removed(fs_iterator *fi) { - return (((workdir_iterator *)self)->entry.path == NULL); + workdir_iterator *wi = (workdir_iterator *)fi; + git_ignore__pop_dir(&wi->ignores); + return 0; } -static int workdir_iterator__advance_into( - const git_index_entry **entry, git_iterator *iter) +static int workdir_iterator__entry_updated(fs_iterator *fi) { int error = 0; - workdir_iterator *wi = (workdir_iterator *)iter; + workdir_iterator *wi = (workdir_iterator *)fi; - iterator__clear_entry(entry); + /* skip over .git entries */ + if (workdir_path_is_dotgit(&fi->path)) + return GIT_ENOTFOUND; - /* workdir iterator will allow you to explicitly advance into a - * commit/submodule (as well as a tree) to avoid some cases where an - * entry is mislabeled as a submodule in the working directory - */ - if (wi->entry.path != NULL && - (wi->entry.mode == GIT_FILEMODE_TREE || - wi->entry.mode == GIT_FILEMODE_COMMIT)) - /* returns GIT_ENOTFOUND if the directory is empty */ - error = workdir_iterator__expand_dir(wi); + /* reset is_ignored since we haven't checked yet */ + wi->is_ignored = -1; - if (!error && entry) - error = workdir_iterator__current(entry, iter); + /* check if apparent tree entries are actually submodules */ + if (fi->entry.mode != GIT_FILEMODE_TREE) + return 0; - return error; -} - -static int workdir_iterator__advance( - const git_index_entry **entry, git_iterator *self) -{ - int error = 0; - workdir_iterator *wi = (workdir_iterator *)self; - workdir_iterator_frame *wf; - git_path_with_stat *next; - - /* given include_trees & autoexpand, we might have to go into a tree */ - if (iterator__do_autoexpand(wi) && - wi->entry.path != NULL && - wi->entry.mode == GIT_FILEMODE_TREE) - { - error = workdir_iterator__advance_into(entry, self); - - /* continue silently past empty directories if autoexpanding */ - if (error != GIT_ENOTFOUND) - return error; + error = git_submodule_lookup(NULL, fi->base.repo, fi->entry.path); + if (error < 0) giterr_clear(); - error = 0; + + /* mark submodule (or any dir with .git) as GITLINK and remove slash */ + if (!error || error == GIT_EEXISTS) { + fi->entry.mode = S_IFGITLINK; + fi->entry.path[strlen(fi->entry.path) - 1] = '\0'; } - if (entry != NULL) - *entry = NULL; - - while (wi->entry.path != NULL) { - wf = wi->stack; - next = git_vector_get(&wf->entries, ++wf->index); - - if (next != NULL) { - /* match git's behavior of ignoring anything named ".git" */ - if (path_is_dotgit(next)) - continue; - /* else found a good entry */ - break; - } - - /* pop stack if anything is left to pop */ - if (!wf->next) { - memset(&wi->entry, 0, sizeof(wi->entry)); - return 0; - } - - wi->stack = wf->next; - wi->depth--; - workdir_iterator__free_frame(wf); - git_ignore__pop_dir(&wi->ignores); - } - - error = workdir_iterator__update_entry(wi); - - if (!error && entry != NULL) - error = workdir_iterator__current(entry, self); - - return error; -} - -static int workdir_iterator__seek(git_iterator *self, const char *prefix) -{ - GIT_UNUSED(self); - GIT_UNUSED(prefix); - /* pop stack until matching prefix */ - /* find prefix item in current frame */ - /* push subdirectories as deep as possible while matching */ return 0; } -static int workdir_iterator__reset( - git_iterator *self, const char *start, const char *end) -{ - workdir_iterator *wi = (workdir_iterator *)self; - - while (wi->stack != NULL && wi->stack->next != NULL) { - workdir_iterator_frame *wf = wi->stack; - wi->stack = wf->next; - workdir_iterator__free_frame(wf); - git_ignore__pop_dir(&wi->ignores); - } - wi->depth = 0; - - if (iterator__reset_range(self, start, end) < 0) - return -1; - - workdir_iterator__seek_frame_start(wi, wi->stack); - - return workdir_iterator__update_entry(wi); -} - static void workdir_iterator__free(git_iterator *self) { workdir_iterator *wi = (workdir_iterator *)self; - - while (wi->stack != NULL) { - workdir_iterator_frame *wf = wi->stack; - wi->stack = wf->next; - workdir_iterator__free_frame(wf); - } - + fs_iterator__free(self); git_ignore__free(&wi->ignores); - git_buf_free(&wi->path); -} - -static int workdir_iterator__update_entry(workdir_iterator *wi) -{ - int error = 0; - git_path_with_stat *ps = - git_vector_get(&wi->stack->entries, wi->stack->index); - - git_buf_truncate(&wi->path, wi->root_len); - memset(&wi->entry, 0, sizeof(wi->entry)); - - if (!ps) - return 0; - - /* skip over .git entries */ - if (path_is_dotgit(ps)) - return workdir_iterator__advance(NULL, (git_iterator *)wi); - - if (git_buf_put(&wi->path, ps->path, ps->path_len) < 0) - return -1; - - if (iterator__past_end(wi, wi->path.ptr + wi->root_len)) - return 0; - - wi->entry.path = ps->path; - - wi->is_ignored = -1; - - git_index_entry__init_from_stat(&wi->entry, &ps->st); - - /* need different mode here to keep directories during iteration */ - wi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); - - /* if this is a file type we don't handle, treat as ignored */ - if (wi->entry.mode == 0) { - wi->is_ignored = 1; - return 0; - } - - /* if this isn't a tree, then we're done */ - if (wi->entry.mode != GIT_FILEMODE_TREE) - return 0; - - /* detect submodules */ - error = git_submodule_lookup(NULL, wi->base.repo, wi->entry.path); - if (error == GIT_ENOTFOUND) - giterr_clear(); - - if (error == GIT_EEXISTS) /* if contains .git, treat as untracked submod */ - error = 0; - - /* if submodule, mark as GITLINK and remove trailing slash */ - if (!error) { - size_t len = strlen(wi->entry.path); - assert(wi->entry.path[len - 1] == '/'); - wi->entry.path[len - 1] = '\0'; - wi->entry.mode = S_IFGITLINK; - return 0; - } - - if (iterator__include_trees(wi)) - return 0; - - return workdir_iterator__advance(NULL, (git_iterator *)wi); } int git_iterator_for_workdir( @@ -1481,7 +1250,8 @@ int git_iterator_for_workdir( const char *end) { int error; - workdir_iterator *wi; + workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); + GITERR_CHECK_ALLOC(wi); assert(iter && repo); @@ -1489,32 +1259,24 @@ int git_iterator_for_workdir( repo, "scan working directory")) < 0) return error; - ITERATOR_BASE_INIT(wi, workdir, WORKDIR, repo); + /* initialize as an fs iterator then do overrides */ + ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); - if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0) - goto fail; + wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; + wi->fi.cb.free = workdir_iterator__free; + wi->fi.frame_added = workdir_iterator__frame_added; + wi->fi.frame_removed = workdir_iterator__frame_removed; + wi->fi.entry_updated = workdir_iterator__entry_updated; - if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 || - git_path_to_dir(&wi->path) < 0 || - git_ignore__for_path(repo, "", &wi->ignores) < 0) + if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0 || + (error = git_ignore__for_path(repo, "", &wi->ignores)) < 0) { - git__free(wi); - return -1; - } - wi->root_len = wi->path.size; - - if ((error = workdir_iterator__expand_dir(wi)) < 0) { - if (error != GIT_ENOTFOUND) - goto fail; - giterr_clear(); + git_iterator_free((git_iterator *)wi); + return error; } - *iter = (git_iterator *)wi; - return 0; - -fail: - git_iterator_free((git_iterator *)wi); - return error; + return fs_iterator__initialize( + iter, (fs_iterator *)wi, git_repository_workdir(repo)); } @@ -1616,7 +1378,8 @@ bool git_iterator_current_is_ignored(git_iterator *iter) if (wi->is_ignored != -1) return (bool)(wi->is_ignored != 0); - if (git_ignore__lookup(&wi->ignores, wi->entry.path, &wi->is_ignored) < 0) + if (git_ignore__lookup( + &wi->ignores, wi->fi.entry.path, &wi->is_ignored) < 0) wi->is_ignored = true; return (bool)wi->is_ignored; @@ -1641,10 +1404,10 @@ int git_iterator_current_workdir_path(git_buf **path, git_iterator *iter) { workdir_iterator *wi = (workdir_iterator *)iter; - if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->entry.path) + if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->fi.entry.path) *path = NULL; else - *path = &wi->path; + *path = &wi->fi.path; return 0; } From fc57471a0c1834143ae6b18e65c1484c5c04e7e3 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:13:53 -0700 Subject: [PATCH 015/134] More filesystem iterator cleanup Renamed the callback functions and made some minor rearrangements to clean up the flow of some code. --- src/iterator.c | 83 +++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index 6eee5a805..a72f97eca 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -853,9 +853,9 @@ struct fs_iterator { size_t root_len; int depth; - int (*frame_added)(fs_iterator *self); - int (*frame_removed)(fs_iterator *self); - int (*entry_updated)(fs_iterator *self); + int (*enter_dir_cb)(fs_iterator *self); + int (*leave_dir_cb)(fs_iterator *self); + int (*update_entry_cb)(fs_iterator *self); }; #define FS_MAX_DEPTH 100 @@ -875,31 +875,34 @@ static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) return ff; } -static void fs_iterator__pop_frame( - fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) +static void fs_iterator__free_frame(fs_iterator_frame *ff) { size_t i; git_path_with_stat *path; - fs_iterator_frame *ff_next = ff->next; - - if (fi && !ff_next && !pop_last) { - memset(&fi->entry, 0, sizeof(fi->entry)); - return; - } git_vector_foreach(&ff->entries, i, path) git__free(path); git_vector_free(&ff->entries); git__free(ff); +} - if (!fi || fi->stack != ff) - return; +static void fs_iterator__pop_frame( + fs_iterator *fi, fs_iterator_frame *ff, bool pop_last) +{ + if (fi && fi->stack == ff) { + if (!ff->next && !pop_last) { + memset(&fi->entry, 0, sizeof(fi->entry)); + return; + } - fi->stack = ff_next; - fi->depth--; + if (fi->leave_dir_cb) + (void)fi->leave_dir_cb(fi); - if (fi->frame_removed) - fi->frame_removed(fi); + fi->stack = ff->next; + fi->depth--; + } + + fs_iterator__free_frame(ff); } static int fs_iterator__update_entry(fs_iterator *fi); @@ -929,6 +932,12 @@ static int fs_iterator__expand_dir(fs_iterator *fi) int error; fs_iterator_frame *ff; + if (fi->depth > FS_MAX_DEPTH) { + giterr_set(GITERR_REPOSITORY, + "Directory nesting is too deep (%d)", fi->depth); + return -1; + } + ff = fs_iterator__alloc_frame(fi); GITERR_CHECK_ALLOC(ff); @@ -937,23 +946,17 @@ static int fs_iterator__expand_dir(fs_iterator *fi) fi->base.start, fi->base.end, &ff->entries); if (error < 0 || ff->entries.length == 0) { - fs_iterator__pop_frame(NULL, ff, true); + fs_iterator__free_frame(ff); return GIT_ENOTFOUND; } - if (++(fi->depth) > FS_MAX_DEPTH) { - giterr_set(GITERR_REPOSITORY, - "Directory nesting is too deep (%d)", fi->depth); - fs_iterator__pop_frame(NULL, ff, true); - return -1; - } - fs_iterator__seek_frame_start(fi, ff); ff->next = fi->stack; fi->stack = ff; + fi->depth++; - if (fi->frame_added && (error = fi->frame_added(fi)) < 0) + if (fi->enter_dir_cb && (error = fi->enter_dir_cb(fi)) < 0) return error; return fs_iterator__update_entry(fi); @@ -1106,8 +1109,8 @@ static int fs_iterator__update_entry(fs_iterator *fi) fi->entry.mode = git_futils_canonical_mode(ps->st.st_mode); /* allow wrapper to check/update the entry (can force skip) */ - if (fi->entry_updated && - fi->entry_updated(fi) == GIT_ENOTFOUND) + if (fi->update_entry_cb && + fi->update_entry_cb(fi) == GIT_ENOTFOUND) return fs_iterator__advance_over(NULL, (git_iterator *)fi); /* if this is a tree and trees aren't included, then skip */ @@ -1126,7 +1129,6 @@ static int fs_iterator__initialize( git__free(fi); return -1; } - fi->root_len = fi->path.size; if ((error = fs_iterator__expand_dir(fi)) == GIT_ENOTFOUND) { @@ -1186,7 +1188,7 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path) return (len == 4 || path->ptr[len - 5] == '/'); } -static int workdir_iterator__frame_added(fs_iterator *fi) +static int workdir_iterator__enter_dir(fs_iterator *fi) { /* only push new ignores if this is not top level directory */ if (fi->stack->next != NULL) { @@ -1199,14 +1201,14 @@ static int workdir_iterator__frame_added(fs_iterator *fi) return 0; } -static int workdir_iterator__frame_removed(fs_iterator *fi) +static int workdir_iterator__leave_dir(fs_iterator *fi) { workdir_iterator *wi = (workdir_iterator *)fi; git_ignore__pop_dir(&wi->ignores); return 0; } -static int workdir_iterator__entry_updated(fs_iterator *fi) +static int workdir_iterator__update_entry(fs_iterator *fi) { int error = 0; workdir_iterator *wi = (workdir_iterator *)fi; @@ -1243,7 +1245,7 @@ static void workdir_iterator__free(git_iterator *self) } int git_iterator_for_workdir( - git_iterator **iter, + git_iterator **out, git_repository *repo, git_iterator_flag_t flags, const char *start, @@ -1253,7 +1255,7 @@ int git_iterator_for_workdir( workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); GITERR_CHECK_ALLOC(wi); - assert(iter && repo); + assert(out && repo); if ((error = git_repository__ensure_not_bare( repo, "scan working directory")) < 0) @@ -1262,11 +1264,11 @@ int git_iterator_for_workdir( /* initialize as an fs iterator then do overrides */ ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); - wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; - wi->fi.cb.free = workdir_iterator__free; - wi->fi.frame_added = workdir_iterator__frame_added; - wi->fi.frame_removed = workdir_iterator__frame_removed; - wi->fi.entry_updated = workdir_iterator__entry_updated; + wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; + wi->fi.cb.free = workdir_iterator__free; + wi->fi.enter_dir_cb = workdir_iterator__enter_dir; + wi->fi.leave_dir_cb = workdir_iterator__leave_dir; + wi->fi.update_entry_cb = workdir_iterator__update_entry; if ((error = iterator__update_ignore_case((git_iterator *)wi, flags)) < 0 || (error = git_ignore__for_path(repo, "", &wi->ignores)) < 0) @@ -1275,8 +1277,7 @@ int git_iterator_for_workdir( return error; } - return fs_iterator__initialize( - iter, (fs_iterator *)wi, git_repository_workdir(repo)); + return fs_iterator__initialize(out, &wi->fi, git_repository_workdir(repo)); } From 627d590819efa7f43b605ce1a22278c0c6b42516 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:14:22 -0700 Subject: [PATCH 016/134] More filesystem iterator tests Refactors the helper function that builds a directory hierarchy and then made use of it to try more variations on filesystem iterator tests. --- tests-clar/repo/iterator.c | 150 +++++++++++++++++++++++++++---------- 1 file changed, 111 insertions(+), 39 deletions(-) diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index ef9bfc33d..2e53c48d7 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -755,47 +755,52 @@ void test_repo_iterator__workdir_icase(void) git_iterator_free(i); } -void test_repo_iterator__workdir_depth(void) +static void build_workdir_tree(const char *root, int dirs, int subs) { int i, j; + char buf[64], sub[64]; + + for (i = 0; i < dirs; ++i) { + if (i % 2 == 0) { + p_snprintf(buf, sizeof(buf), "%s/dir%02d", root, i); + cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + + p_snprintf(buf, sizeof(buf), "%s/dir%02d/file", root, i); + cl_git_mkfile(buf, buf); + buf[strlen(buf) - 5] = '\0'; + } else { + p_snprintf(buf, sizeof(buf), "%s/DIR%02d", root, i); + cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); + } + + for (j = 0; j < subs; ++j) { + switch (j % 4) { + case 0: p_snprintf(sub, sizeof(sub), "%s/sub%02d", buf, j); break; + case 1: p_snprintf(sub, sizeof(sub), "%s/sUB%02d", buf, j); break; + case 2: p_snprintf(sub, sizeof(sub), "%s/Sub%02d", buf, j); break; + case 3: p_snprintf(sub, sizeof(sub), "%s/SUB%02d", buf, j); break; + } + cl_git_pass(git_futils_mkdir(sub, NULL, 0775, GIT_MKDIR_PATH)); + + if (j % 2 == 0) { + size_t sublen = strlen(sub); + memcpy(&sub[sublen], "/file", sizeof("/file")); + cl_git_mkfile(sub, sub); + sub[sublen] = '\0'; + } + } + } +} + +void test_repo_iterator__workdir_depth(void) +{ git_iterator *iter; - char buf[64]; g_repo = cl_git_sandbox_init("icase"); - for (i = 0; i < 10; ++i) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d", i); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); - - if (i % 2 == 0) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/file", i); - cl_git_mkfile(buf, buf); - } - - for (j = 0; j < 10; ++j) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/sub%02d", i, j); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); - - if (j % 2 == 0) { - p_snprintf( - buf, sizeof(buf), "icase/dir%02d/sub%02d/file", i, j); - cl_git_mkfile(buf, buf); - } - } - } - - for (i = 1; i < 3; ++i) { - for (j = 0; j < 50; ++j) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/sub01/moar%02d", i, j); - cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH)); - - if (j % 2 == 0) { - p_snprintf(buf, sizeof(buf), - "icase/dir%02d/sub01/moar%02d/file", i, j); - cl_git_mkfile(buf, buf); - } - } - } + build_workdir_tree("icase", 10, 10); + build_workdir_tree("icase/dir01/Sub01", 50, 0); + build_workdir_tree("icase/DIR02/Sub01", 50, 0); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL)); @@ -812,8 +817,42 @@ void test_repo_iterator__workdir_depth(void) void test_repo_iterator__fs(void) { git_iterator *i; - static const char *expect_subdir[] = { + static const char *expect_base[] = { + "DIR01/Sub02/file", + "DIR01/sub00/file", "current_file", + "dir00/Sub02/file", + "dir00/file", + "dir00/sub00/file", + "modified_file", + "new_file", + NULL, + }; + static const char *expect_trees[] = { + "DIR01/", + "DIR01/SUB03/", + "DIR01/Sub02/", + "DIR01/Sub02/file", + "DIR01/sUB01/", + "DIR01/sub00/", + "DIR01/sub00/file", + "current_file", + "dir00/", + "dir00/SUB03/", + "dir00/Sub02/", + "dir00/Sub02/file", + "dir00/file", + "dir00/sUB01/", + "dir00/sub00/", + "dir00/sub00/file", + "modified_file", + "new_file", + NULL, + }; + static const char *expect_noauto[] = { + "DIR01/", + "current_file", + "dir00/", "modified_file", "new_file", NULL, @@ -821,16 +860,49 @@ void test_repo_iterator__fs(void) g_repo = cl_git_sandbox_init("status"); + build_workdir_tree("status/subdir", 2, 4); + cl_git_pass(git_iterator_for_filesystem( &i, "status/subdir", 0, NULL, NULL)); - expect_iterator_items(i, 3, expect_subdir, 3, expect_subdir); + expect_iterator_items(i, 8, expect_base, 8, expect_base); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); + expect_iterator_items(i, 18, expect_trees, 18, expect_trees); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); + expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); + git_iterator_free(i); + + git__tsort((void **)expect_base, 8, (git__tsort_cmp)git__strcasecmp); + git__tsort((void **)expect_trees, 18, (git__tsort_cmp)git__strcasecmp); + git__tsort((void **)expect_noauto, 5, (git__tsort_cmp)git__strcasecmp); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE, NULL, NULL)); + expect_iterator_items(i, 8, expect_base, 8, expect_base); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | + GIT_ITERATOR_INCLUDE_TREES, NULL, NULL)); + expect_iterator_items(i, 18, expect_trees, 18, expect_trees); + git_iterator_free(i); + + cl_git_pass(git_iterator_for_filesystem( + &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE | + GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); + expect_iterator_items(i, 5, expect_noauto, 18, expect_trees); git_iterator_free(i); } void test_repo_iterator__fs2(void) { git_iterator *i; - static const char *expect_subdir[] = { + static const char *expect_base[] = { "heads/br2", "heads/dir", "heads/master", @@ -849,6 +921,6 @@ void test_repo_iterator__fs2(void) cl_git_pass(git_iterator_for_filesystem( &i, "testrepo/.git/refs", 0, NULL, NULL)); - expect_iterator_items(i, 11, expect_subdir, 11, expect_subdir); + expect_iterator_items(i, 11, expect_base, 11, expect_base); git_iterator_free(i); } From 2aee1aa4165583cf77815df404d87818d53b72dc Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:35:13 -0700 Subject: [PATCH 017/134] Fix uninitialized var warnings --- src/index.c | 2 +- src/revparse.c | 2 +- tests-clar/repo/iterator.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.c b/src/index.c index 6290ec4e8..2afd28158 100644 --- a/src/index.c +++ b/src/index.c @@ -1345,7 +1345,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer static int parse_index(git_index *index, const char *buffer, size_t buffer_size) { unsigned int i; - struct index_header header; + struct index_header header = { 0 }; git_oid checksum_calculated, checksum_expected; #define seek_forward(_increase) { \ diff --git a/src/revparse.c b/src/revparse.c index 74635ed04..8a22a04f3 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -16,7 +16,7 @@ static int disambiguate_refname(git_reference **out, git_repository *repo, const char *refname) { - int error, i; + int error = 0, i; bool fallbackmode = true; git_reference *ref; git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT; diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 2e53c48d7..9118dd17e 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -422,7 +422,7 @@ static void build_test_tree( git_treebuilder *builder; const char *scan = fmt, *next; char type, delimiter; - git_filemode_t mode; + git_filemode_t mode = GIT_FILEMODE_BLOB; git_buf name = GIT_BUF_INIT; va_list arglist; From 9ea29c8f1dd155cf62fc6c87edaeb9984da72f72 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:41:16 -0700 Subject: [PATCH 018/134] Fix fs iterator test on case sensitive fs --- tests-clar/repo/iterator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index 9118dd17e..ab460735c 100644 --- a/tests-clar/repo/iterator.c +++ b/tests-clar/repo/iterator.c @@ -799,8 +799,8 @@ void test_repo_iterator__workdir_depth(void) g_repo = cl_git_sandbox_init("icase"); build_workdir_tree("icase", 10, 10); - build_workdir_tree("icase/dir01/Sub01", 50, 0); - build_workdir_tree("icase/DIR02/Sub01", 50, 0); + build_workdir_tree("icase/DIR01/sUB01", 50, 0); + build_workdir_tree("icase/dir02/sUB01", 50, 0); /* auto expand with no tree entries */ cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL)); From 38fd8121a2a87cc0da405b50f4439ca6578dcff5 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 14:48:20 -0700 Subject: [PATCH 019/134] Fix win64 warnings --- src/branch.c | 2 +- tests-clar/refdb/inmemory.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/branch.c b/src/branch.c index e7088790e..956286b74 100644 --- a/src/branch.c +++ b/src/branch.c @@ -377,7 +377,7 @@ int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo if (buffer) git_buf_copy_cstr(buffer, buffer_len, &buf); - ret = git_buf_len(&buf) + 1; + ret = (int)git_buf_len(&buf) + 1; git_buf_free(&buf); return ret; diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index 2cccd8eb2..ca721e977 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -160,7 +160,7 @@ void test_refdb_inmemory__foreach(void) cl_git_pass(git_reference_create(&write3, repo, GIT_REFS_HEADS_DIR "test3", &oid3, 0)); cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, foreach_test, &i)); - cl_assert_equal_i(i, 3); + cl_assert_equal_i(3, (int)i); git_reference_free(write1); git_reference_free(write2); @@ -207,7 +207,7 @@ void test_refdb_inmemory__delete(void) git_reference_free(write3); cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, delete_test, &i)); - cl_assert_equal_i(i, 1); + cl_assert_equal_i(1, (int)i); git_reference_free(write2); } From 1af80a676613882b3e04e82874c6e7c8c14b5f49 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 18 Apr 2013 16:13:52 -0700 Subject: [PATCH 020/134] Fix workdir iterator leak When attempting to create a workdir iterator for a bare repo, don't leak the iterator structure. --- src/iterator.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index a72f97eca..ff08c1ce0 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -1252,16 +1252,14 @@ int git_iterator_for_workdir( const char *end) { int error; - workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); - GITERR_CHECK_ALLOC(wi); + workdir_iterator *wi; - assert(out && repo); - - if ((error = git_repository__ensure_not_bare( - repo, "scan working directory")) < 0) - return error; + if (git_repository__ensure_not_bare(repo, "scan working directory") < 0) + return GIT_EBAREREPO; /* initialize as an fs iterator then do overrides */ + wi = git__calloc(1, sizeof(workdir_iterator)); + GITERR_CHECK_ALLOC(wi); ITERATOR_BASE_INIT((&wi->fi), fs, FS, repo); wi->fi.base.type = GIT_ITERATOR_TYPE_WORKDIR; From 743048f1e9d9c853ffac80093a4814a1ac7d9c62 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Fri, 19 Apr 2013 10:29:50 -0700 Subject: [PATCH 021/134] Fix some minor issues --- README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fdddc5ca1..a2a18765a 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ release its source code. * Archives: * Website: * API documentation: +* IRC: #libgit2 on irc.freenode.net. What It Can Do ================================== @@ -155,15 +156,7 @@ we can add it to the list. How Can I Contribute? ================================== -Fork libgit2/libgit2 on GitHub, add your improvement, push it to a branch -in your fork named for the topic, send a pull request. If you change the -API or make other large changes, make a note of it in docs/rel-notes/ in a -file named after the next release. - -You can also file bugs or feature requests under the libgit2 project on -GitHub, or join us on the mailing list by sending an email to: - -libgit2@librelist.com +Check the [contribution guidelines](CONTRIBUTING.md). License From a29c6b5f47676d864af1e78c7927bc3cb2b329d7 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 19 Apr 2013 23:51:18 +0200 Subject: [PATCH 022/134] odb: Do not allow duplicate on-disk backends --- src/odb.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/odb.c b/src/odb.c index c98df247c..1c7969fcb 100644 --- a/src/odb.c +++ b/src/odb.c @@ -29,7 +29,8 @@ typedef struct { git_odb_backend *backend; int priority; - int is_alternate; + bool is_alternate; + ino_t disk_inode; } backend_internal; size_t git_odb__cache_size = GIT_DEFAULT_CACHE_SIZE; @@ -365,7 +366,9 @@ int git_odb_new(git_odb **out) return 0; } -static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int priority, int is_alternate) +static int add_backend_internal( + git_odb *odb, git_odb_backend *backend, + int priority, bool is_alternate, ino_t disk_inode) { backend_internal *internal; @@ -382,6 +385,7 @@ static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int prio internal->backend = backend; internal->priority = priority; internal->is_alternate = is_alternate; + internal->disk_inode = disk_inode; if (git_vector_insert(&odb->backends, internal) < 0) { git__free(internal); @@ -395,26 +399,41 @@ static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int prio int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority) { - return add_backend_internal(odb, backend, priority, 0); + return add_backend_internal(odb, backend, priority, false, 0); } int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority) { - return add_backend_internal(odb, backend, priority, 1); + return add_backend_internal(odb, backend, priority, true, 0); } -static int add_default_backends(git_odb *db, const char *objects_dir, int as_alternates, int alternate_depth) +static int add_default_backends( + git_odb *db, const char *objects_dir, + bool as_alternates, int alternate_depth) { + size_t i; + struct stat st; git_odb_backend *loose, *packed; + if (p_stat(objects_dir, &st) < 0) { + giterr_set(GITERR_ODB, "Failed to load object database in '%s'", objects_dir); + return -1; + } + + for (i = 0; i < db->backends.length; ++i) { + backend_internal *backend = git_vector_get(&db->backends, i); + if (backend->disk_inode == st.st_ino) + return 0; + } + /* add the loose object backend */ if (git_odb_backend_loose(&loose, objects_dir, -1, 0) < 0 || - add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates) < 0) + add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, st.st_ino) < 0) return -1; /* add the packed file backend */ if (git_odb_backend_pack(&packed, objects_dir) < 0 || - add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates) < 0) + add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, st.st_ino) < 0) return -1; return load_alternates(db, objects_dir, alternate_depth); @@ -464,7 +483,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_ alternate = git_buf_cstr(&alternates_path); } - if ((result = add_default_backends(odb, alternate, 1, alternate_depth + 1)) < 0) + if ((result = add_default_backends(odb, alternate, true, alternate_depth + 1)) < 0) break; } @@ -476,7 +495,7 @@ static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_ int git_odb_add_disk_alternate(git_odb *odb, const char *path) { - return add_default_backends(odb, path, 1, 0); + return add_default_backends(odb, path, true, 0); } int git_odb_open(git_odb **out, const char *objects_dir) From 4a38143c93dc705bc40109e3f79d7fac722d44d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 19 Apr 2013 23:55:37 +0200 Subject: [PATCH 023/134] remote: specify what values direction can mean in git_remote_connect() This fixes #1487 --- include/git2/remote.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 6f36a3999..9494a8b01 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -184,7 +184,8 @@ GIT_EXTERN(const git_refspec *) git_remote_pushspec(const git_remote *remote); * starts up a specific binary which can only do the one or the other. * * @param remote the remote to connect to - * @param direction whether you want to receive or send data + * @param direction GIT_DIRECTION_FETCH if you want to fetch or + * GIT_DIRECTION_PUSH if you want to push * @return 0 or an error code */ GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction); From 4e4eab52f7c5062ea21ea278a38e48700e753883 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 19 Apr 2013 18:19:53 -0500 Subject: [PATCH 024/134] alloc doesn't take a refdb; git_refdb_free nicely in the tests --- include/git2/refdb.h | 2 -- include/git2/refdb_backend.h | 3 +-- src/refdb.c | 15 +++++++++++++-- src/refdb_fs.c | 11 ++++------- src/refs.c | 25 ++++++++++++------------- tests-clar/refdb/inmemory.c | 5 +++-- tests-clar/refdb/testdb.c | 11 ++--------- tests-clar/refs/delete.c | 1 + tests-clar/refs/pack.c | 1 + tests-clar/refs/rename.c | 1 + 10 files changed, 38 insertions(+), 37 deletions(-) diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 76b8fda0d..0e3ec5eaf 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -32,13 +32,11 @@ GIT_BEGIN_DECL * @return the created git_reference or NULL on error */ GIT_EXTERN(git_reference *) git_reference__alloc( - git_refdb *refdb, const char *name, const git_oid *oid, const git_oid *peel); GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( - git_refdb *refdb, const char *name, const char *target); diff --git a/include/git2/refdb_backend.h b/include/git2/refdb_backend.h index bf33817d6..20eb6a9dd 100644 --- a/include/git2/refdb_backend.h +++ b/include/git2/refdb_backend.h @@ -101,8 +101,7 @@ struct git_refdb_backend { */ GIT_EXTERN(int) git_refdb_backend_fs( struct git_refdb_backend **backend_out, - git_repository *repo, - git_refdb *refdb); + git_repository *repo); GIT_END_DECL diff --git a/src/refdb.c b/src/refdb.c index d9b73c6e7..2a0fd702c 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -45,7 +45,7 @@ int git_refdb_open(git_refdb **out, git_repository *repo) return -1; /* Add the default (filesystem) backend */ - if (git_refdb_backend_fs(&dir, repo, db) < 0) { + if (git_refdb_backend_fs(&dir, repo) < 0) { git_refdb_free(db); return -1; } @@ -111,9 +111,20 @@ int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name) int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name) { + git_reference *ref; + int error; + assert(db && db->backend && ref_name); - return db->backend->lookup(out, db->backend, ref_name); + *out = NULL; + + if ((error = db->backend->lookup(&ref, db->backend, ref_name)) == 0) + { + ref->db = db; + *out = ref; + } + + return error; } int git_refdb_foreach( diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 784749fd3..56b2b6a99 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -42,7 +42,6 @@ typedef struct refdb_fs_backend { git_repository *repo; const char *path; - git_refdb *refdb; git_refcache refcache; } refdb_fs_backend; @@ -430,12 +429,12 @@ static int loose_lookup( goto done; } - *out = git_reference__alloc_symbolic(backend->refdb, ref_name, target); + *out = git_reference__alloc_symbolic(ref_name, target); } else { if ((error = loose_parse_oid(&oid, &ref_file)) < 0) goto done; - *out = git_reference__alloc(backend->refdb, ref_name, &oid, NULL); + *out = git_reference__alloc(ref_name, &oid, NULL); } if (*out == NULL) @@ -484,7 +483,7 @@ static int packed_lookup( if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0) return error; - if ((*out = git_reference__alloc(backend->refdb, ref_name, + if ((*out = git_reference__alloc(ref_name, &entry->oid, &entry->peel)) == NULL) return -1; @@ -999,8 +998,7 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend) int git_refdb_backend_fs( git_refdb_backend **backend_out, - git_repository *repository, - git_refdb *refdb) + git_repository *repository) { refdb_fs_backend *backend; @@ -1009,7 +1007,6 @@ int git_refdb_backend_fs( backend->repo = repository; backend->path = repository->path_repository; - backend->refdb = refdb; backend->parent.exists = &refdb_fs_backend__exists; backend->parent.lookup = &refdb_fs_backend__lookup; diff --git a/src/refs.c b/src/refs.c index 29d1c4fa9..5b5812aae 100644 --- a/src/refs.c +++ b/src/refs.c @@ -31,7 +31,7 @@ enum { GIT_PACKREF_WAS_LOOSE = 2 }; -static git_reference *alloc_ref(git_refdb *refdb, const char *name) +static git_reference *alloc_ref(const char *name) { git_reference *ref; size_t namelen = strlen(name); @@ -39,22 +39,20 @@ static git_reference *alloc_ref(git_refdb *refdb, const char *name) if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL) return NULL; - ref->db = refdb; memcpy(ref->name, name, namelen + 1); return ref; } git_reference *git_reference__alloc_symbolic( - git_refdb *refdb, const char *name, const char *target) { git_reference *ref; - assert(refdb && name && target); + assert(name && target); - ref = alloc_ref(refdb, name); + ref = alloc_ref(name); if (!ref) return NULL; @@ -69,16 +67,15 @@ git_reference *git_reference__alloc_symbolic( } git_reference *git_reference__alloc( - git_refdb *refdb, const char *name, const git_oid *oid, const git_oid *peel) { git_reference *ref; - assert(refdb && name && oid); + assert(name && oid); - ref = alloc_ref(refdb, name); + ref = alloc_ref(name); if (!ref) return NULL; @@ -368,12 +365,13 @@ static int reference__create( if (oid != NULL) { assert(symbolic == NULL); - ref = git_reference__alloc(refdb, name, oid, NULL); + ref = git_reference__alloc(name, oid, NULL); } else { - ref = git_reference__alloc_symbolic(refdb, name, symbolic); + ref = git_reference__alloc_symbolic(name, symbolic); } GITERR_CHECK_ALLOC(ref); + ref->db = refdb; if ((error = git_refdb_write(refdb, ref)) < 0) { git_reference_free(ref); @@ -490,10 +488,9 @@ int git_reference_rename( * Create the new reference. */ if (ref->type == GIT_REF_OID) { - result = git_reference__alloc(ref->db, new_name, - &ref->target.oid, &ref->peel); + result = git_reference__alloc(new_name, &ref->target.oid, &ref->peel); } else if (ref->type == GIT_REF_SYMBOLIC) { - result = git_reference__alloc_symbolic(ref->db, new_name, ref->target.symbolic); + result = git_reference__alloc_symbolic(new_name, ref->target.symbolic); } else { assert(0); } @@ -501,6 +498,8 @@ int git_reference_rename( if (result == NULL) return -1; + result->db = ref->db; + /* Check if we have to update HEAD. */ if ((error = git_branch_is_head(ref)) < 0) goto on_error; diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index ca721e977..ea76172cf 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -6,7 +6,6 @@ #define TEST_REPO_PATH "testrepo" static git_repository *repo; -static git_refdb *refdb; static git_refdb_backend *refdb_backend; int unlink_ref(void *payload, git_buf *file) @@ -52,6 +51,8 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi void test_refdb_inmemory__initialize(void) { + git_refdb *refdb; + git_buf repo_refs_dir = GIT_BUF_INIT; repo = cl_git_sandbox_init(TEST_REPO_PATH); @@ -60,10 +61,10 @@ void test_refdb_inmemory__initialize(void) cl_git_pass(refdb_backend_test(&refdb_backend, repo)); cl_git_pass(git_refdb_set_backend(refdb, refdb_backend)); - ref_file_foreach(repo, unlink_ref); git_buf_free(&repo_refs_dir); + git_refdb_free(refdb); } void test_refdb_inmemory__cleanup(void) diff --git a/tests-clar/refdb/testdb.c b/tests-clar/refdb/testdb.c index e60f6790e..4bca39878 100644 --- a/tests-clar/refdb/testdb.c +++ b/tests-clar/refdb/testdb.c @@ -10,7 +10,6 @@ typedef struct refdb_test_backend { git_refdb_backend parent; git_repository *repo; - git_refdb *refdb; git_vector refs; } refdb_test_backend; @@ -100,10 +99,10 @@ static int refdb_test_backend__lookup( if (strcmp(entry->name, ref_name) == 0) { if (entry->type == GIT_REF_OID) { - *out = git_reference__alloc(backend->refdb, ref_name, + *out = git_reference__alloc(ref_name, &entry->target.oid, NULL); } else if (entry->type == GIT_REF_SYMBOLIC) { - *out = git_reference__alloc_symbolic(backend->refdb, ref_name, + *out = git_reference__alloc_symbolic(ref_name, entry->target.symbolic); } @@ -195,11 +194,6 @@ int refdb_backend_test( git_repository *repo) { refdb_test_backend *backend; - git_refdb *refdb; - int error = 0; - - if ((error = git_repository_refdb(&refdb, repo)) < 0) - return error; backend = git__calloc(1, sizeof(refdb_test_backend)); GITERR_CHECK_ALLOC(backend); @@ -207,7 +201,6 @@ int refdb_backend_test( git_vector_init(&backend->refs, 0, ref_name_cmp); backend->repo = repo; - backend->refdb = refdb; backend->parent.exists = &refdb_test_backend__exists; backend->parent.lookup = &refdb_test_backend__lookup; diff --git a/tests-clar/refs/delete.c b/tests-clar/refs/delete.c index ac517d869..053f41229 100644 --- a/tests-clar/refs/delete.c +++ b/tests-clar/refs/delete.c @@ -88,4 +88,5 @@ void test_refs_delete__packed_only(void) /* This should pass */ cl_git_pass(git_reference_delete(ref)); git_reference_free(ref); + git_refdb_free(refdb); } diff --git a/tests-clar/refs/pack.c b/tests-clar/refs/pack.c index 973abae30..412c4c5fd 100644 --- a/tests-clar/refs/pack.c +++ b/tests-clar/refs/pack.c @@ -25,6 +25,7 @@ static void packall(void) cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); + git_refdb_free(refdb); } void test_refs_pack__empty(void) diff --git a/tests-clar/refs/rename.c b/tests-clar/refs/rename.c index e39abeb05..5ab84c48e 100644 --- a/tests-clar/refs/rename.c +++ b/tests-clar/refs/rename.c @@ -284,6 +284,7 @@ void test_refs_rename__overwrite(void) git_reference_free(ref_one); git_reference_free(ref_one_new); git_reference_free(ref_two); + git_refdb_free(refdb); } From 8f24e65ff6f7573bc6778f5bbea7119fc9b7b626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 20 Apr 2013 16:20:21 +0200 Subject: [PATCH 025/134] Plug a couple of leaks --- tests-clar/stash/drop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests-clar/stash/drop.c b/tests-clar/stash/drop.c index 12f922630..60b3c72e0 100644 --- a/tests-clar/stash/drop.c +++ b/tests-clar/stash/drop.c @@ -146,6 +146,8 @@ void retrieve_top_stash_id(git_oid *out) cl_git_pass(git_reference_name_to_id(out, repo, GIT_REFS_STASH_FILE)); cl_assert_equal_i(true, git_oid_cmp(out, git_object_id(top_stash)) == 0); + + git_object_free(top_stash); } void test_stash_drop__dropping_the_top_stash_updates_the_stash_reference(void) @@ -165,4 +167,6 @@ void test_stash_drop__dropping_the_top_stash_updates_the_stash_reference(void) retrieve_top_stash_id(&oid); cl_git_pass(git_oid_cmp(&oid, git_object_id(next_top_stash))); + + git_object_free(next_top_stash); } From e5a27f039ee3ae1291fd5084707c3f9c168f10ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 20 Apr 2013 15:25:39 +0200 Subject: [PATCH 026/134] config: allow setting multivars when none exist yet Adding a multivar when there are no variables with that name set should set the variable instead of failing. --- src/config_file.c | 4 +++- tests-clar/config/multivar.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/config_file.c b/src/config_file.c index 8b51ab21b..01559221e 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -481,8 +481,10 @@ static int config_set_multivar( pos = git_strmap_lookup_index(b->values, key); if (!git_strmap_valid_index(b->values, pos)) { + /* If we don't have it, behave like a normal set */ + result = config_set(cfg, name, value); git__free(key); - return GIT_ENOTFOUND; + return result; } var = git_strmap_value_at(b->values, pos); diff --git a/tests-clar/config/multivar.c b/tests-clar/config/multivar.c index 26537e20a..0bda6bcec 100644 --- a/tests-clar/config/multivar.c +++ b/tests-clar/config/multivar.c @@ -97,6 +97,22 @@ void test_config_multivar__add(void) git_config_free(cfg); } +void test_config_multivar__add_new(void) +{ + const char *var = "a.brand.new"; + git_config *cfg; + int n; + + cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); + + cl_git_pass(git_config_set_multivar(cfg, var, "", "variable")); + n = 0; + cl_git_pass(git_config_get_multivar(cfg, var, NULL, cb, &n)); + cl_assert(n == 1); + + git_config_free(cfg); +} + void test_config_multivar__replace(void) { git_config *cfg; From 4330ab26b53c0e1bf8cbb5e65704f65e3d116eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 20 Apr 2013 04:43:28 +0200 Subject: [PATCH 027/134] remote: handle multiple refspecs A remote can have a multitude of refspecs. Up to now our git_remote's have supported a single one for each fetch and push out of simplicity to get something working. Let the remotes and internal code know about multiple remotes and get the tests passing with them. Instead of setting a refspec, the external users can clear all and add refspecs. This should be enough for most uses, though we're still missing a querying function. --- include/git2/remote.h | 29 ++- src/branch.c | 22 +- src/clone.c | 12 +- src/fetch.c | 3 +- src/push.c | 5 +- src/refspec.c | 1 + src/refspec.h | 2 +- src/remote.c | 387 +++++++++++++++++----------- src/remote.h | 7 +- tests-clar/clone/nonetwork.c | 5 +- tests-clar/network/remote/remotes.c | 56 +++- tests-clar/online/fetchhead.c | 6 +- tests-clar/online/push.c | 5 +- tests-clar/refs/branches/remote.c | 3 +- 14 files changed, 337 insertions(+), 206 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 9494a8b01..7a161796f 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -142,30 +142,22 @@ GIT_EXTERN(int) git_remote_set_url(git_remote *remote, const char* url); GIT_EXTERN(int) git_remote_set_pushurl(git_remote *remote, const char* url); /** - * Set the remote's fetch refspec + * Add a fetch refspec to the remote * * @param remote the remote - * @apram spec the new fetch refspec + * @apram refspec the new fetch refspec * @return 0 or an error value */ -GIT_EXTERN(int) git_remote_set_fetchspec(git_remote *remote, const char *spec); +GIT_EXTERN(int) git_remote_add_fetchspec(git_remote *remote, const char *refspec); /** - * Get the fetch refspec + * Add a push refspec to the remote * * @param remote the remote - * @return a pointer to the fetch refspec or NULL if it doesn't exist - */ -GIT_EXTERN(const git_refspec *) git_remote_fetchspec(const git_remote *remote); - -/** - * Set the remote's push refspec - * - * @param remote the remote - * @param spec the new push refspec + * @param refspec the new push refspec * @return 0 or an error value */ -GIT_EXTERN(int) git_remote_set_pushspec(git_remote *remote, const char *spec); +GIT_EXTERN(int) git_remote_add_pushspec(git_remote *remote, const char *refspec); /** * Get the push refspec @@ -176,6 +168,15 @@ GIT_EXTERN(int) git_remote_set_pushspec(git_remote *remote, const char *spec); GIT_EXTERN(const git_refspec *) git_remote_pushspec(const git_remote *remote); +/** + * Clear the refspecs + * + * Remove all configured fetch and push refspecs from the remote. + * + * @param remote the remote + */ +GIT_EXTERN(void) git_remote_clear_refspecs(git_remote *remote); + /** * Open a connection to a remote * diff --git a/src/branch.c b/src/branch.c index 956286b74..88f052529 100644 --- a/src/branch.c +++ b/src/branch.c @@ -11,6 +11,7 @@ #include "config.h" #include "refspec.h" #include "refs.h" +#include "remote.h" #include "git2/branch.h" @@ -283,12 +284,10 @@ int git_branch_upstream__name( if ((error = git_remote_load(&remote, repo, remote_name)) < 0) goto cleanup; - refspec = git_remote_fetchspec(remote); - if (refspec == NULL - || refspec->src == NULL - || refspec->dst == NULL) { - error = GIT_ENOTFOUND; - goto cleanup; + refspec = git_remote__matching_refspec(remote, merge_name); + if (!refspec) { + error = GIT_ENOTFOUND; + goto cleanup; } if (git_refspec_transform_r(&buf, refspec, merge_name) < 0) @@ -333,11 +332,8 @@ static int remote_name(git_buf *buf, git_repository *repo, const char *canonical if ((error = git_remote_load(&remote, repo, remote_list.strings[i])) < 0) continue; - fetchspec = git_remote_fetchspec(remote); - - /* Defensivly check that we have a fetchspec */ - if (fetchspec && - git_refspec_dst_matches(fetchspec, canonical_branch_name)) { + fetchspec = git_remote__matching_dst_refspec(remote, canonical_branch_name); + if (fetchspec) { /* If we have not already set out yet, then set * it to the matching remote name. Otherwise * multiple remotes match this reference, and it @@ -522,9 +518,9 @@ int git_branch_set_upstream(git_reference *branch, const char *upstream_name) if (git_remote_load(&remote, repo, git_buf_cstr(&value)) < 0) goto on_error; - fetchspec = git_remote_fetchspec(remote); + fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream)); git_buf_clear(&value); - if (git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0) + if (!fetchspec || git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0) goto on_error; git_remote_free(remote); diff --git a/src/clone.c b/src/clone.c index 0bbccd44b..cb4053736 100644 --- a/src/clone.c +++ b/src/clone.c @@ -187,6 +187,7 @@ static int get_head_callback(git_remote_head *head, void *payload) static int update_head_to_remote(git_repository *repo, git_remote *remote) { int retcode = -1; + git_refspec dummy_spec; git_remote_head *remote_head; struct head_info head_info; git_buf remote_master_name = GIT_BUF_INIT; @@ -211,8 +212,13 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote) git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid); git_buf_init(&head_info.branchname, 16); head_info.repo = repo; - head_info.refspec = git_remote_fetchspec(remote); + head_info.refspec = git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE); head_info.found = 0; + + if (head_info.refspec == NULL) { + memset(&dummy_spec, 0, sizeof(git_refspec)); + head_info.refspec = &dummy_spec; + } /* Determine the remote tracking reference name from the local master */ if (git_refspec_transform_r( @@ -318,11 +324,11 @@ static int create_and_configure_origin( goto on_error; if (options->fetch_spec && - (error = git_remote_set_fetchspec(origin, options->fetch_spec)) < 0) + (error = git_remote_add_fetchspec(origin, options->fetch_spec)) < 0) goto on_error; if (options->push_spec && - (error = git_remote_set_pushspec(origin, options->push_spec)) < 0) + (error = git_remote_add_pushspec(origin, options->push_spec)) < 0) goto on_error; if (options->pushurl && diff --git a/src/fetch.c b/src/fetch.c index b60a95232..8ae34bddf 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -34,7 +34,7 @@ static int filter_ref__cb(git_remote_head *head, void *payload) if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) p->found_head = 1; - else if (git_refspec_src_matches(p->spec, head->name)) + else if (git_remote__matching_refspec(p->remote, head->name)) match = 1; else if (p->remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL && git_refspec_src_matches(p->tagspec, head->name)) @@ -68,7 +68,6 @@ static int filter_wants(git_remote *remote) * not interested in any particular branch but just the remote's * HEAD, which will be stored in FETCH_HEAD after the fetch. */ - p.spec = git_remote_fetchspec(remote); p.tagspec = &tagspec; p.found_head = 0; p.remote = remote; diff --git a/src/push.c b/src/push.c index cec4c64af..b6be1a4e1 100644 --- a/src/push.c +++ b/src/push.c @@ -177,9 +177,9 @@ int git_push_add_refspec(git_push *push, const char *refspec) int git_push_update_tips(git_push *push) { - git_refspec *fetch_spec = &push->remote->fetch; git_buf remote_ref_name = GIT_BUF_INIT; size_t i, j; + git_refspec *fetch_spec; push_spec *push_spec; git_reference *remote_ref; push_status *status; @@ -191,7 +191,8 @@ int git_push_update_tips(git_push *push) continue; /* Find the corresponding remote ref */ - if (!git_refspec_src_matches(fetch_spec, status->ref)) + fetch_spec = git_remote__matching_refspec(push->remote, status->ref); + if (!fetch_spec) continue; if ((error = git_refspec_transform_r(&remote_ref_name, fetch_spec, status->ref)) < 0) diff --git a/src/refspec.c b/src/refspec.c index a51b0cfab..0ed02f48b 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -25,6 +25,7 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) assert(refspec && input); memset(refspec, 0x0, sizeof(git_refspec)); + refspec->push = !is_fetch; lhs = input; if (*lhs == '+') { diff --git a/src/refspec.h b/src/refspec.h index a7a4dd834..339d10eb2 100644 --- a/src/refspec.h +++ b/src/refspec.h @@ -11,10 +11,10 @@ #include "buffer.h" struct git_refspec { - struct git_refspec *next; char *src; char *dst; unsigned int force :1, + push : 1, pattern :1, matching :1; }; diff --git a/src/remote.c b/src/remote.c index 56853834b..1c4b22bb9 100644 --- a/src/remote.c +++ b/src/remote.c @@ -19,15 +19,34 @@ #include -static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var, bool is_fetch) +static int add_refspec(git_remote *remote, const char *string, bool is_fetch) { - int error; - const char *val; + char *name_dup; + git_refspec *spec; - if ((error = git_config_get_string(&val, cfg, var)) < 0) - return error; + spec = git__calloc(1, sizeof(git_refspec)); + GITERR_CHECK_ALLOC(spec); - return git_refspec__parse(refspec, val, is_fetch); + name_dup = git__strdup(string); + if (!name_dup) + goto on_error; + + if (git_refspec__parse(spec, string, is_fetch) < 0) + goto on_error; + + spec->push = !is_fetch; + if (git_vector_insert(&remote->refspec_strings, name_dup) < 0) + goto on_error; + + if (git_vector_insert(&remote->refspecs, spec) < 0) + goto on_error; + + return 0; + +on_error: + git__free(spec); + git__free(name_dup); + return -1; } static int download_tags_value(git_remote *remote, git_config *cfg) @@ -99,7 +118,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n } if (fetch != NULL) { - if (git_refspec__parse(&remote->fetch, fetch, true) < 0) + if (add_refspec(remote, fetch, true) < 0) goto on_error; } @@ -186,6 +205,18 @@ int git_remote_create_inmemory(git_remote **out, git_repository *repo, const cha return 0; } +struct refspec_cb_data { + git_remote *remote; + int fetch; +}; + +static int refspec_cb(const git_config_entry *entry, void *payload) +{ + const struct refspec_cb_data *data = (struct refspec_cb_data *)payload; + + return add_refspec(data->remote, entry->value, data->fetch); +} + int git_remote_load(git_remote **out, git_repository *repo, const char *name) { git_remote *remote; @@ -193,6 +224,8 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) const char *val; int error = 0; git_config *config; + struct refspec_cb_data data; + assert(out && repo && name); @@ -211,7 +244,9 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) remote->name = git__strdup(name); GITERR_CHECK_ALLOC(remote->name); - if (git_vector_init(&remote->refs, 32, NULL) < 0) { + if ((git_vector_init(&remote->refs, 32, NULL) < 0) || + (git_vector_init(&remote->refspecs, 2, NULL)) || + (git_vector_init(&remote->refspec_strings, 2, NULL))) { error = -1; goto cleanup; } @@ -262,7 +297,9 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) goto cleanup; } - error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf), true); + data.remote = remote; + data.fetch = true; + error = git_config_get_multivar(config, git_buf_cstr(&buf), NULL, refspec_cb, &data); if (error == GIT_ENOTFOUND) error = 0; @@ -277,7 +314,8 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) goto cleanup; } - error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf), false); + data.fetch = false; + error = git_config_get_multivar(config, git_buf_cstr(&buf), NULL, refspec_cb, &data); if (error == GIT_ENOTFOUND) error = 0; @@ -300,36 +338,46 @@ cleanup: return error; } -static int update_config_refspec( - git_config *config, - const char *remote_name, - const git_refspec *refspec, - int git_direction) +static int update_config_refspec(const git_remote *remote, git_config *config, int direction) { - git_buf name = GIT_BUF_INIT, value = GIT_BUF_INIT; + git_buf name = GIT_BUF_INIT; + int push; + const char *dir; + size_t i; int error = -1; - if (refspec->src == NULL || refspec->dst == NULL) - return 0; + push = direction == GIT_DIRECTION_PUSH; + dir = push ? "push" : "fetch"; - if (git_buf_printf( - &name, - "remote.%s.%s", - remote_name, - git_direction == GIT_DIRECTION_FETCH ? "fetch" : "push") < 0) + if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0) + return -1; + + /* Clear out the existing config */ + do { + error = git_config_delete_entry(config, git_buf_cstr(&name)); + } while (!error); + + if (error != GIT_ENOTFOUND) + return error; + + for (i = 0; i < remote->refspec_strings.length; i++) { + git_refspec *spec = git_vector_get(&remote->refspecs, i); + const char *str = git_vector_get(&remote->refspec_strings, i); + assert(spec && str); + + if (spec->push != push) + continue; + + if ((error = git_config_set_multivar(config, git_buf_cstr(&name), "", str)) < 0) { goto cleanup; + } + } - if (git_refspec__serialize(&value, refspec) < 0) - goto cleanup; - - error = git_config_set_string( - config, - git_buf_cstr(&name), - git_buf_cstr(&value)); + giterr_clear(); + error = 0; cleanup: git_buf_free(&name); - git_buf_free(&value); return error; } @@ -383,19 +431,11 @@ int git_remote_save(const git_remote *remote) } } - if (update_config_refspec( - config, - remote->name, - &remote->fetch, - GIT_DIRECTION_FETCH) < 0) - goto on_error; + if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0) + goto on_error; - if (update_config_refspec( - config, - remote->name, - &remote->push, - GIT_DIRECTION_PUSH) < 0) - goto on_error; + if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0) + goto on_error; /* * What action to take depends on the old and new values. This @@ -482,49 +522,6 @@ int git_remote_set_pushurl(git_remote *remote, const char* url) return 0; } -int git_remote_set_fetchspec(git_remote *remote, const char *spec) -{ - git_refspec refspec; - - assert(remote && spec); - - if (git_refspec__parse(&refspec, spec, true) < 0) - return -1; - - git_refspec__free(&remote->fetch); - memcpy(&remote->fetch, &refspec, sizeof(git_refspec)); - - return 0; -} - -const git_refspec *git_remote_fetchspec(const git_remote *remote) -{ - assert(remote); - return &remote->fetch; -} - -int git_remote_set_pushspec(git_remote *remote, const char *spec) -{ - git_refspec refspec; - - assert(remote && spec); - - if (git_refspec__parse(&refspec, spec, false) < 0) - return -1; - - git_refspec__free(&remote->push); - remote->push.src = refspec.src; - remote->push.dst = refspec.dst; - - return 0; -} - -const git_refspec *git_remote_pushspec(const git_remote *remote) -{ - assert(remote); - return &remote->push; -} - const char* git_remote__urlfordirection(git_remote *remote, int direction) { assert(remote); @@ -687,21 +684,21 @@ static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *upda return 0; } -static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_vector *update_heads, git_reference *ref) +static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vector *update_heads, git_reference *ref) { git_reference *resolved_ref = NULL; git_reference *tracking_ref = NULL; git_buf remote_name = GIT_BUF_INIT; int error = 0; - assert(out && remote && ref); + assert(out && spec && ref); *out = NULL; if ((error = git_reference_resolve(&resolved_ref, ref)) < 0 || (!git_reference_is_branch(resolved_ref)) || (error = git_branch_upstream(&tracking_ref, resolved_ref)) < 0 || - (error = git_refspec_transform_l(&remote_name, &remote->fetch, git_reference_name(tracking_ref))) < 0) { + (error = git_refspec_transform_l(&remote_name, spec, git_reference_name(tracking_ref))) < 0) { /* Not an error if HEAD is orphaned or no tracking branch */ if (error == GIT_ENOTFOUND) error = 0; @@ -718,9 +715,8 @@ cleanup: return error; } -static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_heads) +static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads) { - struct git_refspec *spec; git_reference *head_ref = NULL; git_fetchhead_ref *fetchhead_ref; git_remote_head *remote_ref, *merge_remote_ref; @@ -735,8 +731,6 @@ static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_hea if (update_heads->length == 0) return 0; - spec = &remote->fetch; - if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0) return -1; @@ -746,7 +740,7 @@ static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_hea /* Determine what to merge: if refspec was a wildcard, just use HEAD */ if (git_refspec_is_wildcard(spec)) { if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 || - (error = remote_head_for_ref(&merge_remote_ref, remote, update_heads, head_ref)) < 0) + (error = remote_head_for_ref(&merge_remote_ref, spec, update_heads, head_ref)) < 0) goto cleanup; } else { /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */ @@ -786,7 +780,7 @@ cleanup: return error; } -int git_remote_update_tips(git_remote *remote) +static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vector *refs) { int error = 0, autotag; unsigned int i = 0; @@ -795,14 +789,11 @@ int git_remote_update_tips(git_remote *remote) git_odb *odb; git_remote_head *head; git_reference *ref; - struct git_refspec *spec; git_refspec tagspec; - git_vector refs, update_heads; + git_vector update_heads; assert(remote); - spec = &remote->fetch; - if (git_repository_odb__weakptr(&odb, remote->repo) < 0) return -1; @@ -810,16 +801,12 @@ int git_remote_update_tips(git_remote *remote) return -1; /* Make a copy of the transport's refs */ - if (git_vector_init(&refs, 16, NULL) < 0 || - git_vector_init(&update_heads, 16, NULL) < 0) + if (git_vector_init(&update_heads, 16, NULL) < 0) return -1; - if (git_remote_ls(remote, update_tips_callback, &refs) < 0) - goto on_error; - /* Let's go find HEAD, if it exists. Check only the first ref in the vector. */ - if (refs.length > 0) { - head = (git_remote_head *)refs.contents[0]; + if (refs->length > 0) { + head = git_vector_get(refs, 0); if (!strcmp(head->name, GIT_HEAD_FILE)) { if (git_reference_create(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0) @@ -830,8 +817,8 @@ int git_remote_update_tips(git_remote *remote) } } - for (; i < refs.length; ++i) { - head = (git_remote_head *)refs.contents[i]; + for (; i < refs->length; ++i) { + head = git_vector_get(refs, i); autotag = 0; /* Ignore malformed ref names (which also saves us from tag^{} */ @@ -886,17 +873,15 @@ int git_remote_update_tips(git_remote *remote) } if (git_remote_update_fetchhead(remote) && - (error = git_remote_write_fetchhead(remote, &update_heads)) < 0) + (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0) goto on_error; - git_vector_free(&refs); git_vector_free(&update_heads); git_refspec__free(&tagspec); git_buf_free(&refname); return 0; on_error: - git_vector_free(&refs); git_vector_free(&update_heads); git_refspec__free(&tagspec); git_buf_free(&refname); @@ -904,6 +889,34 @@ on_error: } +int git_remote_update_tips(git_remote *remote) +{ + git_refspec *spec; + git_vector refs; + size_t i; + + if (git_vector_init(&refs, 16, NULL) < 0) + return -1; + + if (git_remote_ls(remote, update_tips_callback, &refs) < 0) + goto on_error; + + git_vector_foreach(&remote->refspecs, i, spec) { + if (spec->push) + continue; + + if (update_tips_for_spec(remote, spec, &refs) < 0) + goto on_error; + } + + git_vector_free(&refs); + return 0; + +on_error: + git_vector_free(&refs); + return -1; +} + int git_remote_connected(git_remote *remote) { assert(remote); @@ -933,6 +946,10 @@ void git_remote_disconnect(git_remote *remote) void git_remote_free(git_remote *remote) { + git_refspec *spec; + char *str; + size_t i; + if (remote == NULL) return; @@ -945,8 +962,16 @@ void git_remote_free(git_remote *remote) git_vector_free(&remote->refs); - git_refspec__free(&remote->fetch); - git_refspec__free(&remote->push); + git_vector_foreach(&remote->refspecs, i, spec) { + git_refspec__free(spec); + git__free(spec); + } + git_vector_free(&remote->refspecs); + + git_vector_foreach(&remote->refspec_strings, i, str) + git__free(str); + git_vector_free(&remote->refspec_strings); + git__free(remote->url); git__free(remote->pushurl); git__free(remote->name); @@ -1237,58 +1262,61 @@ static int rename_fetch_refspecs( void *payload) { git_config *config; - const git_refspec *fetch_refspec; - git_buf dst_prefix = GIT_BUF_INIT, serialized = GIT_BUF_INIT; - const char* pos; + git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT; + const char *refspec; + size_t i; int error = -1; - fetch_refspec = git_remote_fetchspec(remote); - - /* Is there a refspec to deal with? */ - if (fetch_refspec->src == NULL && - fetch_refspec->dst == NULL) - return 0; - - if (git_refspec__serialize(&serialized, fetch_refspec) < 0) + if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0) goto cleanup; - /* Is it an in-memory remote? */ - if (!remote->name) { - error = (callback(git_buf_cstr(&serialized), payload) < 0) ? GIT_EUSER : 0; - goto cleanup; - } + git_vector_foreach(&remote->refspec_strings, i, refspec) { + git_refspec *spec = git_vector_get(&remote->refspecs, i); + assert(spec); - if (git_buf_printf(&dst_prefix, ":refs/remotes/%s/", remote->name) < 0) - goto cleanup; + if (spec->push) + continue; - pos = strstr(git_buf_cstr(&serialized), git_buf_cstr(&dst_prefix)); + /* Every refspec is a problem refspec for an in-memory remote */ + if (!remote->name) { + if (callback(refspec, payload) < 0) { + error = GIT_EUSER; + goto cleanup; + } - /* Does the dst part of the refspec follow the extected standard format? */ - if (!pos) { - error = (callback(git_buf_cstr(&serialized), payload) < 0) ? GIT_EUSER : 0; - goto cleanup; - } + continue; + } - if (git_buf_splice( - &serialized, - pos - git_buf_cstr(&serialized) + strlen(":refs/remotes/"), - strlen(remote->name), new_name, - strlen(new_name)) < 0) + /* Does the dst part of the refspec follow the extected standard format? */ + if (strcmp(git_buf_cstr(&base), refspec)) { + if (callback(refspec, payload) < 0) { + error = GIT_EUSER; + goto cleanup; + } + + continue; + } + + /* If we do want to move it to the new section */ + if (git_buf_printf(&val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0) goto cleanup; - git_refspec__free(&remote->fetch); + if (git_buf_printf(&var, "remote.%s.fetch", new_name) < 0) + goto cleanup; - if (git_refspec__parse(&remote->fetch, git_buf_cstr(&serialized), true) < 0) - goto cleanup; + if (git_repository_config__weakptr(&config, remote->repo) < 0) + goto cleanup; - if (git_repository_config__weakptr(&config, remote->repo) < 0) - goto cleanup; + if (git_config_set_string(config, git_buf_cstr(&var), git_buf_cstr(&val)) < 0) + goto cleanup; + } - error = update_config_refspec(config, new_name, &remote->fetch, GIT_DIRECTION_FETCH); + error = 0; cleanup: - git_buf_free(&serialized); - git_buf_free(&dst_prefix); + git_buf_free(&base); + git_buf_free(&var); + git_buf_free(&val); return error; } @@ -1389,3 +1417,62 @@ int git_remote_is_valid_name( giterr_clear(); return error == 0; } + +git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname) +{ + git_refspec *spec; + size_t i; + + git_vector_foreach(&remote->refspecs, i, spec) { + if (spec->push) + continue; + + if (git_refspec_src_matches(spec, refname)) + return spec; + } + + return NULL; +} + +git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname) +{ + git_refspec *spec; + size_t i; + + git_vector_foreach(&remote->refspecs, i, spec) { + if (spec->push) + continue; + + if (git_refspec_dst_matches(spec, refname)) + return spec; + } + + return NULL; +} + +void git_remote_clear_refspecs(git_remote *remote) +{ + git_refspec *spec; + char *str; + size_t i; + + git_vector_foreach(&remote->refspecs, i, spec) { + git_refspec__free(spec); + } + git_vector_clear(&remote->refspecs); + + git_vector_foreach(&remote->refspec_strings, i, str) { + git__free(str); + } + git_vector_clear(&remote->refspec_strings); +} + +int git_remote_add_fetchspec(git_remote *remote, const char *refspec) +{ + return add_refspec(remote, refspec, true); +} + +int git_remote_add_pushspec(git_remote *remote, const char *refspec) +{ + return add_refspec(remote, refspec, false); +} diff --git a/src/remote.h b/src/remote.h index 4c1a18aa7..b1f33f0e7 100644 --- a/src/remote.h +++ b/src/remote.h @@ -20,8 +20,8 @@ struct git_remote { char *url; char *pushurl; git_vector refs; - struct git_refspec fetch; - struct git_refspec push; + git_vector refspecs; + git_vector refspec_strings; git_cred_acquire_cb cred_acquire_cb; void *cred_acquire_payload; git_transport *transport; @@ -37,4 +37,7 @@ struct git_remote { const char* git_remote__urlfordirection(struct git_remote *remote, int direction); int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url); +git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname); +git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname); + #endif diff --git a/tests-clar/clone/nonetwork.c b/tests-clar/clone/nonetwork.c index c4b482234..02066e07d 100644 --- a/tests-clar/clone/nonetwork.c +++ b/tests-clar/clone/nonetwork.c @@ -2,6 +2,7 @@ #include "git2/clone.h" #include "repository.h" +#include "remote.h" #define LIVE_REPO_URL "git://github.com/libgit2/TestGitRepository" @@ -148,7 +149,7 @@ void test_clone_nonetwork__custom_fetch_spec(void) cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); - actual_fs = git_remote_fetchspec(g_remote); + actual_fs = git_vector_get(&g_remote->refspecs, 0); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); @@ -164,7 +165,7 @@ void test_clone_nonetwork__custom_push_spec(void) cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); - actual_fs = git_remote_pushspec(g_remote); + actual_fs = git_vector_get(&g_remote->refspecs, g_remote->refspecs.length - 1); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); } diff --git a/tests-clar/network/remote/remotes.c b/tests-clar/network/remote/remotes.c index a5ff7415f..92c9d8ac1 100644 --- a/tests-clar/network/remote/remotes.c +++ b/tests-clar/network/remote/remotes.c @@ -13,7 +13,7 @@ void test_network_remote_remotes__initialize(void) cl_git_pass(git_remote_load(&_remote, _repo, "test")); - _refspec = git_remote_fetchspec(_remote); + _refspec = git_vector_get(&_remote->refspecs, 0); cl_assert(_refspec != NULL); } @@ -109,20 +109,41 @@ void test_network_remote_remotes__refspec_parsing(void) cl_assert_equal_s(git_refspec_dst(_refspec), "refs/remotes/test/*"); } -void test_network_remote_remotes__set_fetchspec(void) +void test_network_remote_remotes__add_fetchspec(void) { - cl_git_pass(git_remote_set_fetchspec(_remote, "refs/*:refs/*")); - _refspec = git_remote_fetchspec(_remote); + size_t size; + + size = _remote->refspecs.length; + cl_assert_equal_i(size, _remote->refspec_strings.length); + + cl_git_pass(git_remote_add_fetchspec(_remote, "refs/*:refs/*")); + + size++; + cl_assert_equal_i(size, _remote->refspec_strings.length); + cl_assert_equal_i(size, _remote->refspecs.length); + + _refspec = git_vector_get(&_remote->refspecs, size-1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); + cl_assert_equal_i(_refspec->push, false); } -void test_network_remote_remotes__set_pushspec(void) +void test_network_remote_remotes__add_pushspec(void) { - cl_git_pass(git_remote_set_pushspec(_remote, "refs/*:refs/*")); - _refspec = git_remote_pushspec(_remote); + size_t size; + + size = _remote->refspecs.length; + + cl_git_pass(git_remote_add_pushspec(_remote, "refs/*:refs/*")); + size++; + cl_assert_equal_i(size, _remote->refspec_strings.length); + cl_assert_equal_i(size, _remote->refspecs.length); + + _refspec = git_vector_get(&_remote->refspecs, size-1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); + + cl_assert_equal_i(_refspec->push, true); } void test_network_remote_remotes__save(void) @@ -132,8 +153,18 @@ void test_network_remote_remotes__save(void) /* Set up the remote and save it to config */ cl_git_pass(git_remote_create(&_remote, _repo, "upstream", "git://github.com/libgit2/libgit2")); - cl_git_pass(git_remote_set_fetchspec(_remote, "refs/heads/*:refs/remotes/upstream/*")); - cl_git_pass(git_remote_set_pushspec(_remote, "refs/heads/*:refs/heads/*")); + git_remote_clear_refspecs(_remote); + cl_assert_equal_i(0, _remote->refspecs.length); + cl_assert_equal_i(0, _remote->refspec_strings.length); + + cl_git_pass(git_remote_add_fetchspec(_remote, "refs/heads/*:refs/remotes/upstream/*")); + cl_assert_equal_i(1, _remote->refspecs.length); + cl_assert_equal_i(1, _remote->refspec_strings.length); + + cl_git_pass(git_remote_add_pushspec(_remote, "refs/heads/*:refs/heads/*")); + cl_assert_equal_i(2, _remote->refspecs.length); + cl_assert_equal_i(2, _remote->refspec_strings.length); + cl_git_pass(git_remote_set_pushurl(_remote, "git://github.com/libgit2/libgit2_push")); cl_git_pass(git_remote_save(_remote)); git_remote_free(_remote); @@ -142,13 +173,14 @@ void test_network_remote_remotes__save(void) /* Load it from config and make sure everything matches */ cl_git_pass(git_remote_load(&_remote, _repo, "upstream")); - _refspec = git_remote_fetchspec(_remote); + _refspec = git_vector_get(&_remote->refspecs, 0); cl_assert(_refspec != NULL); cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/remotes/upstream/*"); cl_assert_equal_i(0, git_refspec_force(_refspec)); - _refspec = git_remote_pushspec(_remote); + cl_assert(_refspec != git_vector_get(&_remote->refspecs, 1)); + _refspec = git_vector_get(&_remote->refspecs, 1); cl_assert(_refspec != NULL); cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/heads/*"); @@ -265,7 +297,7 @@ void test_network_remote_remotes__add(void) _remote = NULL; cl_git_pass(git_remote_load(&_remote, _repo, "addtest")); - _refspec = git_remote_fetchspec(_remote); + _refspec = git_vector_get(&_remote->refspecs, 0); cl_assert_equal_s("refs/heads/*", git_refspec_src(_refspec)); cl_assert(git_refspec_force(_refspec) == 1); cl_assert_equal_s("refs/remotes/addtest/*", git_refspec_dst(_refspec)); diff --git a/tests-clar/online/fetchhead.c b/tests-clar/online/fetchhead.c index a8a5bb918..3cbdc7e93 100644 --- a/tests-clar/online/fetchhead.c +++ b/tests-clar/online/fetchhead.c @@ -42,8 +42,10 @@ static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fet cl_git_pass(git_remote_load(&remote, g_repo, "origin")); git_remote_set_autotag(remote, GIT_REMOTE_DOWNLOAD_TAGS_AUTO); - if(fetchspec != NULL) - git_remote_set_fetchspec(remote, fetchspec); + if(fetchspec != NULL) { + git_remote_clear_refspecs(remote); + git_remote_add_fetchspec(remote, fetchspec); + } cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); cl_git_pass(git_remote_download(remote, NULL, NULL)); diff --git a/tests-clar/online/push.c b/tests-clar/online/push.c index 907d6d29f..5dc7974c7 100644 --- a/tests-clar/online/push.c +++ b/tests-clar/online/push.c @@ -160,7 +160,7 @@ static int tracking_branch_list_cb(const char *branch_name, git_branch_t branch_ */ static void verify_tracking_branches(git_remote *remote, expected_ref expected_refs[], size_t expected_refs_len) { - git_refspec *fetch_spec = &remote->fetch; + git_refspec *fetch_spec; size_t i, j; git_buf msg = GIT_BUF_INIT; git_buf ref_name = GIT_BUF_INIT; @@ -179,7 +179,8 @@ static void verify_tracking_branches(git_remote *remote, expected_ref expected_r /* Convert remote reference name into tracking branch name. * If the spec is not under refs/heads/, then skip. */ - if (!git_refspec_src_matches(fetch_spec, expected_refs[i].name)) + fetch_spec = git_remote__matching_refspec(remote, expected_refs[i].name); + if (!fetch_spec) continue; cl_git_pass(git_refspec_transform_r(&ref_name, fetch_spec, expected_refs[i].name)); diff --git a/tests-clar/refs/branches/remote.c b/tests-clar/refs/branches/remote.c index 2beef3724..475fa54a8 100644 --- a/tests-clar/refs/branches/remote.c +++ b/tests-clar/refs/branches/remote.c @@ -69,7 +69,8 @@ void test_refs_branches_remote__ambiguous_remote_returns_error(void) cl_git_pass(git_remote_create(&remote, g_repo, "addtest", "http://github.com/libgit2/libgit2")); /* Update the remote fetch spec */ - cl_git_pass(git_remote_set_fetchspec(remote, "refs/heads/*:refs/remotes/test/*")); + git_remote_clear_refspecs(remote); + cl_git_pass(git_remote_add_fetchspec(remote, "refs/heads/*:refs/remotes/test/*")); cl_git_pass(git_remote_save(remote)); git_remote_free(remote); From bc6374eac485ab9ad9cfd7165b6d071c3dcb673a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 20 Apr 2013 18:49:11 +0200 Subject: [PATCH 028/134] remote: allow querying for refspecs Introduce git_remote_{fetch,push}_refspecs() to get a list of refspecs from the remote and rename the refspec-adding functions to a less silly name. Use this instead of the vector index hacks in the tests. --- include/git2/remote.h | 26 +++++++++- src/clone.c | 4 +- src/remote.c | 52 ++++++++++++++++++- tests-clar/network/remote/remotes.c | 79 ++++++++++++++++++++--------- tests-clar/online/fetchhead.c | 2 +- tests-clar/refs/branches/remote.c | 2 +- 6 files changed, 134 insertions(+), 31 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 7a161796f..5dcd93099 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -148,7 +148,18 @@ GIT_EXTERN(int) git_remote_set_pushurl(git_remote *remote, const char* url); * @apram refspec the new fetch refspec * @return 0 or an error value */ -GIT_EXTERN(int) git_remote_add_fetchspec(git_remote *remote, const char *refspec); +GIT_EXTERN(int) git_remote_add_fetch(git_remote *remote, const char *refspec); + +/** + * Get the remote's list of fetch refspecs + * + * The memory is owned by the user and should be freed with + * `git_strarray_free`. + * + * @param array pointer to the array in which to store the strings + * @param remote the remote to query + */ +GIT_EXTERN(int) git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote); /** * Add a push refspec to the remote @@ -157,7 +168,18 @@ GIT_EXTERN(int) git_remote_add_fetchspec(git_remote *remote, const char *refspec * @param refspec the new push refspec * @return 0 or an error value */ -GIT_EXTERN(int) git_remote_add_pushspec(git_remote *remote, const char *refspec); +GIT_EXTERN(int) git_remote_add_push(git_remote *remote, const char *refspec); + +/** + * Get the remote's list of push refspecs + * + * The memory is owned by the user and should be freed with + * `git_strarray_free`. + * + * @param array pointer to the array in which to store the strings + * @param remote the remote to query + */ +GIT_EXTERN(int) git_remote_get_push_refspecs(git_strarray *array, git_remote *remote); /** * Get the push refspec diff --git a/src/clone.c b/src/clone.c index cb4053736..8f10ca819 100644 --- a/src/clone.c +++ b/src/clone.c @@ -324,11 +324,11 @@ static int create_and_configure_origin( goto on_error; if (options->fetch_spec && - (error = git_remote_add_fetchspec(origin, options->fetch_spec)) < 0) + (error = git_remote_add_fetch(origin, options->fetch_spec)) < 0) goto on_error; if (options->push_spec && - (error = git_remote_add_pushspec(origin, options->push_spec)) < 0) + (error = git_remote_add_push(origin, options->push_spec)) < 0) goto on_error; if (options->pushurl && diff --git a/src/remote.c b/src/remote.c index 1c4b22bb9..8b7e66e53 100644 --- a/src/remote.c +++ b/src/remote.c @@ -1467,12 +1467,60 @@ void git_remote_clear_refspecs(git_remote *remote) git_vector_clear(&remote->refspec_strings); } -int git_remote_add_fetchspec(git_remote *remote, const char *refspec) +int git_remote_add_fetch(git_remote *remote, const char *refspec) { return add_refspec(remote, refspec, true); } -int git_remote_add_pushspec(git_remote *remote, const char *refspec) +int git_remote_add_push(git_remote *remote, const char *refspec) { return add_refspec(remote, refspec, false); } + +static int copy_refspecs(git_strarray *array, git_remote *remote, int push) +{ + size_t i; + git_vector refspecs; + git_refspec *spec; + char *dup; + + if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0) + return -1; + + git_vector_foreach(&remote->refspecs, i, spec) { + if (spec->push != push) + continue; + + dup = git__strdup(git_vector_get(&remote->refspec_strings, i)); + if (!dup) { + goto on_error; + } + + if (git_vector_insert(&refspecs, dup) < 0) { + git__free(dup); + goto on_error; + } + } + + array->strings = (char **)refspecs.contents; + array->count = refspecs.length; + + return 0; + +on_error: + git_vector_foreach(&refspecs, i, dup) + git__free(dup); + git_vector_free(&refspecs); + + return -1; +} + +int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote) +{ + return copy_refspecs(array, remote, false); +} + +int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote) +{ + return copy_refspecs(array, remote, true); +} diff --git a/tests-clar/network/remote/remotes.c b/tests-clar/network/remote/remotes.c index 92c9d8ac1..7b6e6aa85 100644 --- a/tests-clar/network/remote/remotes.c +++ b/tests-clar/network/remote/remotes.c @@ -116,7 +116,7 @@ void test_network_remote_remotes__add_fetchspec(void) size = _remote->refspecs.length; cl_assert_equal_i(size, _remote->refspec_strings.length); - cl_git_pass(git_remote_add_fetchspec(_remote, "refs/*:refs/*")); + cl_git_pass(git_remote_add_fetch(_remote, "refs/*:refs/*")); size++; cl_assert_equal_i(size, _remote->refspec_strings.length); @@ -134,7 +134,7 @@ void test_network_remote_remotes__add_pushspec(void) size = _remote->refspecs.length; - cl_git_pass(git_remote_add_pushspec(_remote, "refs/*:refs/*")); + cl_git_pass(git_remote_add_push(_remote, "refs/*:refs/*")); size++; cl_assert_equal_i(size, _remote->refspec_strings.length); cl_assert_equal_i(size, _remote->refspecs.length); @@ -148,23 +148,19 @@ void test_network_remote_remotes__add_pushspec(void) void test_network_remote_remotes__save(void) { + git_strarray array; + const char *fetch_refspec = "refs/heads/*:refs/remotes/upstream/*"; + const char *push_refspec = "refs/heads/*:refs/heads/*"; + git_remote_free(_remote); _remote = NULL; /* Set up the remote and save it to config */ cl_git_pass(git_remote_create(&_remote, _repo, "upstream", "git://github.com/libgit2/libgit2")); git_remote_clear_refspecs(_remote); - cl_assert_equal_i(0, _remote->refspecs.length); - cl_assert_equal_i(0, _remote->refspec_strings.length); - - cl_git_pass(git_remote_add_fetchspec(_remote, "refs/heads/*:refs/remotes/upstream/*")); - cl_assert_equal_i(1, _remote->refspecs.length); - cl_assert_equal_i(1, _remote->refspec_strings.length); - - cl_git_pass(git_remote_add_pushspec(_remote, "refs/heads/*:refs/heads/*")); - cl_assert_equal_i(2, _remote->refspecs.length); - cl_assert_equal_i(2, _remote->refspec_strings.length); + cl_git_pass(git_remote_add_fetch(_remote, fetch_refspec)); + cl_git_pass(git_remote_add_push(_remote, push_refspec)); cl_git_pass(git_remote_set_pushurl(_remote, "git://github.com/libgit2/libgit2_push")); cl_git_pass(git_remote_save(_remote)); git_remote_free(_remote); @@ -173,20 +169,17 @@ void test_network_remote_remotes__save(void) /* Load it from config and make sure everything matches */ cl_git_pass(git_remote_load(&_remote, _repo, "upstream")); - _refspec = git_vector_get(&_remote->refspecs, 0); - cl_assert(_refspec != NULL); - cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); - cl_assert_equal_s(git_refspec_dst(_refspec), "refs/remotes/upstream/*"); - cl_assert_equal_i(0, git_refspec_force(_refspec)); - - cl_assert(_refspec != git_vector_get(&_remote->refspecs, 1)); - _refspec = git_vector_get(&_remote->refspecs, 1); - cl_assert(_refspec != NULL); - cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); - cl_assert_equal_s(git_refspec_dst(_refspec), "refs/heads/*"); + cl_git_pass(git_remote_get_fetch_refspecs(&array, _remote)); + cl_assert_equal_i(1, array.count); + cl_assert_equal_s(fetch_refspec, array.strings[0]); + git_strarray_free(&array); + cl_git_pass(git_remote_get_push_refspecs(&array, _remote)); + cl_assert_equal_i(1, array.count); + cl_assert_equal_s(push_refspec, array.strings[0]); cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2"); cl_assert_equal_s(git_remote_pushurl(_remote), "git://github.com/libgit2/libgit2_push"); + git_strarray_free(&array); /* remove the pushurl again and see if we can save that too */ cl_git_pass(git_remote_set_pushurl(_remote, NULL)); @@ -418,3 +411,43 @@ void test_network_remote_remotes__cannot_create_a_remote_which_name_is_invalid(v assert_cannot_create_remote(".lock", GIT_EINVALIDSPEC); assert_cannot_create_remote("a.lock", GIT_EINVALIDSPEC); } + +static const char *fetch_refspecs[] = { + "+refs/heads/*:refs/remotes/origin/*", + "refs/tags/*:refs/tags/*", + "+refs/pull/*:refs/pull/*", +}; + +static const char *push_refspecs[] = { + "refs/heads/*:refs/heads/*", + "refs/tags/*:refs/tags/*", + "refs/notes/*:refs/notes/*", +}; + +void test_network_remote_remotes__query_refspecs(void) +{ + git_remote *remote; + git_strarray array; + int i; + + cl_git_pass(git_remote_create_inmemory(&remote, _repo, NULL, "git://github.com/libgit2/libgit2")); + + for (i = 0; i < 3; i++) { + cl_git_pass(git_remote_add_fetch(remote, fetch_refspecs[i])); + cl_git_pass(git_remote_add_push(remote, push_refspecs[i])); + } + + cl_git_pass(git_remote_get_fetch_refspecs(&array, remote)); + for (i = 0; i < 3; i++) { + cl_assert_equal_s(fetch_refspecs[i], array.strings[i]); + } + git_strarray_free(&array); + + cl_git_pass(git_remote_get_push_refspecs(&array, remote)); + for (i = 0; i < 3; i++) { + cl_assert_equal_s(push_refspecs[i], array.strings[i]); + } + git_strarray_free(&array); + + git_remote_free(remote); +} diff --git a/tests-clar/online/fetchhead.c b/tests-clar/online/fetchhead.c index 3cbdc7e93..e14ae0926 100644 --- a/tests-clar/online/fetchhead.c +++ b/tests-clar/online/fetchhead.c @@ -44,7 +44,7 @@ static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fet if(fetchspec != NULL) { git_remote_clear_refspecs(remote); - git_remote_add_fetchspec(remote, fetchspec); + git_remote_add_fetch(remote, fetchspec); } cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); diff --git a/tests-clar/refs/branches/remote.c b/tests-clar/refs/branches/remote.c index 475fa54a8..6043828b3 100644 --- a/tests-clar/refs/branches/remote.c +++ b/tests-clar/refs/branches/remote.c @@ -70,7 +70,7 @@ void test_refs_branches_remote__ambiguous_remote_returns_error(void) /* Update the remote fetch spec */ git_remote_clear_refspecs(remote); - cl_git_pass(git_remote_add_fetchspec(remote, "refs/heads/*:refs/remotes/test/*")); + cl_git_pass(git_remote_add_fetch(remote, "refs/heads/*:refs/remotes/test/*")); cl_git_pass(git_remote_save(remote)); git_remote_free(remote); From 1be680c4d0909ee5160292d7b56c4522c4bc309c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 20 Apr 2013 19:13:47 +0200 Subject: [PATCH 029/134] refspec: unify the string and parsed data It used to be separate as an attempt to make the querying easier, but it didn't work out that way, so put all the data together. Add git_refspec_string() as well to get the original string, which is now stored alongside the independent parts. --- include/git2/refspec.h | 8 ++++ src/refspec.c | 9 ++++ src/refspec.h | 1 + src/remote.c | 64 +++++++++-------------------- src/remote.h | 1 - tests-clar/network/remote/remotes.c | 6 +-- 6 files changed, 40 insertions(+), 49 deletions(-) diff --git a/include/git2/refspec.h b/include/git2/refspec.h index ec7830b7c..3e1b502ef 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -35,6 +35,14 @@ GIT_EXTERN(const char *) git_refspec_src(const git_refspec *refspec); */ GIT_EXTERN(const char *) git_refspec_dst(const git_refspec *refspec); +/** + * Get the refspec's string + * + * @param refspec the refspec + * @returns the refspec's original string + */ +GIT_EXTERN(const char *) git_refspec_string(const git_refspec *refspec); + /** * Get the force update setting * diff --git a/src/refspec.c b/src/refspec.c index 0ed02f48b..fbdea9d93 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -120,6 +120,9 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) } } + refspec->string = git__strdup(input); + GITERR_CHECK_ALLOC(refspec->string); + return 0; invalid: @@ -133,6 +136,7 @@ void git_refspec__free(git_refspec *refspec) git__free(refspec->src); git__free(refspec->dst); + git__free(refspec->string); } const char *git_refspec_src(const git_refspec *refspec) @@ -145,6 +149,11 @@ const char *git_refspec_dst(const git_refspec *refspec) return refspec == NULL ? NULL : refspec->dst; } +const char *git_refspec_string(const git_refspec *refspec) +{ + return refspec == NULL ? NULL : refspec->string; +} + int git_refspec_force(const git_refspec *refspec) { assert(refspec); diff --git a/src/refspec.h b/src/refspec.h index 339d10eb2..29f4d5354 100644 --- a/src/refspec.h +++ b/src/refspec.h @@ -11,6 +11,7 @@ #include "buffer.h" struct git_refspec { + char *string; char *src; char *dst; unsigned int force :1, diff --git a/src/remote.c b/src/remote.c index 8b7e66e53..ffce2b6e2 100644 --- a/src/remote.c +++ b/src/remote.c @@ -21,32 +21,24 @@ static int add_refspec(git_remote *remote, const char *string, bool is_fetch) { - char *name_dup; git_refspec *spec; spec = git__calloc(1, sizeof(git_refspec)); GITERR_CHECK_ALLOC(spec); - name_dup = git__strdup(string); - if (!name_dup) - goto on_error; - - if (git_refspec__parse(spec, string, is_fetch) < 0) - goto on_error; + if (git_refspec__parse(spec, string, is_fetch) < 0) { + git__free(spec); + return -1; + } spec->push = !is_fetch; - if (git_vector_insert(&remote->refspec_strings, name_dup) < 0) - goto on_error; - - if (git_vector_insert(&remote->refspecs, spec) < 0) - goto on_error; + if (git_vector_insert(&remote->refspecs, spec) < 0) { + git_refspec__free(spec); + git__free(spec); + return -1; + } return 0; - -on_error: - git__free(spec); - git__free(name_dup); - return -1; } static int download_tags_value(git_remote *remote, git_config *cfg) @@ -245,8 +237,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) GITERR_CHECK_ALLOC(remote->name); if ((git_vector_init(&remote->refs, 32, NULL) < 0) || - (git_vector_init(&remote->refspecs, 2, NULL)) || - (git_vector_init(&remote->refspec_strings, 2, NULL))) { + (git_vector_init(&remote->refspecs, 2, NULL))) { error = -1; goto cleanup; } @@ -360,15 +351,13 @@ static int update_config_refspec(const git_remote *remote, git_config *config, i if (error != GIT_ENOTFOUND) return error; - for (i = 0; i < remote->refspec_strings.length; i++) { + for (i = 0; i < remote->refspecs.length; i++) { git_refspec *spec = git_vector_get(&remote->refspecs, i); - const char *str = git_vector_get(&remote->refspec_strings, i); - assert(spec && str); if (spec->push != push) continue; - if ((error = git_config_set_multivar(config, git_buf_cstr(&name), "", str)) < 0) { + if ((error = git_config_set_multivar(config, git_buf_cstr(&name), "", spec->string)) < 0) { goto cleanup; } } @@ -947,7 +936,6 @@ void git_remote_disconnect(git_remote *remote) void git_remote_free(git_remote *remote) { git_refspec *spec; - char *str; size_t i; if (remote == NULL) @@ -968,10 +956,6 @@ void git_remote_free(git_remote *remote) } git_vector_free(&remote->refspecs); - git_vector_foreach(&remote->refspec_strings, i, str) - git__free(str); - git_vector_free(&remote->refspec_strings); - git__free(remote->url); git__free(remote->pushurl); git__free(remote->name); @@ -1263,23 +1247,20 @@ static int rename_fetch_refspecs( { git_config *config; git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT; - const char *refspec; + const git_refspec *spec; size_t i; int error = -1; if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0) goto cleanup; - git_vector_foreach(&remote->refspec_strings, i, refspec) { - git_refspec *spec = git_vector_get(&remote->refspecs, i); - assert(spec); - + git_vector_foreach(&remote->refspecs, i, spec) { if (spec->push) continue; /* Every refspec is a problem refspec for an in-memory remote */ if (!remote->name) { - if (callback(refspec, payload) < 0) { + if (callback(spec->string, payload) < 0) { error = GIT_EUSER; goto cleanup; } @@ -1288,8 +1269,8 @@ static int rename_fetch_refspecs( } /* Does the dst part of the refspec follow the extected standard format? */ - if (strcmp(git_buf_cstr(&base), refspec)) { - if (callback(refspec, payload) < 0) { + if (strcmp(git_buf_cstr(&base), spec->string)) { + if (callback(spec->string, payload) < 0) { error = GIT_EUSER; goto cleanup; } @@ -1453,18 +1434,13 @@ git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *re void git_remote_clear_refspecs(git_remote *remote) { git_refspec *spec; - char *str; size_t i; git_vector_foreach(&remote->refspecs, i, spec) { git_refspec__free(spec); + git__free(spec); } git_vector_clear(&remote->refspecs); - - git_vector_foreach(&remote->refspec_strings, i, str) { - git__free(str); - } - git_vector_clear(&remote->refspec_strings); } int git_remote_add_fetch(git_remote *remote, const char *refspec) @@ -1491,10 +1467,8 @@ static int copy_refspecs(git_strarray *array, git_remote *remote, int push) if (spec->push != push) continue; - dup = git__strdup(git_vector_get(&remote->refspec_strings, i)); - if (!dup) { + if ((dup = git__strdup(spec->string)) == NULL) goto on_error; - } if (git_vector_insert(&refspecs, dup) < 0) { git__free(dup); diff --git a/src/remote.h b/src/remote.h index b1f33f0e7..c9c26b77d 100644 --- a/src/remote.h +++ b/src/remote.h @@ -21,7 +21,6 @@ struct git_remote { char *pushurl; git_vector refs; git_vector refspecs; - git_vector refspec_strings; git_cred_acquire_cb cred_acquire_cb; void *cred_acquire_payload; git_transport *transport; diff --git a/tests-clar/network/remote/remotes.c b/tests-clar/network/remote/remotes.c index 7b6e6aa85..908e17d96 100644 --- a/tests-clar/network/remote/remotes.c +++ b/tests-clar/network/remote/remotes.c @@ -114,17 +114,17 @@ void test_network_remote_remotes__add_fetchspec(void) size_t size; size = _remote->refspecs.length; - cl_assert_equal_i(size, _remote->refspec_strings.length); + cl_assert_equal_i(size, _remote->refspecs.length); cl_git_pass(git_remote_add_fetch(_remote, "refs/*:refs/*")); size++; - cl_assert_equal_i(size, _remote->refspec_strings.length); cl_assert_equal_i(size, _remote->refspecs.length); _refspec = git_vector_get(&_remote->refspecs, size-1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); + cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); cl_assert_equal_i(_refspec->push, false); } @@ -136,12 +136,12 @@ void test_network_remote_remotes__add_pushspec(void) cl_git_pass(git_remote_add_push(_remote, "refs/*:refs/*")); size++; - cl_assert_equal_i(size, _remote->refspec_strings.length); cl_assert_equal_i(size, _remote->refspecs.length); _refspec = git_vector_get(&_remote->refspecs, size-1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); + cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); cl_assert_equal_i(_refspec->push, true); } From 6b24688758b721afece65702475f76d225d096be Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sun, 21 Apr 2013 08:59:04 +0200 Subject: [PATCH 030/134] mailmap: Coalesce some identities --- .mailmap | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.mailmap b/.mailmap index a8b171908..3f5a087ea 100644 --- a/.mailmap +++ b/.mailmap @@ -5,3 +5,14 @@ Ben Straub Ben Straub Ben Straub Ben Straub Carlos Martín Nieto Carlos Martín Nieto +nulltoken +Scott J. Goldman +Martin Woodward +Peter Drahoš +Adam Roben +Adam Roben +Xavier L. +Xavier L. +Sascha Cunz +Authmillenon +Authmillenon From 83041c711cd7d9fccb7a1327e642ce33f0705370 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 11:52:04 -0700 Subject: [PATCH 031/134] Move git_config_backend to include/git2/sys Moving backend implementor objects into include/git2/sys so the APIs can be isolated from the ones that normal libgit2 users would be likely to use. --- include/git2/config.h | 52 ++------------------------- include/git2/sys/config.h | 70 +++++++++++++++++++++++++++++++++++++ src/config.c | 1 + src/config_file.c | 1 + src/submodule.c | 1 + tests-clar/config/backend.c | 1 + 6 files changed, 76 insertions(+), 50 deletions(-) create mode 100644 include/git2/sys/config.h diff --git a/include/git2/config.h b/include/git2/config.h index 19d4cb78d..5a2f956fd 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -43,29 +43,6 @@ typedef struct { typedef int (*git_config_foreach_cb)(const git_config_entry *, void *); - -/** - * Generic backend that implements the interface to - * access a configuration file - */ -struct git_config_backend { - unsigned int version; - struct git_config *cfg; - - /* Open means open the file/database and parse if necessary */ - int (*open)(struct git_config_backend *, unsigned int level); - int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry); - int (*get_multivar)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload); - int (*set)(struct git_config_backend *, const char *key, const char *value); - int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); - int (*del)(struct git_config_backend *, const char *key); - int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload); - int (*refresh)(struct git_config_backend *); - void (*free)(struct git_config_backend *); -}; -#define GIT_CONFIG_BACKEND_VERSION 1 -#define GIT_CONFIG_BACKEND_INIT {GIT_CONFIG_BACKEND_VERSION} - typedef enum { GIT_CVAR_FALSE = 0, GIT_CVAR_TRUE = 1, @@ -153,30 +130,6 @@ GIT_EXTERN(int) git_config_open_default(git_config **out); */ GIT_EXTERN(int) git_config_new(git_config **out); -/** - * Add a generic config file instance to an existing config - * - * Note that the configuration object will free the file - * automatically. - * - * Further queries on this config object will access each - * of the config file instances in order (instances with - * a higher priority level will be accessed first). - * - * @param cfg the configuration to add the file to - * @param file the configuration file (backend) to add - * @param level the priority level of the backend - * @param force if a config file already exists for the given - * priority level, replace it - * @return 0 on success, GIT_EEXISTS when adding more than one file - * for a given priority level (and force_replace set to 0), or error code - */ -GIT_EXTERN(int) git_config_add_backend( - git_config *cfg, - git_config_backend *file, - unsigned int level, - int force); - /** * Add an on-disk config file instance to an existing config * @@ -192,10 +145,9 @@ GIT_EXTERN(int) git_config_add_backend( * a higher priority level will be accessed first). * * @param cfg the configuration to add the file to - * @param path path to the configuration file (backend) to add + * @param path path to the configuration file to add * @param level the priority level of the backend - * @param force if a config file already exists for the given - * priority level, replace it + * @param force replace config file at the given priority level * @return 0 on success, GIT_EEXISTS when adding more than one file * for a given priority level (and force_replace set to 0), * GIT_ENOTFOUND when the file doesn't exist or error code diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h new file mode 100644 index 000000000..c9039e96e --- /dev/null +++ b/include/git2/sys/config.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_git_sys_config_h__ +#define INCLUDE_git_sys_config_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/config.h" + +/** + * @file git2/sys/config.h + * @brief Git config backend routines + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Generic backend that implements the interface to + * access a configuration file + */ +struct git_config_backend { + unsigned int version; + struct git_config *cfg; + + /* Open means open the file/database and parse if necessary */ + int (*open)(struct git_config_backend *, unsigned int level); + int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry); + int (*get_multivar)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload); + int (*set)(struct git_config_backend *, const char *key, const char *value); + int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); + int (*del)(struct git_config_backend *, const char *key); + int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload); + int (*refresh)(struct git_config_backend *); + void (*free)(struct git_config_backend *); +}; +#define GIT_CONFIG_BACKEND_VERSION 1 +#define GIT_CONFIG_BACKEND_INIT {GIT_CONFIG_BACKEND_VERSION} + +/** + * Add a generic config file instance to an existing config + * + * Note that the configuration object will free the file + * automatically. + * + * Further queries on this config object will access each + * of the config file instances in order (instances with + * a higher priority level will be accessed first). + * + * @param cfg the configuration to add the file to + * @param file the configuration file (backend) to add + * @param level the priority level of the backend + * @param force if a config file already exists for the given + * priority level, replace it + * @return 0 on success, GIT_EEXISTS when adding more than one file + * for a given priority level (and force_replace set to 0), or error code + */ +GIT_EXTERN(int) git_config_add_backend( + git_config *cfg, + git_config_backend *file, + unsigned int level, + int force); + +/** @} */ +GIT_END_DECL +#endif diff --git a/src/config.c b/src/config.c index 5379b0ec5..1283522ca 100644 --- a/src/config.c +++ b/src/config.c @@ -9,6 +9,7 @@ #include "fileops.h" #include "config.h" #include "git2/config.h" +#include "git2/sys/config.h" #include "vector.h" #include "buf_text.h" #include "config_file.h" diff --git a/src/config_file.c b/src/config_file.c index 8b51ab21b..a4ff8bb94 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -12,6 +12,7 @@ #include "buffer.h" #include "buf_text.h" #include "git2/config.h" +#include "git2/sys/config.h" #include "git2/types.h" #include "strmap.h" diff --git a/src/submodule.c b/src/submodule.c index 2fdaf2f77..0a22e3b13 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -7,6 +7,7 @@ #include "common.h" #include "git2/config.h" +#include "git2/sys/config.h" #include "git2/types.h" #include "git2/repository.h" #include "git2/index.h" diff --git a/tests-clar/config/backend.c b/tests-clar/config/backend.c index 28502a8ba..3fd6eb114 100644 --- a/tests-clar/config/backend.c +++ b/tests-clar/config/backend.c @@ -1,4 +1,5 @@ #include "clar_libgit2.h" +#include "git2/sys/config.h" void test_config_backend__checks_version(void) { From 83cc70d9fec5f81d07f9fc4133c9515527efb9af Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 12:48:33 -0700 Subject: [PATCH 032/134] Move odb_backend implementors stuff into git2/sys This moves some of the odb_backend stuff that is related to the internals of an odb_backend implementation into include/git2/sys. Some of the stuff related to streaming I left in include/git2 because it seemed like it would be reasonably needed by a normal user who wanted to stream objects into and out of the ODB. Also, I added APIs for traversing the list of backends so that some of the tests would not need to access ODB internals. --- include/git2/indexer.h | 22 +----- include/git2/odb.h | 97 +++++++++++++++---------- include/git2/odb_backend.h | 123 +++++--------------------------- include/git2/sys/config.h | 5 +- include/git2/sys/odb_backend.h | 86 ++++++++++++++++++++++ include/git2/types.h | 20 ++++++ src/blob.c | 1 + src/odb.c | 22 ++++++ src/odb_loose.c | 2 +- src/odb_pack.c | 3 +- src/tag.c | 1 + src/transports/smart_protocol.c | 1 + tests-clar/object/raw/write.c | 3 +- tests-clar/odb/packed_one.c | 3 +- tests-clar/odb/sorting.c | 18 +++-- 15 files changed, 225 insertions(+), 182 deletions(-) create mode 100644 include/git2/sys/odb_backend.h diff --git a/include/git2/indexer.h b/include/git2/indexer.h index dfe6ae5aa..262dcd154 100644 --- a/include/git2/indexer.h +++ b/include/git2/indexer.h @@ -8,31 +8,11 @@ #define _INCLUDE_git_indexer_h__ #include "common.h" +#include "types.h" #include "oid.h" GIT_BEGIN_DECL -/** - * This is passed as the first argument to the callback to allow the - * user to see the progress. - */ -typedef struct git_transfer_progress { - unsigned int total_objects; - unsigned int indexed_objects; - unsigned int received_objects; - size_t received_bytes; -} git_transfer_progress; - - -/** - * Type for progress callbacks during indexing. Return a value less than zero - * to cancel the transfer. - * - * @param stats Structure containing information about the state of the transfer - * @param payload Payload provided by caller - */ -typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); - typedef struct git_indexer_stream git_indexer_stream; /** diff --git a/include/git2/odb.h b/include/git2/odb.h index 8fd1a95be..b64436c4d 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -10,8 +10,6 @@ #include "common.h" #include "types.h" #include "oid.h" -#include "odb_backend.h" -#include "indexer.h" /** * @file git2/odb.h @@ -22,6 +20,11 @@ */ GIT_BEGIN_DECL +/** + * Function type for callbacks from git_odb_foreach. + */ +typedef int (*git_odb_foreach_cb)(const git_oid *id, void *payload); + /** * Create a new object database with no backends. * @@ -52,42 +55,6 @@ GIT_EXTERN(int) git_odb_new(git_odb **out); */ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); -/** - * Add a custom backend to an existing Object DB - * - * The backends are checked in relative ordering, based on the - * value of the `priority` parameter. - * - * Read for more information. - * - * @param odb database to add the backend to - * @param backend pointer to a git_odb_backend instance - * @param priority Value for ordering the backends queue - * @return 0 on success; error code otherwise - */ -GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority); - -/** - * Add a custom backend to an existing Object DB; this - * backend will work as an alternate. - * - * Alternate backends are always checked for objects *after* - * all the main backends have been exhausted. - * - * The backends are checked in relative ordering, based on the - * value of the `priority` parameter. - * - * Writing is disabled on alternate backends. - * - * Read for more information. - * - * @param odb database to add the backend to - * @param backend pointer to a git_odb_backend instance - * @param priority Value for ordering the backends queue - * @return 0 on success; error code otherwise - */ -GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority); - /** * Add an on-disk alternate to an existing Object DB. * @@ -406,6 +373,60 @@ GIT_EXTERN(size_t) git_odb_object_size(git_odb_object *object); */ GIT_EXTERN(git_otype) git_odb_object_type(git_odb_object *object); +/** + * Add a custom backend to an existing Object DB + * + * The backends are checked in relative ordering, based on the + * value of the `priority` parameter. + * + * Read for more information. + * + * @param odb database to add the backend to + * @param backend pointer to a git_odb_backend instance + * @param priority Value for ordering the backends queue + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority); + +/** + * Add a custom backend to an existing Object DB; this + * backend will work as an alternate. + * + * Alternate backends are always checked for objects *after* + * all the main backends have been exhausted. + * + * The backends are checked in relative ordering, based on the + * value of the `priority` parameter. + * + * Writing is disabled on alternate backends. + * + * Read for more information. + * + * @param odb database to add the backend to + * @param backend pointer to a git_odb_backend instance + * @param priority Value for ordering the backends queue + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority); + +/** + * Get the number of ODB backend objects + * + * @param odb object database + * @return number of backends in the ODB + */ +GIT_EXTERN(size_t) git_odb_num_backends(git_odb *odb); + +/** + * Lookup an ODB backend object by index + * + * @param out output pointer to ODB backend at pos + * @param odb object database + * @param pos index into object database backend list + * @return 0 on success; GIT_ENOTFOUND if pos is invalid; other errors < 0 + */ +GIT_EXTERN(int) git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h index dbc3981f6..d38005d15 100644 --- a/include/git2/odb_backend.h +++ b/include/git2/odb_backend.h @@ -7,106 +7,24 @@ #ifndef INCLUDE_git_odb_backend_h__ #define INCLUDE_git_odb_backend_h__ -#include "common.h" -#include "types.h" -#include "oid.h" -#include "indexer.h" +#include "git2/common.h" +#include "git2/types.h" /** * @file git2/backend.h * @brief Git custom backend functions - * @defgroup git_backend Git custom backend API + * @defgroup git_odb Git object database routines * @ingroup Git * @{ */ GIT_BEGIN_DECL -struct git_odb_stream; -struct git_odb_writepack; - /** - * Function type for callbacks from git_odb_foreach. + * Constructors for in-box ODB backends. */ -typedef int (*git_odb_foreach_cb)(const git_oid *id, void *payload); - -/** - * An instance for a custom backend - */ -struct git_odb_backend { - unsigned int version; - git_odb *odb; - - /* read and read_prefix each return to libgit2 a buffer which - * will be freed later. The buffer should be allocated using - * the function git_odb_backend_malloc to ensure that it can - * be safely freed later. */ - int (* read)( - void **, size_t *, git_otype *, - struct git_odb_backend *, - const git_oid *); - - /* To find a unique object given a prefix - * of its oid. - * The oid given must be so that the - * remaining (GIT_OID_HEXSZ - len)*4 bits - * are 0s. - */ - int (* read_prefix)( - git_oid *, - void **, size_t *, git_otype *, - struct git_odb_backend *, - const git_oid *, - size_t); - - int (* read_header)( - size_t *, git_otype *, - struct git_odb_backend *, - const git_oid *); - - /* The writer may assume that the object - * has already been hashed and is passed - * in the first parameter. - */ - int (* write)( - git_oid *, - struct git_odb_backend *, - const void *, - size_t, - git_otype); - - int (* writestream)( - struct git_odb_stream **, - struct git_odb_backend *, - size_t, - git_otype); - - int (* readstream)( - struct git_odb_stream **, - struct git_odb_backend *, - const git_oid *); - - int (* exists)( - struct git_odb_backend *, - const git_oid *); - - int (* refresh)(struct git_odb_backend *); - - int (* foreach)( - struct git_odb_backend *, - git_odb_foreach_cb cb, - void *payload); - - int (* writepack)( - struct git_odb_writepack **, - struct git_odb_backend *, - git_transfer_progress_callback progress_cb, - void *progress_payload); - - void (* free)(struct git_odb_backend *); -}; - -#define GIT_ODB_BACKEND_VERSION 1 -#define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} +GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); +GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects_dir, int compression_level, int do_fsync); +GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file); /** Streaming mode */ enum { @@ -117,33 +35,24 @@ enum { /** A stream to read/write from a backend */ struct git_odb_stream { - struct git_odb_backend *backend; + git_odb_backend *backend; unsigned int mode; - int (*read)(struct git_odb_stream *stream, char *buffer, size_t len); - int (*write)(struct git_odb_stream *stream, const char *buffer, size_t len); - int (*finalize_write)(git_oid *oid_p, struct git_odb_stream *stream); - void (*free)(struct git_odb_stream *stream); + int (*read)(git_odb_stream *stream, char *buffer, size_t len); + int (*write)(git_odb_stream *stream, const char *buffer, size_t len); + int (*finalize_write)(git_oid *oid_p, git_odb_stream *stream); + void (*free)(git_odb_stream *stream); }; /** A stream to write a pack file to the ODB */ struct git_odb_writepack { - struct git_odb_backend *backend; + git_odb_backend *backend; - int (*add)(struct git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats); - int (*commit)(struct git_odb_writepack *writepack, git_transfer_progress *stats); - void (*free)(struct git_odb_writepack *writepack); + int (*add)(git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats); + int (*commit)(git_odb_writepack *writepack, git_transfer_progress *stats); + void (*free)(git_odb_writepack *writepack); }; -GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len); - -/** - * Constructors for in-box ODB backends. - */ -GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); -GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects_dir, int compression_level, int do_fsync); -GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file); - GIT_END_DECL #endif diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index c9039e96e..1c9deba7c 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -4,8 +4,8 @@ * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ -#ifndef INCLUDE_git_sys_config_h__ -#define INCLUDE_git_sys_config_h__ +#ifndef INCLUDE_sys_git_config_backend_h__ +#define INCLUDE_sys_git_config_backend_h__ #include "git2/common.h" #include "git2/types.h" @@ -14,6 +14,7 @@ /** * @file git2/sys/config.h * @brief Git config backend routines + * @defgroup git_backend Git custom backend APIs * @ingroup Git * @{ */ diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h new file mode 100644 index 000000000..3cd2734c0 --- /dev/null +++ b/include/git2/sys/odb_backend.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sys_git_odb_backend_h__ +#define INCLUDE_sys_git_odb_backend_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" +#include "git2/odb.h" + +/** + * @file git2/sys/backend.h + * @brief Git custom backend implementors functions + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * An instance for a custom backend + */ +struct git_odb_backend { + unsigned int version; + git_odb *odb; + + /* read and read_prefix each return to libgit2 a buffer which + * will be freed later. The buffer should be allocated using + * the function git_odb_backend_malloc to ensure that it can + * be safely freed later. */ + int (* read)( + void **, size_t *, git_otype *, git_odb_backend *, const git_oid *); + + /* To find a unique object given a prefix + * of its oid. + * The oid given must be so that the + * remaining (GIT_OID_HEXSZ - len)*4 bits + * are 0s. + */ + int (* read_prefix)( + git_oid *, void **, size_t *, git_otype *, + git_odb_backend *, const git_oid *, size_t); + + int (* read_header)( + size_t *, git_otype *, git_odb_backend *, const git_oid *); + + /* The writer may assume that the object + * has already been hashed and is passed + * in the first parameter. + */ + int (* write)( + git_oid *, git_odb_backend *, const void *, size_t, git_otype); + + int (* writestream)( + git_odb_stream **, git_odb_backend *, size_t, git_otype); + + int (* readstream)( + git_odb_stream **, git_odb_backend *, const git_oid *); + + int (* exists)( + git_odb_backend *, const git_oid *); + + int (* refresh)(git_odb_backend *); + + int (* foreach)( + git_odb_backend *, git_odb_foreach_cb cb, void *payload); + + int (* writepack)( + git_odb_writepack **, git_odb_backend *, + git_transfer_progress_callback progress_cb, void *progress_payload); + + void (* free)(git_odb_backend *); +}; + +#define GIT_ODB_BACKEND_VERSION 1 +#define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} + +GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len); + +GIT_END_DECL + +#endif diff --git a/include/git2/types.h b/include/git2/types.h index bc15050ce..aca9ed927 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -196,6 +196,26 @@ typedef struct git_push git_push; typedef struct git_remote_head git_remote_head; typedef struct git_remote_callbacks git_remote_callbacks; +/** + * This is passed as the first argument to the callback to allow the + * user to see the progress. + */ +typedef struct git_transfer_progress { + unsigned int total_objects; + unsigned int indexed_objects; + unsigned int received_objects; + size_t received_bytes; +} git_transfer_progress; + +/** + * Type for progress callbacks during indexing. Return a value less than zero + * to cancel the transfer. + * + * @param stats Structure containing information about the state of the transfer + * @param payload Payload provided by caller + */ +typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); + /** @} */ GIT_END_DECL diff --git a/src/blob.c b/src/blob.c index c0514fc13..11e1f4d77 100644 --- a/src/blob.c +++ b/src/blob.c @@ -8,6 +8,7 @@ #include "git2/common.h" #include "git2/object.h" #include "git2/repository.h" +#include "git2/odb_backend.h" #include "common.h" #include "blob.h" diff --git a/src/odb.c b/src/odb.c index c98df247c..ecdaf7ac2 100644 --- a/src/odb.c +++ b/src/odb.c @@ -8,6 +8,7 @@ #include "common.h" #include #include "git2/object.h" +#include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" @@ -403,6 +404,27 @@ int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority) return add_backend_internal(odb, backend, priority, 1); } +size_t git_odb_num_backends(git_odb *odb) +{ + assert(odb); + return odb->backends.length; +} + +int git_odb_get_backend(git_odb_backend **out, git_odb *odb, size_t pos) +{ + backend_internal *internal; + + assert(odb && odb); + internal = git_vector_get(&odb->backends, pos); + + if (internal && internal->backend) { + *out = internal->backend; + return 0; + } + + return GIT_ENOTFOUND; +} + static int add_default_backends(git_odb *db, const char *objects_dir, int as_alternates, int alternate_depth) { git_odb_backend *loose, *packed; diff --git a/src/odb_loose.c b/src/odb_loose.c index 68083f7fd..e78172cf6 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -8,7 +8,7 @@ #include "common.h" #include #include "git2/object.h" -#include "git2/oid.h" +#include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" diff --git a/src/odb_pack.c b/src/odb_pack.c index 7240a4ac7..773e14974 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -8,7 +8,8 @@ #include "common.h" #include #include "git2/repository.h" -#include "git2/oid.h" +#include "git2/indexer.h" +#include "git2/sys/odb_backend.h" #include "fileops.h" #include "hash.h" #include "odb.h" diff --git a/src/tag.c b/src/tag.c index 735ba7e1d..c82decbe3 100644 --- a/src/tag.c +++ b/src/tag.c @@ -13,6 +13,7 @@ #include "git2/object.h" #include "git2/repository.h" #include "git2/signature.h" +#include "git2/odb_backend.h" void git_tag__free(git_tag *tag) { diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 8acedeb49..90851980c 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -5,6 +5,7 @@ * a Linking Exception. For full terms see the included COPYING file. */ #include "git2.h" +#include "git2/odb_backend.h" #include "smart.h" #include "refs.h" diff --git a/tests-clar/object/raw/write.c b/tests-clar/object/raw/write.c index 1b28d0df7..60aa31f6a 100644 --- a/tests-clar/object/raw/write.c +++ b/tests-clar/object/raw/write.c @@ -1,5 +1,6 @@ - #include "clar_libgit2.h" +#include "git2/odb_backend.h" + #include "fileops.h" #include "odb.h" diff --git a/tests-clar/odb/packed_one.c b/tests-clar/odb/packed_one.c index e9d246c23..4f9bde9ed 100644 --- a/tests-clar/odb/packed_one.c +++ b/tests-clar/odb/packed_one.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" -#include "odb.h" +#include "git2/odb_backend.h" + #include "pack_data_one.h" #include "pack.h" diff --git a/tests-clar/odb/sorting.c b/tests-clar/odb/sorting.c index b4f9e44bc..147a160c8 100644 --- a/tests-clar/odb/sorting.c +++ b/tests-clar/odb/sorting.c @@ -1,13 +1,12 @@ #include "clar_libgit2.h" -#include "git2/odb_backend.h" -#include "odb.h" +#include "git2/sys/odb_backend.h" typedef struct { git_odb_backend base; - int position; + size_t position; } fake_backend; -static git_odb_backend *new_backend(int position) +static git_odb_backend *new_backend(size_t position) { fake_backend *b; @@ -22,14 +21,13 @@ static git_odb_backend *new_backend(int position) static void check_backend_sorting(git_odb *odb) { - unsigned int i; - - for (i = 0; i < odb->backends.length; ++i) { - fake_backend *internal = - *((fake_backend **)git_vector_get(&odb->backends, i)); + size_t i, max_i = git_odb_num_backends(odb); + fake_backend *internal; + for (i = 0; i < max_i; ++i) { + cl_git_pass(git_odb_get_backend((git_odb_backend **)&internal, odb, i)); cl_assert(internal != NULL); - cl_assert(internal->position == (int)i); + cl_assert_equal_sz(i, internal->position); } } From 7cc3c9202722c53bf46e5a8f8d0d7180423a7632 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 29 Jan 2013 07:48:36 -0600 Subject: [PATCH 033/134] Added git_repository_new function --- include/git2/repository.h | 8 ++++++++ src/repository.c | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/include/git2/repository.h b/include/git2/repository.h index ed837b359..f55ab798f 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -136,6 +136,14 @@ GIT_EXTERN(int) git_repository_open_ext( */ GIT_EXTERN(int) git_repository_open_bare(git_repository **out, const char *bare_path); +/** + * Create a new repository with neither backends nor config object + * + * Note that this is only useful if you wish to associate the repository + * with a non-filesystem-backed object database and config store. + */ +GIT_EXTERN(int) git_repository_new(git_repository **out); + /** * Free a previously allocated repository * diff --git a/src/repository.c b/src/repository.c index 64ab2f4db..72b5a079a 100644 --- a/src/repository.c +++ b/src/repository.c @@ -129,6 +129,12 @@ static git_repository *repository_alloc(void) return repo; } +int git_repository_new(git_repository **out) +{ + *out = repository_alloc(); + return 0; +} + static int load_config_data(git_repository *repo) { int is_bare; From 1384b688d0bb5cd784c453fffef69d27e3db44ca Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 13:00:12 -0700 Subject: [PATCH 034/134] Move some low-level repo fns to include/git2/sys --- include/git2/repository.h | 70 ----------------------- include/git2/sys/repository.h | 92 +++++++++++++++++++++++++++++++ src/repository.c | 1 + tests-clar/diff/patch.c | 2 + tests-clar/repo/setters.c | 2 + tests-clar/status/worktree_init.c | 6 +- 6 files changed, 101 insertions(+), 72 deletions(-) create mode 100644 include/git2/sys/repository.h diff --git a/include/git2/repository.h b/include/git2/repository.h index f55ab798f..08024cd89 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -136,14 +136,6 @@ GIT_EXTERN(int) git_repository_open_ext( */ GIT_EXTERN(int) git_repository_open_bare(git_repository **out, const char *bare_path); -/** - * Create a new repository with neither backends nor config object - * - * Note that this is only useful if you wish to associate the repository - * with a non-filesystem-backed object database and config store. - */ -GIT_EXTERN(int) git_repository_new(git_repository **out); - /** * Free a previously allocated repository * @@ -408,21 +400,6 @@ GIT_EXTERN(int) git_repository_is_bare(git_repository *repo); */ GIT_EXTERN(int) git_repository_config(git_config **out, git_repository *repo); -/** - * Set the configuration file for this repository - * - * This configuration file will be used for all configuration - * queries involving this repository. - * - * The repository will keep a reference to the config file; - * the user must still free the config after setting it - * to the repository, or it will leak. - * - * @param repo A repository object - * @param config A Config object - */ -GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *config); - /** * Get the Object Database for this repository. * @@ -439,21 +416,6 @@ GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *con */ GIT_EXTERN(int) git_repository_odb(git_odb **out, git_repository *repo); -/** - * Set the Object Database for this repository - * - * The ODB will be used for all object-related operations - * involving this repository. - * - * The repository will keep a reference to the ODB; the user - * must still free the ODB object after setting it to the - * repository, or it will leak. - * - * @param repo A repository object - * @param odb An ODB object - */ -GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); - /** * Get the Reference Database Backend for this repository. * @@ -470,23 +432,6 @@ GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); */ GIT_EXTERN(int) git_repository_refdb(git_refdb **out, git_repository *repo); -/** - * Set the Reference Database Backend for this repository - * - * The refdb will be used for all reference related operations - * involving this repository. - * - * The repository will keep a reference to the refdb; the user - * must still free the refdb object after setting it to the - * repository, or it will leak. - * - * @param repo A repository object - * @param refdb An refdb object - */ -GIT_EXTERN(void) git_repository_set_refdb( - git_repository *repo, - git_refdb *refdb); - /** * Get the Index file for this repository. * @@ -503,21 +448,6 @@ GIT_EXTERN(void) git_repository_set_refdb( */ GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo); -/** - * Set the index file for this repository - * - * This index will be used for all index-related operations - * involving this repository. - * - * The repository will keep a reference to the index file; - * the user must still free the index after setting it - * to the repository, or it will leak. - * - * @param repo A repository object - * @param index An index object - */ -GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index); - /** * Retrieve git's prepared message * diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h new file mode 100644 index 000000000..34bc17516 --- /dev/null +++ b/include/git2/sys/repository.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sys_git_repository_h__ +#define INCLUDE_sys_git_repository_h__ + +/** + * @file git2/sys/repository.h + * @brief Git repository custom implementation routines + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Create a new repository with neither backends nor config object + * + * Note that this is only useful if you wish to associate the repository + * with a non-filesystem-backed object database and config store. + * + * @param out The blank repository + * @return 0 on success, or an error code + */ +GIT_EXTERN(int) git_repository_new(git_repository **out); + +/** + * Set the configuration file for this repository + * + * This configuration file will be used for all configuration + * queries involving this repository. + * + * The repository will keep a reference to the config file; + * the user must still free the config after setting it + * to the repository, or it will leak. + * + * @param repo A repository object + * @param config A Config object + */ +GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *config); + +/** + * Set the Object Database for this repository + * + * The ODB will be used for all object-related operations + * involving this repository. + * + * The repository will keep a reference to the ODB; the user + * must still free the ODB object after setting it to the + * repository, or it will leak. + * + * @param repo A repository object + * @param odb An ODB object + */ +GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); + +/** + * Set the Reference Database Backend for this repository + * + * The refdb will be used for all reference related operations + * involving this repository. + * + * The repository will keep a reference to the refdb; the user + * must still free the refdb object after setting it to the + * repository, or it will leak. + * + * @param repo A repository object + * @param refdb An refdb object + */ +GIT_EXTERN(void) git_repository_set_refdb(git_repository *repo, git_refdb *refdb); + +/** + * Set the index file for this repository + * + * This index will be used for all index-related operations + * involving this repository. + * + * The repository will keep a reference to the index file; + * the user must still free the index after setting it + * to the repository, or it will leak. + * + * @param repo A repository object + * @param index An index object + */ +GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index); + +/** @} */ +GIT_END_DECL +#endif diff --git a/src/repository.c b/src/repository.c index 72b5a079a..a16f69da4 100644 --- a/src/repository.c +++ b/src/repository.c @@ -9,6 +9,7 @@ #include "git2/object.h" #include "git2/refdb.h" +#include "git2/sys/repository.h" #include "common.h" #include "repository.h" diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c index 4d17da468..d41f3f12d 100644 --- a/tests-clar/diff/patch.c +++ b/tests-clar/diff/patch.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "git2/sys/repository.h" + #include "diff_helpers.h" #include "repository.h" #include "buf_text.h" diff --git a/tests-clar/repo/setters.c b/tests-clar/repo/setters.c index 7e482dee1..063d76c8d 100644 --- a/tests-clar/repo/setters.c +++ b/tests-clar/repo/setters.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "git2/sys/repository.h" + #include "buffer.h" #include "posix.h" #include "util.h" diff --git a/tests-clar/status/worktree_init.c b/tests-clar/status/worktree_init.c index b67107aec..296c27c86 100644 --- a/tests-clar/status/worktree_init.c +++ b/tests-clar/status/worktree_init.c @@ -1,4 +1,6 @@ #include "clar_libgit2.h" +#include "git2/sys/repository.h" + #include "fileops.h" #include "ignore.h" #include "status_helpers.h" @@ -321,10 +323,10 @@ void test_status_worktree_init__new_staged_file_must_handle_crlf(void) cl_set_cleanup(&cleanup_new_repo, "getting_started"); cl_git_pass(git_repository_init(&repo, "getting_started", 0)); - // Ensure that repo has core.autocrlf=true + /* Ensure that repo has core.autocrlf=true */ cl_repo_set_bool(repo, "core.autocrlf", true); - cl_git_mkfile("getting_started/testfile.txt", "content\r\n"); // Content with CRLF + 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_bypath(index, "testfile.txt")); From 9255039898bf4c625f678f390c8075c11d10cad0 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 29 Jan 2013 09:53:23 -0600 Subject: [PATCH 035/134] Added git_commit_create_oid --- include/git2/commit.h | 20 +++++++++++++++++ src/commit.c | 50 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/include/git2/commit.h b/include/git2/commit.h index 764053eaa..e7ef51816 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -287,6 +287,26 @@ GIT_EXTERN(int) git_commit_create_v( int parent_count, ...); +/** + * Create a new commit in the repository, as with `git_commit_create`, + * using `git_oid` instances as parameters instead of `git_object`. + * + * See documentation for `git_commit_create` for information about the + * parameters, as the meaning is identical excepting that `tree` and + * `parents` now take `git_oid`. + */ +GIT_EXTERN(int) git_commit_create_oid( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + int parent_count, + const git_oid *parents[]); + /** @} */ GIT_END_DECL #endif diff --git a/src/commit.c b/src/commit.c index c7b83ed43..e6bfd95ce 100644 --- a/src/commit.c +++ b/src/commit.c @@ -76,7 +76,7 @@ int git_commit_create_v( return res; } -int git_commit_create( +int git_commit_create_oid( git_oid *oid, git_repository *repo, const char *update_ref, @@ -84,22 +84,18 @@ int git_commit_create( const git_signature *committer, const char *message_encoding, const char *message, - const git_tree *tree, + const git_oid *tree, int parent_count, - const git_commit *parents[]) + const git_oid *parents[]) { git_buf commit = GIT_BUF_INIT; int i; git_odb *odb; - assert(git_object_owner((const git_object *)tree) == repo); + git_oid__writebuf(&commit, "tree ", tree); - git_oid__writebuf(&commit, "tree ", git_object_id((const git_object *)tree)); - - for (i = 0; i < parent_count; ++i) { - assert(git_object_owner((const git_object *)parents[i]) == repo); - git_oid__writebuf(&commit, "parent ", git_object_id((const git_object *)parents[i])); - } + for (i = 0; i < parent_count; ++i) + git_oid__writebuf(&commit, "parent ", parents[i]); git_signature__writebuf(&commit, "author ", author); git_signature__writebuf(&commit, "committer ", committer); @@ -131,6 +127,40 @@ on_error: return -1; } +int git_commit_create( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + const git_commit *parents[]) +{ + int retval, i; + const git_oid **parent_oids; + + assert(git_object_owner((const git_object *)tree) == repo); + + parent_oids = git__malloc(parent_count * sizeof(git_oid *)); + GITERR_CHECK_ALLOC(parent_oids); + + for (i = 0; i < parent_count; ++i) { + assert(git_object_owner((const git_object *)parents[i]) == repo); + parent_oids[i] = git_object_id((const git_object *)parents[i]); + } + + retval = git_commit_create_oid(oid, repo, update_ref, author, committer, + message_encoding, message, + git_object_id((const git_object *)tree), + parent_count, parent_oids); + + git__free((void *)parent_oids); + return retval; +} + int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) { const char *buffer = data; From 9233b3de4ea264a8ae846c784acc70c505022d8b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 13:17:29 -0700 Subject: [PATCH 036/134] Move git_commit_create_from_oids into sys/commit.h Actually this renames git_commit_create_oid to git_commit_create_from_oids and moves the API declaration to include/git2/sys/commit.h since it is a dangerous API for general use (because it doesn't check that the OID list items actually refer to real objects). --- include/git2/commit.h | 108 +++++++++++++++----------------------- include/git2/sys/commit.h | 45 ++++++++++++++++ src/commit.c | 81 ++++++++++++++-------------- 3 files changed, 129 insertions(+), 105 deletions(-) create mode 100644 include/git2/sys/commit.h diff --git a/include/git2/commit.h b/include/git2/commit.h index e7ef51816..0f7601252 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -201,14 +201,12 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor( unsigned int n); /** - * Create a new commit in the repository using `git_object` - * instances as parameters. + * Create new commit in the repository from a list of `git_object` pointers * - * The message will not be cleaned up. This can be achieved - * through `git_message_prettify()`. + * The message will not be cleaned up automatically. You can do that with + * the `git_message_prettify()` function. * - * @param id Pointer where to store the OID of the - * newly created commit + * @param id Pointer in which to store the OID of the newly created commit * * @param repo Repository where to store the commit * @@ -219,93 +217,69 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor( * make it point to this commit. If the reference doesn't * exist yet, it will be created. * - * @param author Signature representing the author and the authory - * time of this commit + * @param author Signature with author and author time of commit * - * @param committer Signature representing the committer and the - * commit time of this commit + * @param committer Signature with committer and * commit time of commit * * @param message_encoding The encoding for the message in the - * commit, represented with a standard encoding name. - * E.g. "UTF-8". If NULL, no encoding header is written and - * UTF-8 is assumed. + * commit, represented with a standard encoding name. + * E.g. "UTF-8". If NULL, no encoding header is written and + * UTF-8 is assumed. * * @param message Full message for this commit * * @param tree An instance of a `git_tree` object that will - * be used as the tree for the commit. This tree object must - * also be owned by the given `repo`. + * be used as the tree for the commit. This tree object must + * also be owned by the given `repo`. * * @param parent_count Number of parents for this commit * * @param parents[] Array of `parent_count` pointers to `git_commit` - * objects that will be used as the parents for this commit. This - * array may be NULL if `parent_count` is 0 (root commit). All the - * given commits must be owned by the `repo`. + * objects that will be used as the parents for this commit. This + * array may be NULL if `parent_count` is 0 (root commit). All the + * given commits must be owned by the `repo`. * * @return 0 or an error code * The created commit will be written to the Object Database and * the given reference will be updated to point to it */ GIT_EXTERN(int) git_commit_create( - git_oid *id, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - const git_commit *parents[]); + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + const git_commit *parents[]); /** - * Create a new commit in the repository using a variable - * argument list. + * Create new commit in the repository using a variable argument list. * - * The message will be cleaned up from excess whitespace - * it will be made sure that the last line ends with a '\n'. + * The message will be cleaned up from excess whitespace and it will be made + * sure that the last line ends with a '\n'. * - * The parents for the commit are specified as a variable - * list of pointers to `const git_commit *`. Note that this - * is a convenience method which may not be safe to export - * for certain languages or compilers + * The parents for the commit are specified as a variable list of pointers + * to `const git_commit *`. Note that this is a convenience method which may + * not be safe to export for certain languages or compilers * - * All other parameters remain the same + * All other parameters remain the same at `git_commit_create()`. * * @see git_commit_create */ GIT_EXTERN(int) git_commit_create_v( - git_oid *id, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - ...); - -/** - * Create a new commit in the repository, as with `git_commit_create`, - * using `git_oid` instances as parameters instead of `git_object`. - * - * See documentation for `git_commit_create` for information about the - * parameters, as the meaning is identical excepting that `tree` and - * `parents` now take `git_oid`. - */ -GIT_EXTERN(int) git_commit_create_oid( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_oid *tree, - int parent_count, - const git_oid *parents[]); + git_oid *id, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + ...); /** @} */ GIT_END_DECL diff --git a/include/git2/sys/commit.h b/include/git2/sys/commit.h new file mode 100644 index 000000000..096e028c5 --- /dev/null +++ b/include/git2/sys/commit.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sys_git_commit_h__ +#define INCLUDE_sys_git_commit_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" + +/** + * @file git2/sys/commit.h + * @brief Low-level Git commit creation + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** + * Create new commit in the repository from a list of `git_oid` values + * + * See documentation for `git_commit_create()` for information about the + * parameters, as the meaning is identical excepting that `tree` and + * `parents` now take `git_oid`. This is a dangerous API in that the + * `parents` list of `git_oid`s in not checked for validity. + */ +GIT_EXTERN(int) git_commit_create_from_oids( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + int parent_count, + const git_oid *parents[]); + +/** @} */ +GIT_END_DECL +#endif diff --git a/src/commit.c b/src/commit.c index e6bfd95ce..dd416920d 100644 --- a/src/commit.c +++ b/src/commit.c @@ -9,6 +9,7 @@ #include "git2/object.h" #include "git2/repository.h" #include "git2/signature.h" +#include "git2/sys/commit.h" #include "common.h" #include "odb.h" @@ -44,16 +45,16 @@ void git_commit__free(git_commit *commit) } int git_commit_create_v( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - ...) + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + ...) { va_list ap; int i, res; @@ -76,22 +77,25 @@ int git_commit_create_v( return res; } -int git_commit_create_oid( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_oid *tree, - int parent_count, - const git_oid *parents[]) +int git_commit_create_from_oids( + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_oid *tree, + int parent_count, + const git_oid *parents[]) { git_buf commit = GIT_BUF_INIT; int i; git_odb *odb; + assert(oid && repo && tree && parent_count >= 0); + assert(git_object_owner((const git_object *)tree) == repo); + git_oid__writebuf(&commit, "tree ", tree); for (i = 0; i < parent_count; ++i) @@ -128,21 +132,21 @@ on_error: } int git_commit_create( - git_oid *oid, - git_repository *repo, - const char *update_ref, - const git_signature *author, - const git_signature *committer, - const char *message_encoding, - const char *message, - const git_tree *tree, - int parent_count, - const git_commit *parents[]) + git_oid *oid, + git_repository *repo, + const char *update_ref, + const git_signature *author, + const git_signature *committer, + const char *message_encoding, + const char *message, + const git_tree *tree, + int parent_count, + const git_commit *parents[]) { - int retval, i; + int retval, i; const git_oid **parent_oids; - assert(git_object_owner((const git_object *)tree) == repo); + assert(parent_count >= 0); parent_oids = git__malloc(parent_count * sizeof(git_oid *)); GITERR_CHECK_ALLOC(parent_oids); @@ -152,13 +156,14 @@ int git_commit_create( parent_oids[i] = git_object_id((const git_object *)parents[i]); } - retval = git_commit_create_oid(oid, repo, update_ref, author, committer, - message_encoding, message, - git_object_id((const git_object *)tree), - parent_count, parent_oids); + retval = git_commit_create_from_oids( + oid, repo, update_ref, author, committer, + message_encoding, message, + git_object_id((const git_object *)tree), parent_count, parent_oids); git__free((void *)parent_oids); - return retval; + + return retval; } int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) From 4dcd87801972e1b880afa9cd0998842bae7af5b5 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 19 Apr 2013 17:17:44 -0700 Subject: [PATCH 037/134] Move refdb_backend to include/git2/sys This moves most of the refdb stuff over to the include/git2/sys directory, with some minor shifts in function organization. While I was making the necessary updates, I also removed the trailing whitespace in a few files that I modified just because I was there and it was bugging me. --- include/git2/refdb.h | 14 ------ include/git2/{ => sys}/refdb_backend.h | 18 ++++++-- src/refdb.c | 9 ++-- src/refdb_fs.c | 30 ++++++------- src/refs.c | 45 +++++++++---------- src/util.h | 2 + tests-clar/refdb/inmemory.c | 62 ++++++++++++++------------ tests-clar/refdb/testdb.c | 48 +++++++++----------- tests-clar/refdb/testdb.h | 5 +++ 9 files changed, 119 insertions(+), 114 deletions(-) rename include/git2/{ => sys}/refdb_backend.h (86%) diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 0e3ec5eaf..9278b1116 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -81,20 +81,6 @@ GIT_EXTERN(int) git_refdb_compress(git_refdb *refdb); */ GIT_EXTERN(void) git_refdb_free(git_refdb *refdb); -/** - * Sets the custom backend to an existing reference DB - * - * Read for more information. - * - * @param refdb database to add the backend to - * @param backend pointer to a git_refdb_backend instance - * @param priority Value for ordering the backends queue - * @return 0 on success; error code otherwise - */ -GIT_EXTERN(int) git_refdb_set_backend( - git_refdb *refdb, - git_refdb_backend *backend); - /** @} */ GIT_END_DECL diff --git a/include/git2/refdb_backend.h b/include/git2/sys/refdb_backend.h similarity index 86% rename from include/git2/refdb_backend.h rename to include/git2/sys/refdb_backend.h index 20eb6a9dd..dcdf7bcb8 100644 --- a/include/git2/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -7,9 +7,9 @@ #ifndef INCLUDE_git_refdb_backend_h__ #define INCLUDE_git_refdb_backend_h__ -#include "common.h" -#include "types.h" -#include "oid.h" +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" /** * @file git2/refdb_backend.h @@ -103,6 +103,18 @@ GIT_EXTERN(int) git_refdb_backend_fs( struct git_refdb_backend **backend_out, git_repository *repo); +/** + * Sets the custom backend to an existing reference DB + * + * @param refdb database to add the backend to + * @param backend pointer to a git_refdb_backend instance + * @param priority Value for ordering the backends queue + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_refdb_set_backend( + git_refdb *refdb, + git_refdb_backend *backend); + GIT_END_DECL #endif diff --git a/src/refdb.c b/src/refdb.c index 2a0fd702c..0675be638 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -7,15 +7,16 @@ #include "common.h" #include "posix.h" + #include "git2/object.h" #include "git2/refs.h" #include "git2/refdb.h" +#include "git2/sys/refdb_backend.h" + #include "hash.h" #include "refdb.h" #include "refs.h" -#include "git2/refdb_backend.h" - int git_refdb_new(git_refdb **out, git_repository *repo) { git_refdb *db; @@ -74,11 +75,11 @@ int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) int git_refdb_compress(git_refdb *db) { assert(db); - + if (db->backend->compress) { return db->backend->compress(db->backend); } - + return 0; } diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 56b2b6a99..4d5d6006d 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include GIT__USE_STRMAP; @@ -61,7 +61,7 @@ static int reference_read( /* Determine the full path of the file */ if (git_buf_joinpath(&path, repo_path, ref_name) < 0) return -1; - + result = git_futils_readbuffer_updated(file_content, path.ptr, mtime, NULL, updated); git_buf_free(&path); @@ -174,7 +174,7 @@ static int packed_load(refdb_fs_backend *backend) ref_cache->packfile = git_strmap_alloc(); GITERR_CHECK_ALLOC(ref_cache->packfile); } - + result = reference_read(&packfile, &ref_cache->packfile_time, backend->path, GIT_PACKEDREFS_FILE, &updated); @@ -192,7 +192,7 @@ static int packed_load(refdb_fs_backend *backend) if (result < 0) return -1; - + if (!updated) return 0; @@ -433,7 +433,7 @@ static int loose_lookup( } else { if ((error = loose_parse_oid(&oid, &ref_file)) < 0) goto done; - + *out = git_reference__alloc(ref_name, &oid, NULL); } @@ -455,19 +455,19 @@ static int packed_map_entry( if (packed_load(backend) < 0) return -1; - + /* Look up on the packfile */ packfile_refs = backend->refcache.packfile; *pos = git_strmap_lookup_index(packfile_refs, ref_name); - + if (!git_strmap_valid_index(packfile_refs, *pos)) { giterr_set(GITERR_REFERENCE, "Reference '%s' not found", ref_name); return GIT_ENOTFOUND; } *entry = git_strmap_value_at(packfile_refs, *pos); - + return 0; } @@ -479,14 +479,14 @@ static int packed_lookup( struct packref *entry; khiter_t pos; int error = 0; - + if ((error = packed_map_entry(&entry, &pos, backend, ref_name)) < 0) return error; if ((*out = git_reference__alloc(ref_name, &entry->oid, &entry->peel)) == NULL) return -1; - + return 0; } @@ -582,7 +582,7 @@ static int refdb_fs_backend__foreach( git_buf refs_path = GIT_BUF_INIT; const char *ref_name; void *ref = NULL; - + GIT_UNUSED(ref); assert(_backend); @@ -590,7 +590,7 @@ static int refdb_fs_backend__foreach( if (packed_load(backend) < 0) return -1; - + /* list all the packed references first */ if (list_type & GIT_REF_OID) { git_strmap_foreach(backend->refcache.packfile, ref_name, ref, { @@ -924,7 +924,7 @@ static int refdb_fs_backend__delete( repo = backend->repo; /* If a loose reference exists, remove it from the filesystem */ - + if (git_buf_joinpath(&loose_path, repo->path_repository, ref->name) < 0) return -1; @@ -932,7 +932,7 @@ static int refdb_fs_backend__delete( error = p_unlink(loose_path.ptr); loose_deleted = 1; } - + git_buf_free(&loose_path); if (error != 0) @@ -946,7 +946,7 @@ static int refdb_fs_backend__delete( error = packed_write(backend); } - + if (pack_error == GIT_ENOTFOUND) error = loose_deleted ? 0 : GIT_ENOTFOUND; else diff --git a/src/refs.c b/src/refs.c index 5b5812aae..d9291e56f 100644 --- a/src/refs.c +++ b/src/refs.c @@ -19,7 +19,6 @@ #include #include #include -#include GIT__USE_STRMAP; @@ -255,10 +254,10 @@ int git_reference_lookup_resolved( max_nesting = MAX_NESTING_LEVEL; else if (max_nesting < 0) max_nesting = DEFAULT_NESTING_LEVEL; - + strncpy(scan_name, name, GIT_REFNAME_MAX); scan_type = GIT_REF_SYMBOLIC; - + if ((error = git_repository_refdb__weakptr(&refdb, repo)) < 0) return -1; @@ -276,7 +275,7 @@ int git_reference_lookup_resolved( if ((error = git_refdb_lookup(&ref, refdb, scan_name)) < 0) return error; - + scan_type = ref->type; } @@ -354,7 +353,7 @@ static int reference__create( git_refdb *refdb; git_reference *ref = NULL; int error = 0; - + if (ref_out) *ref_out = NULL; @@ -369,7 +368,7 @@ static int reference__create( } else { ref = git_reference__alloc_symbolic(name, symbolic); } - + GITERR_CHECK_ALLOC(ref); ref->db = refdb; @@ -377,7 +376,7 @@ static int reference__create( git_reference_free(ref); return error; } - + if (ref_out == NULL) git_reference_free(ref); else @@ -397,17 +396,17 @@ int git_reference_create( int error = 0; assert(repo && name && oid); - + /* Sanity check the reference being created - target must exist. */ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; - + if (!git_odb_exists(odb, oid)) { giterr_set(GITERR_REFERENCE, "Target OID for the reference doesn't exist on the repository"); return -1; } - + return reference__create(ref_out, repo, name, oid, NULL, force); } @@ -422,7 +421,7 @@ int git_reference_symbolic_create( int error = 0; assert(repo && name && target); - + if ((error = git_reference__normalize_name_lax( normalized, sizeof(normalized), target)) < 0) return error; @@ -436,7 +435,7 @@ int git_reference_set_target( const git_oid *id) { assert(out && ref && id); - + if (ref->type != GIT_REF_OID) { giterr_set(GITERR_REFERENCE, "Cannot set OID on symbolic reference"); return -1; @@ -451,13 +450,13 @@ int git_reference_symbolic_set_target( const char *target) { assert(out && ref && target); - + if (ref->type != GIT_REF_SYMBOLIC) { giterr_set(GITERR_REFERENCE, "Cannot set symbolic target on a direct reference"); return -1; } - + return git_reference_symbolic_create(out, ref->db->repo, ref->name, target, 1); } @@ -473,7 +472,7 @@ int git_reference_rename( git_reference *result = NULL; int error = 0; int reference_has_log; - + *out = NULL; normalization_flags = ref->type == GIT_REF_SYMBOLIC ? @@ -488,7 +487,7 @@ int git_reference_rename( * Create the new reference. */ if (ref->type == GIT_REF_OID) { - result = git_reference__alloc(new_name, &ref->target.oid, &ref->peel); + result = git_reference__alloc(new_name, &ref->target.oid, &ref->peel); } else if (ref->type == GIT_REF_SYMBOLIC) { result = git_reference__alloc_symbolic(new_name, ref->target.symbolic); } else { @@ -509,11 +508,11 @@ int git_reference_rename( /* Now delete the old ref and save the new one. */ if ((error = git_refdb_delete(ref->db, ref)) < 0) goto on_error; - + /* Save the new reference. */ if ((error = git_refdb_write(ref->db, result)) < 0) goto rollback; - + /* Update HEAD it was poiting to the reference being renamed. */ if (should_head_be_updated && (error = git_repository_set_head(ref->db->repo, new_name)) < 0) { giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); @@ -547,7 +546,7 @@ int git_reference_resolve(git_reference **ref_out, const git_reference *ref) switch (git_reference_type(ref)) { case GIT_REF_OID: return git_reference_lookup(ref_out, ref->db->repo, ref->name); - + case GIT_REF_SYMBOLIC: return git_reference_lookup_resolved(ref_out, ref->db->repo, ref->target.symbolic, -1); @@ -846,7 +845,7 @@ static int reference__update_terminal( if (nesting > MAX_NESTING_LEVEL) return GIT_ENOTFOUND; - + error = git_reference_lookup(&ref, repo, ref_name); /* If we haven't found the reference at all, create a new reference. */ @@ -854,10 +853,10 @@ static int reference__update_terminal( giterr_clear(); return git_reference_create(NULL, repo, ref_name, oid, 0); } - + if (error < 0) return error; - + /* If the ref is a symbolic reference, follow its target. */ if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { error = reference__update_terminal(repo, git_reference_symbolic_target(ref), oid, @@ -867,7 +866,7 @@ static int reference__update_terminal( git_reference_free(ref); error = git_reference_create(NULL, repo, ref_name, oid, 1); } - + return error; } diff --git a/src/util.h b/src/util.h index c0f271997..af3ef0b46 100644 --- a/src/util.h +++ b/src/util.h @@ -7,6 +7,8 @@ #ifndef INCLUDE_util_h__ #define INCLUDE_util_h__ +#include "common.h" + #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define bitsizeof(x) (CHAR_BIT * sizeof(x)) #define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits)))) diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index ea76172cf..2c76d4192 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -1,12 +1,15 @@ #include "clar_libgit2.h" -#include "refdb.h" -#include "repository.h" + +#include "buffer.h" +#include "posix.h" +#include "path.h" +#include "refs.h" + #include "testdb.h" #define TEST_REPO_PATH "testrepo" static git_repository *repo; -static git_refdb_backend *refdb_backend; int unlink_ref(void *payload, git_buf *file) { @@ -26,7 +29,7 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi const char *repo_path; git_buf repo_refs_dir = GIT_BUF_INIT; int error = 0; - + repo_path = git_repository_path(repo); git_buf_joinpath(&repo_refs_dir, repo_path, "HEAD"); @@ -38,7 +41,7 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi git_buf_joinpath(&repo_refs_dir, git_buf_cstr(&repo_refs_dir), "heads"); if (git_path_direach(&repo_refs_dir, cb, NULL) != 0) return -1; - + git_buf_joinpath(&repo_refs_dir, repo_path, "packed-refs"); if (git_path_exists(git_buf_cstr(&repo_refs_dir)) && cb(NULL, &repo_refs_dir) < 0) @@ -51,16 +54,17 @@ int ref_file_foreach(git_repository *repo, int (* cb)(void *payload, git_buf *fi void test_refdb_inmemory__initialize(void) { - git_refdb *refdb; - git_buf repo_refs_dir = GIT_BUF_INIT; + git_refdb *refdb; + git_refdb_backend *refdb_backend; repo = cl_git_sandbox_init(TEST_REPO_PATH); cl_git_pass(git_repository_refdb(&refdb, repo)); cl_git_pass(refdb_backend_test(&refdb_backend, repo)); cl_git_pass(git_refdb_set_backend(refdb, refdb_backend)); - + git_refdb_free(refdb); + ref_file_foreach(repo, unlink_ref); git_buf_free(&repo_refs_dir); @@ -76,10 +80,10 @@ void test_refdb_inmemory__doesnt_write_ref_file(void) { git_reference *ref; git_oid oid; - + cl_git_pass(git_oid_fromstr(&oid, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_reference_create(&ref, repo, GIT_REFS_HEADS_DIR "test1", &oid, 0)); - + ref_file_foreach(repo, empty); git_reference_free(ref); @@ -89,10 +93,10 @@ void test_refdb_inmemory__read(void) { git_reference *write1, *write2, *write3, *read1, *read2, *read3; git_oid oid1, oid2, oid3; - + cl_git_pass(git_oid_fromstr(&oid1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_reference_create(&write1, repo, GIT_REFS_HEADS_DIR "test1", &oid1, 0)); - + cl_git_pass(git_oid_fromstr(&oid2, "e90810b8df3e80c413d903f631643c716887138d")); cl_git_pass(git_reference_create(&write2, repo, GIT_REFS_HEADS_DIR "test2", &oid2, 0)); @@ -139,7 +143,7 @@ int foreach_test(const char *ref_name, void *payload) cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0); ++(*i); - + git_reference_free(ref); return 0; @@ -150,19 +154,19 @@ void test_refdb_inmemory__foreach(void) git_reference *write1, *write2, *write3; git_oid oid1, oid2, oid3; size_t i = 0; - + cl_git_pass(git_oid_fromstr(&oid1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_reference_create(&write1, repo, GIT_REFS_HEADS_DIR "test1", &oid1, 0)); - + cl_git_pass(git_oid_fromstr(&oid2, "e90810b8df3e80c413d903f631643c716887138d")); cl_git_pass(git_reference_create(&write2, repo, GIT_REFS_HEADS_DIR "test2", &oid2, 0)); - + cl_git_pass(git_oid_fromstr(&oid3, "763d71aadf09a7951596c9746c024e7eece7c7af")); cl_git_pass(git_reference_create(&write3, repo, GIT_REFS_HEADS_DIR "test3", &oid3, 0)); - + cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, foreach_test, &i)); cl_assert_equal_i(3, (int)i); - + git_reference_free(write1); git_reference_free(write2); git_reference_free(write3); @@ -175,14 +179,14 @@ int delete_test(const char *ref_name, void *payload) size_t *i = payload; cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); - - cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d")); + + cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d")); cl_assert(git_oid_cmp(&expected, git_reference_target(ref)) == 0); - + ++(*i); - + git_reference_free(ref); - + return 0; } @@ -191,22 +195,22 @@ void test_refdb_inmemory__delete(void) git_reference *write1, *write2, *write3; git_oid oid1, oid2, oid3; size_t i = 0; - + cl_git_pass(git_oid_fromstr(&oid1, "c47800c7266a2be04c571c04d5a6614691ea99bd")); cl_git_pass(git_reference_create(&write1, repo, GIT_REFS_HEADS_DIR "test1", &oid1, 0)); - + cl_git_pass(git_oid_fromstr(&oid2, "e90810b8df3e80c413d903f631643c716887138d")); cl_git_pass(git_reference_create(&write2, repo, GIT_REFS_HEADS_DIR "test2", &oid2, 0)); - + cl_git_pass(git_oid_fromstr(&oid3, "763d71aadf09a7951596c9746c024e7eece7c7af")); cl_git_pass(git_reference_create(&write3, repo, GIT_REFS_HEADS_DIR "test3", &oid3, 0)); - + git_reference_delete(write1); git_reference_free(write1); - + git_reference_delete(write3); git_reference_free(write3); - + cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, delete_test, &i)); cl_assert_equal_i(1, (int)i); diff --git a/tests-clar/refdb/testdb.c b/tests-clar/refdb/testdb.c index 4bca39878..627254e44 100644 --- a/tests-clar/refdb/testdb.c +++ b/tests-clar/refdb/testdb.c @@ -1,14 +1,10 @@ -#include "common.h" #include "vector.h" #include "util.h" -#include -#include -#include -#include +#include "testdb.h" typedef struct refdb_test_backend { git_refdb_backend parent; - + git_repository *repo; git_vector refs; } refdb_test_backend; @@ -16,7 +12,7 @@ typedef struct refdb_test_backend { typedef struct refdb_test_entry { char *name; git_ref_t type; - + union { git_oid oid; char *symbolic; @@ -37,19 +33,19 @@ static int refdb_test_backend__exists( refdb_test_backend *backend; refdb_test_entry *entry; size_t i; - + assert(_backend); backend = (refdb_test_backend *)_backend; - + *exists = 0; - + git_vector_foreach(&backend->refs, i, entry) { if (strcmp(entry->name, ref_name) == 0) { *exists = 1; break; } } - + return 0; } @@ -59,18 +55,18 @@ static int refdb_test_backend__write( { refdb_test_backend *backend; refdb_test_entry *entry; - + assert(_backend); backend = (refdb_test_backend *)_backend; entry = git__calloc(1, sizeof(refdb_test_entry)); GITERR_CHECK_ALLOC(entry); - + entry->name = git__strdup(git_reference_name(ref)); GITERR_CHECK_ALLOC(entry->name); - + entry->type = git_reference_type(ref); - + if (entry->type == GIT_REF_OID) git_oid_cpy(&entry->target.oid, git_reference_target(ref)); else { @@ -79,7 +75,7 @@ static int refdb_test_backend__write( } git_vector_insert(&backend->refs, entry); - + return 0; } @@ -94,7 +90,7 @@ static int refdb_test_backend__lookup( assert(_backend); backend = (refdb_test_backend *)_backend; - + git_vector_foreach(&backend->refs, i, entry) { if (strcmp(entry->name, ref_name) == 0) { @@ -108,7 +104,7 @@ static int refdb_test_backend__lookup( if (*out == NULL) return -1; - + return 0; } } @@ -125,21 +121,21 @@ static int refdb_test_backend__foreach( refdb_test_backend *backend; refdb_test_entry *entry; size_t i; - + assert(_backend); backend = (refdb_test_backend *)_backend; git_vector_foreach(&backend->refs, i, entry) { if (entry->type == GIT_REF_OID && (list_flags & GIT_REF_OID) == 0) continue; - + if (entry->type == GIT_REF_SYMBOLIC && (list_flags & GIT_REF_SYMBOLIC) == 0) continue; - + if (callback(entry->name, payload) != 0) return GIT_EUSER; } - + return 0; } @@ -147,7 +143,7 @@ static void refdb_test_entry_free(refdb_test_entry *entry) { if (entry->type == GIT_REF_SYMBOLIC) git__free(entry->target.symbolic); - + git__free(entry->name); git__free(entry); } @@ -178,14 +174,14 @@ static void refdb_test_backend__free(git_refdb_backend *_backend) refdb_test_backend *backend; refdb_test_entry *entry; size_t i; - + assert(_backend); backend = (refdb_test_backend *)_backend; git_vector_foreach(&backend->refs, i, entry) refdb_test_entry_free(entry); - git_vector_free(&backend->refs); + git_vector_free(&backend->refs); git__free(backend); } @@ -197,7 +193,7 @@ int refdb_backend_test( backend = git__calloc(1, sizeof(refdb_test_backend)); GITERR_CHECK_ALLOC(backend); - + git_vector_init(&backend->refs, 0, ref_name_cmp); backend->repo = repo; diff --git a/tests-clar/refdb/testdb.h b/tests-clar/refdb/testdb.h index e38abd967..49d1cb1d0 100644 --- a/tests-clar/refdb/testdb.h +++ b/tests-clar/refdb/testdb.h @@ -1,3 +1,8 @@ +#include +#include +#include +#include + int refdb_backend_test( git_refdb_backend **backend_out, git_repository *repo); From 21ca045100337bcb2905a20a72d42721d18871f9 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Sun, 21 Apr 2013 12:52:17 -0700 Subject: [PATCH 038/134] Move git_reference__alloc to include/git2/sys Create a new include/git2/sys/refs.h and move the reference alloc functions there. Also fix some documentation issues and some minor code cleanups. --- include/git2/refdb.h | 19 ---------------- include/git2/sys/refdb_backend.h | 36 +++++++++++++++++++----------- include/git2/sys/refs.h | 38 ++++++++++++++++++++++++++++++++ src/refdb.c | 28 ++++++++++------------- src/refdb.h | 2 +- src/refdb_fs.c | 1 + src/refs.c | 4 ++-- tests-clar/refdb/inmemory.c | 1 - tests-clar/refdb/testdb.h | 1 + 9 files changed, 78 insertions(+), 52 deletions(-) create mode 100644 include/git2/sys/refs.h diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 9278b1116..a315876ae 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -21,25 +21,6 @@ */ GIT_BEGIN_DECL -/** - * Create a new reference. Either an oid or a symbolic target must be - * specified. - * - * @param refdb the reference database to associate with this reference - * @param name the reference name - * @param oid the object id for a direct reference - * @param symbolic the target for a symbolic reference - * @return the created git_reference or NULL on error - */ -GIT_EXTERN(git_reference *) git_reference__alloc( - const char *name, - const git_oid *oid, - const git_oid *peel); - -GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( - const char *name, - const char *target); - /** * Create a new reference database with no backends. * diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h index dcdf7bcb8..d5f599fec 100644 --- a/include/git2/sys/refdb_backend.h +++ b/include/git2/sys/refdb_backend.h @@ -4,8 +4,8 @@ * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ -#ifndef INCLUDE_git_refdb_backend_h__ -#define INCLUDE_git_refdb_backend_h__ +#ifndef INCLUDE_sys_git_refdb_backend_h__ +#define INCLUDE_sys_git_refdb_backend_h__ #include "git2/common.h" #include "git2/types.h" @@ -30,7 +30,7 @@ struct git_refdb_backend { */ int (*exists)( int *exists, - struct git_refdb_backend *backend, + git_refdb_backend *backend, const char *ref_name); /** @@ -39,7 +39,7 @@ struct git_refdb_backend { */ int (*lookup)( git_reference **out, - struct git_refdb_backend *backend, + git_refdb_backend *backend, const char *ref_name); /** @@ -47,7 +47,7 @@ struct git_refdb_backend { * provide this function. */ int (*foreach)( - struct git_refdb_backend *backend, + git_refdb_backend *backend, unsigned int list_flags, git_reference_foreach_cb callback, void *payload); @@ -59,7 +59,7 @@ struct git_refdb_backend { * against the glob. */ int (*foreach_glob)( - struct git_refdb_backend *backend, + git_refdb_backend *backend, const char *glob, unsigned int list_flags, git_reference_foreach_cb callback, @@ -69,13 +69,13 @@ struct git_refdb_backend { * Writes the given reference to the refdb. A refdb implementation * must provide this function. */ - int (*write)(struct git_refdb_backend *backend, const git_reference *ref); + int (*write)(git_refdb_backend *backend, const git_reference *ref); /** * Deletes the given reference from the refdb. A refdb implementation * must provide this function. */ - int (*delete)(struct git_refdb_backend *backend, const git_reference *ref); + int (*delete)(git_refdb_backend *backend, const git_reference *ref); /** * Suggests that the given refdb compress or optimize its references. @@ -84,31 +84,41 @@ struct git_refdb_backend { * implementation may provide this function; if it is not provided, * nothing will be done. */ - int (*compress)(struct git_refdb_backend *backend); + int (*compress)(git_refdb_backend *backend); /** * Frees any resources held by the refdb. A refdb implementation may * provide this function; if it is not provided, nothing will be done. */ - void (*free)(struct git_refdb_backend *backend); + void (*free)(git_refdb_backend *backend); }; #define GIT_ODB_BACKEND_VERSION 1 #define GIT_ODB_BACKEND_INIT {GIT_ODB_BACKEND_VERSION} /** - * Constructors for default refdb backends. + * Constructors for default filesystem-based refdb backend + * + * Under normal usage, this is called for you when the repository is + * opened / created, but you can use this to explicitly construct a + * filesystem refdb backend for a repository. + * + * @param backend_out Output pointer to the git_refdb_backend object + * @param repo Git repository to access + * @return 0 on success, <0 error code on failure */ GIT_EXTERN(int) git_refdb_backend_fs( - struct git_refdb_backend **backend_out, + git_refdb_backend **backend_out, git_repository *repo); /** * Sets the custom backend to an existing reference DB * + * The `git_refdb` will take ownership of the `git_refdb_backend` so you + * should NOT free it after calling this function. + * * @param refdb database to add the backend to * @param backend pointer to a git_refdb_backend instance - * @param priority Value for ordering the backends queue * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_refdb_set_backend( diff --git a/include/git2/sys/refs.h b/include/git2/sys/refs.h new file mode 100644 index 000000000..85963258c --- /dev/null +++ b/include/git2/sys/refs.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sys_git_refdb_h__ +#define INCLUDE_sys_git_refdb_h__ + +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" + +/** + * Create a new direct reference from an OID. + * + * @param name the reference name + * @param oid the object id for a direct reference + * @param symbolic the target for a symbolic reference + * @return the created git_reference or NULL on error + */ +GIT_EXTERN(git_reference *) git_reference__alloc( + const char *name, + const git_oid *oid, + const git_oid *peel); + +/** + * Create a new symbolic reference. + * + * @param name the reference name + * @param symbolic the target for a symbolic reference + * @return the created git_reference or NULL on error + */ +GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( + const char *name, + const char *target); + +#endif diff --git a/src/refdb.c b/src/refdb.c index 0675be638..33a1934d1 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -58,15 +58,19 @@ int git_refdb_open(git_refdb **out, git_repository *repo) return 0; } -int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) +static void refdb_free_backend(git_refdb *db) { if (db->backend) { - if(db->backend->free) + if (db->backend->free) db->backend->free(db->backend); else git__free(db->backend); } +} +int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend) +{ + refdb_free_backend(db); db->backend = backend; return 0; @@ -76,22 +80,15 @@ int git_refdb_compress(git_refdb *db) { assert(db); - if (db->backend->compress) { + if (db->backend->compress) return db->backend->compress(db->backend); - } return 0; } static void refdb_free(git_refdb *db) { - if (db->backend) { - if(db->backend->free) - db->backend->free(db->backend); - else - git__free(db->backend); - } - + refdb_free_backend(db); git__free(db); } @@ -115,14 +112,13 @@ int git_refdb_lookup(git_reference **out, git_refdb *db, const char *ref_name) git_reference *ref; int error; - assert(db && db->backend && ref_name); + assert(db && db->backend && out && ref_name); - *out = NULL; - - if ((error = db->backend->lookup(&ref, db->backend, ref_name)) == 0) - { + if (!(error = db->backend->lookup(&ref, db->backend, ref_name))) { ref->db = db; *out = ref; + } else { + *out = NULL; } return error; diff --git a/src/refdb.h b/src/refdb.h index 0969711b9..047113ac8 100644 --- a/src/refdb.h +++ b/src/refdb.h @@ -41,6 +41,6 @@ int git_refdb_foreach_glob( int git_refdb_write(git_refdb *refdb, const git_reference *ref); -int git_refdb_delete(struct git_refdb *refdb, const git_reference *ref); +int git_refdb_delete(git_refdb *refdb, const git_reference *ref); #endif diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 4d5d6006d..443871005 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -19,6 +19,7 @@ #include #include #include +#include GIT__USE_STRMAP; diff --git a/src/refs.c b/src/refs.c index d9291e56f..9c6684a5a 100644 --- a/src/refs.c +++ b/src/refs.c @@ -19,6 +19,7 @@ #include #include #include +#include GIT__USE_STRMAP; @@ -44,8 +45,7 @@ static git_reference *alloc_ref(const char *name) } git_reference *git_reference__alloc_symbolic( - const char *name, - const char *target) + const char *name, const char *target) { git_reference *ref; diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index 2c76d4192..243b5bb37 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -63,7 +63,6 @@ void test_refdb_inmemory__initialize(void) cl_git_pass(git_repository_refdb(&refdb, repo)); cl_git_pass(refdb_backend_test(&refdb_backend, repo)); cl_git_pass(git_refdb_set_backend(refdb, refdb_backend)); - git_refdb_free(refdb); ref_file_foreach(repo, unlink_ref); diff --git a/tests-clar/refdb/testdb.h b/tests-clar/refdb/testdb.h index 49d1cb1d0..a0d1bbc48 100644 --- a/tests-clar/refdb/testdb.h +++ b/tests-clar/refdb/testdb.h @@ -1,6 +1,7 @@ #include #include #include +#include #include int refdb_backend_test( From 0d4a5b13afc6c516212b194b238ab08d3362a041 Mon Sep 17 00:00:00 2001 From: Jasper Lievisse Adriaanse Date: Mon, 22 Apr 2013 00:13:35 +0200 Subject: [PATCH 039/134] Add missing prototype for p_realpath(). --- src/unix/posix.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/unix/posix.h b/src/unix/posix.h index f4886c5d1..9c9f837b9 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -21,6 +21,8 @@ /* The OpenBSD realpath function behaves differently */ #if !defined(__OpenBSD__) # define p_realpath(p, po) realpath(p, po) +#else +char *p_realpath(const char *, char *); #endif #define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) From 4ef2c79cb6dc81e17b68ccf7c270bcc7e4f85bfb Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 22 Apr 2013 16:37:40 +0200 Subject: [PATCH 040/134] odb: Disable inode checks for Win32 --- src/odb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/odb.c b/src/odb.c index 1c7969fcb..8249c5adc 100644 --- a/src/odb.c +++ b/src/odb.c @@ -415,6 +415,9 @@ static int add_default_backends( struct stat st; git_odb_backend *loose, *packed; + /* TODO: inodes are not really relevant on Win32, so we need to find + * a cross-platform workaround for this */ +#ifndef GIT_WIN32 if (p_stat(objects_dir, &st) < 0) { giterr_set(GITERR_ODB, "Failed to load object database in '%s'", objects_dir); return -1; @@ -425,6 +428,7 @@ static int add_default_backends( if (backend->disk_inode == st.st_ino) return 0; } +#endif /* add the loose object backend */ if (git_odb_backend_loose(&loose, objects_dir, -1, 0) < 0 || From 5df184241a6cfe88ac5ebcee9a3ad175abfca0cd Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 1 Apr 2013 19:38:23 +0200 Subject: [PATCH 041/134] lol this worked first try wtf --- src/cache.c | 187 ++++++++++++++++++++++++++--------------- src/cache.h | 33 ++++---- src/object.c | 54 +++++++----- src/odb.c | 36 ++++---- src/odb.h | 4 +- src/oidmap.h | 6 +- src/repository.c | 2 +- src/util.c | 8 -- tests-clar/core/opts.c | 11 --- 9 files changed, 193 insertions(+), 148 deletions(-) diff --git a/src/cache.c b/src/cache.c index e7f333577..6eb18dae5 100644 --- a/src/cache.c +++ b/src/cache.c @@ -11,100 +11,147 @@ #include "thread-utils.h" #include "util.h" #include "cache.h" +#include "odb.h" +#include "object.h" #include "git2/oid.h" -int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr) +GIT__USE_OIDMAP + +int git_cache_init(git_cache *cache) { - if (size < 8) - size = 8; - size = git__size_t_powerof2(size); - - cache->size_mask = size - 1; - cache->lru_count = 0; - cache->free_obj = free_ptr; - + cache->map = git_oidmap_alloc(); git_mutex_init(&cache->lock); - - cache->nodes = git__malloc(size * sizeof(git_cached_obj *)); - GITERR_CHECK_ALLOC(cache->nodes); - - memset(cache->nodes, 0x0, size * sizeof(git_cached_obj *)); return 0; } void git_cache_free(git_cache *cache) { - size_t i; - - for (i = 0; i < (cache->size_mask + 1); ++i) { - if (cache->nodes[i] != NULL) - git_cached_obj_decref(cache->nodes[i], cache->free_obj); - } - + git_oidmap_free(cache->map); git_mutex_free(&cache->lock); - git__free(cache->nodes); } -void *git_cache_get(git_cache *cache, const git_oid *oid) +static bool cache_should_store(git_cached_obj *entry) { - uint32_t hash; - git_cached_obj *node = NULL, *result = NULL; - - memcpy(&hash, oid->id, sizeof(hash)); - - if (git_mutex_lock(&cache->lock)) { - giterr_set(GITERR_THREAD, "unable to lock cache mutex"); - return NULL; - } - - { - node = cache->nodes[hash & cache->size_mask]; - - if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) { - git_cached_obj_incref(node); - result = node; - } - } - git_mutex_unlock(&cache->lock); - - return result; + return true; } -void *git_cache_try_store(git_cache *cache, void *_entry) +static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags) { - git_cached_obj *entry = _entry; - uint32_t hash; + khiter_t pos; + git_cached_obj *entry = NULL; - memcpy(&hash, &entry->oid, sizeof(uint32_t)); - - if (git_mutex_lock(&cache->lock)) { - giterr_set(GITERR_THREAD, "unable to lock cache mutex"); + if (git_mutex_lock(&cache->lock) < 0) return NULL; - } - { - git_cached_obj *node = cache->nodes[hash & cache->size_mask]; + pos = kh_get(oid, cache->map, oid); + if (pos != kh_end(cache->map)) { + entry = kh_val(cache->map, pos); - /* increase the refcount on this object, because - * the cache now owns it */ - git_cached_obj_incref(entry); - - if (node == NULL) { - cache->nodes[hash & cache->size_mask] = entry; - } else if (git_oid_cmp(&node->oid, &entry->oid) == 0) { - git_cached_obj_decref(entry, cache->free_obj); - entry = node; + if (flags && entry->flags != flags) { + entry = NULL; } else { - git_cached_obj_decref(node, cache->free_obj); - cache->nodes[hash & cache->size_mask] = entry; + git_cached_obj_incref(entry); } - - /* increase the refcount again, because we are - * returning it to the user */ - git_cached_obj_incref(entry); - } + git_mutex_unlock(&cache->lock); return entry; } + +static void *cache_store(git_cache *cache, git_cached_obj *entry) +{ + khiter_t pos; + + git_cached_obj_incref(entry); + + if (!cache_should_store(entry)) + return entry; + + if (git_mutex_lock(&cache->lock) < 0) + return entry; + + pos = kh_get(oid, cache->map, &entry->oid); + + /* not found */ + if (pos == kh_end(cache->map)) { + int rval; + + pos = kh_put(oid, cache->map, &entry->oid, &rval); + if (rval >= 0) { + kh_key(cache->map, pos) = &entry->oid; + kh_val(cache->map, pos) = entry; + git_cached_obj_incref(entry); + } + } + /* found */ + else { + git_cached_obj *stored_entry = kh_val(cache->map, pos); + + if (stored_entry->flags == entry->flags) { + git_cached_obj_decref(entry); + git_cached_obj_incref(stored_entry); + entry = stored_entry; + } else if (stored_entry->flags == GIT_CACHE_STORE_RAW && + entry->flags == GIT_CACHE_STORE_PARSED) { + git_cached_obj_decref(stored_entry); + git_cached_obj_incref(entry); + + kh_key(cache->map, pos) = &entry->oid; + kh_val(cache->map, pos) = entry; + } else { + /* NO OP */ + } + } + + git_mutex_unlock(&cache->lock); + return entry; +} + +void *git_cache_store_raw(git_cache *cache, git_odb_object *entry) +{ + entry->cached.flags = GIT_CACHE_STORE_RAW; + return cache_store(cache, (git_cached_obj *)entry); +} + +void *git_cache_store_parsed(git_cache *cache, git_object *entry) +{ + entry->cached.flags = GIT_CACHE_STORE_PARSED; + return cache_store(cache, (git_cached_obj *)entry); +} + +git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid) +{ + return cache_get(cache, oid, GIT_CACHE_STORE_RAW); +} + +git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid) +{ + return cache_get(cache, oid, GIT_CACHE_STORE_PARSED); +} + +void *git_cache_get_any(git_cache *cache, const git_oid *oid) +{ + return cache_get(cache, oid, GIT_CACHE_STORE_ANY); +} + +void git_cached_obj_decref(void *_obj) +{ + git_cached_obj *obj = _obj; + + if (git_atomic_dec(&obj->refcount) == 0) { + switch (obj->flags) { + case GIT_CACHE_STORE_RAW: + git_odb_object__free(_obj); + break; + + case GIT_CACHE_STORE_PARSED: + git_object__free(_obj); + break; + + default: + git__free(_obj); + break; + } + } +} diff --git a/src/cache.h b/src/cache.h index 7034ec268..f30af9c3e 100644 --- a/src/cache.h +++ b/src/cache.h @@ -12,30 +12,35 @@ #include "git2/odb.h" #include "thread-utils.h" +#include "oidmap.h" -#define GIT_DEFAULT_CACHE_SIZE 128 - -typedef void (*git_cached_obj_freeptr)(void *); +enum { + GIT_CACHE_STORE_ANY = 0, + GIT_CACHE_STORE_RAW = 1, + GIT_CACHE_STORE_PARSED = 2 +}; typedef struct { git_oid oid; git_atomic refcount; + uint32_t flags; } git_cached_obj; typedef struct { - git_cached_obj **nodes; + git_oidmap *map; git_mutex lock; - unsigned int lru_count; - size_t size_mask; - git_cached_obj_freeptr free_obj; } git_cache; -int git_cache_init(git_cache *cache, size_t size, git_cached_obj_freeptr free_ptr); +int git_cache_init(git_cache *cache); void git_cache_free(git_cache *cache); -void *git_cache_try_store(git_cache *cache, void *entry); -void *git_cache_get(git_cache *cache, const git_oid *oid); +void *git_cache_store_raw(git_cache *cache, git_odb_object *entry); +void *git_cache_store_parsed(git_cache *cache, git_object *entry); + +git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid); +git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid); +void *git_cache_get_any(git_cache *cache, const git_oid *oid); GIT_INLINE(void) git_cached_obj_incref(void *_obj) { @@ -43,12 +48,6 @@ GIT_INLINE(void) git_cached_obj_incref(void *_obj) git_atomic_inc(&obj->refcount); } -GIT_INLINE(void) git_cached_obj_decref(void *_obj, git_cached_obj_freeptr free_obj) -{ - git_cached_obj *obj = _obj; - - if (git_atomic_dec(&obj->refcount) == 0) - free_obj(obj); -} +void git_cached_obj_decref(void *_obj); #endif diff --git a/src/object.c b/src/object.c index 80fe51152..5542ebc8e 100644 --- a/src/object.c +++ b/src/object.c @@ -121,12 +121,13 @@ int git_object__from_odb_object( break; } - if (error < 0) + if (error < 0) { git_object__free(object); - else - *object_out = git_cache_try_store(&repo->objects, object); + return error; + } - return error; + *object_out = git_cache_store_parsed(&repo->objects, object); + return 0; } int git_object_lookup_prefix( @@ -154,27 +155,38 @@ int git_object_lookup_prefix( len = GIT_OID_HEXSZ; if (len == GIT_OID_HEXSZ) { + git_cached_obj *cached = NULL; + /* We want to match the full id : we can first look up in the cache, * since there is no need to check for non ambiguousity */ - object = git_cache_get(&repo->objects, id); - if (object != NULL) { - if (type != GIT_OBJ_ANY && type != object->type) { - git_object_free(object); - giterr_set(GITERR_INVALID, "The requested type does not match the type in ODB"); - return GIT_ENOTFOUND; + cached = git_cache_get_any(&repo->objects, id); + if (cached != NULL) { + if (cached->flags == GIT_CACHE_STORE_PARSED) { + object = (git_object *)cached; + + if (type != GIT_OBJ_ANY && type != object->type) { + git_object_free(object); + giterr_set(GITERR_INVALID, + "The requested type does not match the type in ODB"); + return GIT_ENOTFOUND; + } + + *object_out = object; + return 0; + } else if (cached->flags == GIT_CACHE_STORE_RAW) { + odb_obj = (git_odb_object *)cached; + } else { + assert(!"Wrong caching type in the global object cache"); } - - *object_out = object; - return 0; + } else { + /* Object was not found in the cache, let's explore the backends. + * We could just use git_odb_read_unique_short_oid, + * it is the same cost for packed and loose object backends, + * but it may be much more costly for sqlite and hiredis. + */ + error = git_odb_read(&odb_obj, odb, id); } - - /* Object was not found in the cache, let's explore the backends. - * We could just use git_odb_read_unique_short_oid, - * it is the same cost for packed and loose object backends, - * but it may be much more costly for sqlite and hiredis. - */ - error = git_odb_read(&odb_obj, odb, id); } else { git_oid short_oid; @@ -245,7 +257,7 @@ void git_object_free(git_object *object) if (object == NULL) return; - git_cached_obj_decref((git_cached_obj *)object, git_object__free); + git_cached_obj_decref(object); } const git_oid *git_object_id(const git_object *obj) diff --git a/src/odb.c b/src/odb.c index d6ea8c29a..821fbd70c 100644 --- a/src/odb.c +++ b/src/odb.c @@ -14,6 +14,7 @@ #include "odb.h" #include "delta-apply.h" #include "filter.h" +#include "repository.h" #include "git2/odb_backend.h" #include "git2/oid.h" @@ -34,7 +35,15 @@ typedef struct ino_t disk_inode; } backend_internal; -size_t git_odb__cache_size = GIT_DEFAULT_CACHE_SIZE; +static git_cache *odb_cache(git_odb *odb) +{ + if (odb->rc.owner != NULL) { + git_repository *owner = odb->rc.owner; + return &owner->objects; + } + + return &odb->own_cache; +} static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_depth); @@ -83,10 +92,8 @@ static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source) return object; } -static void free_odb_object(void *o) +void git_odb_object__free(git_odb_object *object) { - git_odb_object *object = (git_odb_object *)o; - if (object != NULL) { git__free(object->raw.data); git__free(object); @@ -118,7 +125,7 @@ void git_odb_object_free(git_odb_object *object) if (object == NULL) return; - git_cached_obj_decref((git_cached_obj *)object, &free_odb_object); + git_cached_obj_decref(object); } int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type) @@ -355,9 +362,8 @@ int git_odb_new(git_odb **out) git_odb *db = git__calloc(1, sizeof(*db)); GITERR_CHECK_ALLOC(db); - if (git_cache_init(&db->cache, git_odb__cache_size, &free_odb_object) < 0 || - git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) - { + if (git_cache_init(&db->own_cache) < 0 || + git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) { git__free(db); return -1; } @@ -559,7 +565,7 @@ static void odb_free(git_odb *db) } git_vector_free(&db->backends); - git_cache_free(&db->cache); + git_cache_free(&db->own_cache); git__free(db); } @@ -580,7 +586,7 @@ int git_odb_exists(git_odb *db, const git_oid *id) assert(db && id); - if ((object = git_cache_get(&db->cache, id)) != NULL) { + if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { git_odb_object_free(object); return (int)true; } @@ -630,7 +636,7 @@ int git_odb__read_header_or_object( assert(db && id && out && len_p && type_p); - if ((object = git_cache_get(&db->cache, id)) != NULL) { + if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { *len_p = object->raw.len; *type_p = object->raw.type; *out = object; @@ -678,7 +684,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) return GIT_ENOTFOUND; } - *out = git_cache_get(&db->cache, id); + *out = git_cache_get_raw(odb_cache(db), id); if (*out != NULL) return 0; @@ -704,7 +710,7 @@ attempt_lookup: if (error && error != GIT_PASSTHROUGH) return error; - *out = git_cache_try_store(&db->cache, new_odb_object(id, &raw)); + *out = git_cache_store_raw(odb_cache(db), new_odb_object(id, &raw)); return 0; } @@ -727,7 +733,7 @@ int git_odb_read_prefix( len = GIT_OID_HEXSZ; if (len == GIT_OID_HEXSZ) { - *out = git_cache_get(&db->cache, short_id); + *out = git_cache_get_raw(odb_cache(db), short_id); if (*out != NULL) return 0; } @@ -768,7 +774,7 @@ attempt_lookup: if (!found) return git_odb__error_notfound("no match for prefix", short_id); - *out = git_cache_try_store(&db->cache, new_odb_object(&found_full_oid, &raw)); + *out = git_cache_store_raw(odb_cache(db), new_odb_object(&found_full_oid, &raw)); return 0; } diff --git a/src/odb.h b/src/odb.h index 7c018cc50..9abf594e8 100644 --- a/src/odb.h +++ b/src/odb.h @@ -36,9 +36,11 @@ struct git_odb_object { struct git_odb { git_refcount rc; git_vector backends; - git_cache cache; + git_cache own_cache; }; +void git_odb_object__free(git_odb_object *object); + /* * Hash a git_rawobj internally. * The `git_rawobj` is supposed to be previously initialized diff --git a/src/oidmap.h b/src/oidmap.h index 40274cd19..dfa951af3 100644 --- a/src/oidmap.h +++ b/src/oidmap.h @@ -21,10 +21,8 @@ typedef khash_t(oid) git_oidmap; GIT_INLINE(khint_t) hash_git_oid(const git_oid *oid) { - int i; - khint_t h = 0; - for (i = 0; i < 20; ++i) - h = (h << 5) - h + oid->id[i]; + khint_t h; + memcpy(&h, oid, sizeof(khint_t)); return h; } diff --git a/src/repository.c b/src/repository.c index a16f69da4..cda75b85f 100644 --- a/src/repository.c +++ b/src/repository.c @@ -119,7 +119,7 @@ static git_repository *repository_alloc(void) memset(repo, 0x0, sizeof(git_repository)); - if (git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free) < 0) { + if (git_cache_init(&repo->objects) < 0) { git__free(repo); return NULL; } diff --git a/src/util.c b/src/util.c index 8e83d298e..c4a8c786d 100644 --- a/src/util.c +++ b/src/util.c @@ -93,14 +93,6 @@ int git_libgit2_opts(int key, ...) if ((error = config_level_to_futils_dir(va_arg(ap, int))) >= 0) error = git_futils_dirs_set(error, va_arg(ap, const char *)); break; - - case GIT_OPT_GET_ODB_CACHE_SIZE: - *(va_arg(ap, size_t *)) = git_odb__cache_size; - break; - - case GIT_OPT_SET_ODB_CACHE_SIZE: - git_odb__cache_size = va_arg(ap, size_t); - break; } va_end(ap); diff --git a/tests-clar/core/opts.c b/tests-clar/core/opts.c index 907339d51..3173c648b 100644 --- a/tests-clar/core/opts.c +++ b/tests-clar/core/opts.c @@ -16,15 +16,4 @@ void test_core_opts__readwrite(void) git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &new_val); cl_assert(new_val == old_val); - - git_libgit2_opts(GIT_OPT_GET_ODB_CACHE_SIZE, &old_val); - - cl_assert(old_val == GIT_DEFAULT_CACHE_SIZE); - - git_libgit2_opts(GIT_OPT_SET_ODB_CACHE_SIZE, (size_t)GIT_DEFAULT_CACHE_SIZE*2); - git_libgit2_opts(GIT_OPT_GET_ODB_CACHE_SIZE, &new_val); - - cl_assert(new_val == (GIT_DEFAULT_CACHE_SIZE*2)); - - git_libgit2_opts(GIT_OPT_GET_ODB_CACHE_SIZE, &old_val); } From 6b90e244de78640b751d0923c91c3868e12b8658 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 1 Apr 2013 19:53:49 +0200 Subject: [PATCH 042/134] Per-object filtering --- src/cache.c | 37 +++++++++++++++++++++++++++++++------ src/cache.h | 3 ++- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/cache.c b/src/cache.c index 6eb18dae5..a0925a188 100644 --- a/src/cache.c +++ b/src/cache.c @@ -17,8 +17,22 @@ GIT__USE_OIDMAP +bool git_cache__store_types[8] = { + false, /* GIT_OBJ__EXT1 */ + true, /* GIT_OBJ_COMMIT */ + true, /* GIT_OBJ_TREE */ + false, /* GIT_OBJ_BLOB */ + true, /* GIT_OBJ_TAG */ + false, /* GIT_OBJ__EXT2 */ + false, /* GIT_OBJ_OFS_DELTA */ + false /* GIT_OBJ_REF_DELTA */ +}; + +size_t git_cache__max_object_size = 4096; + int git_cache_init(git_cache *cache) { + cache->lru_count = 0; cache->map = git_oidmap_alloc(); git_mutex_init(&cache->lock); return 0; @@ -30,8 +44,14 @@ void git_cache_free(git_cache *cache) git_mutex_free(&cache->lock); } -static bool cache_should_store(git_cached_obj *entry) +static bool cache_should_store(git_otype object_type, size_t object_size) { + if (!git_cache__store_types[object_type]) + return false; + + if (object_size > git_cache__max_object_size) + return false; + return true; } @@ -63,11 +83,6 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) { khiter_t pos; - git_cached_obj_incref(entry); - - if (!cache_should_store(entry)) - return entry; - if (git_mutex_lock(&cache->lock) < 0) return entry; @@ -110,12 +125,22 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) void *git_cache_store_raw(git_cache *cache, git_odb_object *entry) { + git_cached_obj_incref(entry); + + if (!cache_should_store(entry->raw.type, entry->raw.len)) + return entry; + entry->cached.flags = GIT_CACHE_STORE_RAW; return cache_store(cache, (git_cached_obj *)entry); } void *git_cache_store_parsed(git_cache *cache, git_object *entry) { + git_cached_obj_incref(entry); + + if (!cache_should_store(entry->type, 0 /* TODO */)) + return entry; + entry->cached.flags = GIT_CACHE_STORE_PARSED; return cache_store(cache, (git_cached_obj *)entry); } diff --git a/src/cache.h b/src/cache.h index f30af9c3e..3461ff7d5 100644 --- a/src/cache.h +++ b/src/cache.h @@ -23,7 +23,8 @@ enum { typedef struct { git_oid oid; git_atomic refcount; - uint32_t flags; + uint16_t flags; + uint16_t lru; } git_cached_obj; typedef struct { From c4e91d4500bdd357fbf7378bc10648a482513fa6 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 3 Apr 2013 20:57:30 +0200 Subject: [PATCH 043/134] Random eviction --- src/cache.c | 19 ++++++++++++++++++- src/cache.h | 5 ++--- src/object.c | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/cache.c b/src/cache.c index a0925a188..f49515ef3 100644 --- a/src/cache.c +++ b/src/cache.c @@ -32,7 +32,6 @@ size_t git_cache__max_object_size = 4096; int git_cache_init(git_cache *cache) { - cache->lru_count = 0; cache->map = git_oidmap_alloc(); git_mutex_init(&cache->lock); return 0; @@ -44,6 +43,24 @@ void git_cache_free(git_cache *cache) git_mutex_free(&cache->lock); } +static void cache_evict_entries(git_cache *cache, size_t evict) +{ + uint32_t seed = rand(); + + /* do not infinite loop if there's not enough entries to evict */ + if (evict > kh_size(cache->map)) + return; + + while (evict > 0) { + khiter_t pos = seed++ % kh_end(cache->map); + + if (kh_exist(cache->map, pos)) { + kh_del(oid, cache->map, pos); + evict--; + } + } +} + static bool cache_should_store(git_otype object_type, size_t object_size) { if (!git_cache__store_types[object_type]) diff --git a/src/cache.h b/src/cache.h index 3461ff7d5..f952830c5 100644 --- a/src/cache.h +++ b/src/cache.h @@ -23,14 +23,13 @@ enum { typedef struct { git_oid oid; git_atomic refcount; - uint16_t flags; - uint16_t lru; + uint32_t cache_size; + uint32_t flags; } git_cached_obj; typedef struct { git_oidmap *map; git_mutex lock; - unsigned int lru_count; } git_cache; int git_cache_init(git_cache *cache); diff --git a/src/object.c b/src/object.c index 5542ebc8e..54ceea33c 100644 --- a/src/object.c +++ b/src/object.c @@ -98,6 +98,7 @@ int git_object__from_odb_object( /* Initialize parent object */ git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); + object->cached.cache_size = (uint32_t)odb_obj->raw.len; object->repo = repo; switch (type) { From 8842c75f172ed94be4ad11521d4083e97d740785 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 3 Apr 2013 22:30:07 +0200 Subject: [PATCH 044/134] What has science done. --- src/blob.c | 10 +++++----- src/cache.c | 4 ++-- src/cache.h | 5 +++-- src/checkout.c | 4 ++-- src/commit.c | 2 +- src/commit_list.c | 15 +++++++++------ src/object.c | 9 +++++---- src/odb.c | 21 ++++++++++++--------- src/odb.h | 2 +- src/tag.c | 4 ++-- src/tree.c | 4 +++- tests-clar/diff/workdir.c | 3 ++- tests-clar/object/raw/write.c | 8 +++++++- tests-clar/odb/loose.c | 7 ++++++- tests-clar/odb/packed.c | 8 ++++---- tests-clar/odb/packed_one.c | 4 ++-- 16 files changed, 66 insertions(+), 44 deletions(-) diff --git a/src/blob.c b/src/blob.c index 11e1f4d77..7dce4f7ee 100644 --- a/src/blob.c +++ b/src/blob.c @@ -18,19 +18,19 @@ const void *git_blob_rawcontent(const git_blob *blob) { assert(blob); - return blob->odb_object->raw.data; + return blob->odb_object->buffer; } git_off_t git_blob_rawsize(const git_blob *blob) { assert(blob); - return (git_off_t)blob->odb_object->raw.len; + return (git_off_t)blob->odb_object->cached.size; } int git_blob__getbuf(git_buf *buffer, git_blob *blob) { return git_buf_set( - buffer, blob->odb_object->raw.data, blob->odb_object->raw.len); + buffer, blob->odb_object->buffer, blob->odb_object->cached.size); } void git_blob__free(git_blob *blob) @@ -315,8 +315,8 @@ int git_blob_is_binary(git_blob *blob) assert(blob); - content.ptr = blob->odb_object->raw.data; - content.size = min(blob->odb_object->raw.len, 4000); + content.ptr = blob->odb_object->buffer; + content.size = min(blob->odb_object->cached.size, 4000); return git_buf_text_is_binary(&content); } diff --git a/src/cache.c b/src/cache.c index f49515ef3..316007bdf 100644 --- a/src/cache.c +++ b/src/cache.c @@ -144,7 +144,7 @@ void *git_cache_store_raw(git_cache *cache, git_odb_object *entry) { git_cached_obj_incref(entry); - if (!cache_should_store(entry->raw.type, entry->raw.len)) + if (!cache_should_store(entry->cached.type, entry->cached.size)) return entry; entry->cached.flags = GIT_CACHE_STORE_RAW; @@ -155,7 +155,7 @@ void *git_cache_store_parsed(git_cache *cache, git_object *entry) { git_cached_obj_incref(entry); - if (!cache_should_store(entry->type, 0 /* TODO */)) + if (!cache_should_store(entry->cached.type, entry->cached.size)) return entry; entry->cached.flags = GIT_CACHE_STORE_PARSED; diff --git a/src/cache.h b/src/cache.h index f952830c5..3633f62a7 100644 --- a/src/cache.h +++ b/src/cache.h @@ -22,9 +22,10 @@ enum { typedef struct { git_oid oid; - git_atomic refcount; - uint32_t cache_size; + int32_t type; + size_t size; uint32_t flags; + git_atomic refcount; } git_cached_obj; typedef struct { diff --git a/src/checkout.c b/src/checkout.c index 81dc5e3da..bb2f90606 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -710,8 +710,8 @@ static int blob_content_to_file( git_vector filters = GIT_VECTOR_INIT; /* Create a fake git_buf from the blob raw data... */ - filtered.ptr = blob->odb_object->raw.data; - filtered.size = blob->odb_object->raw.len; + filtered.ptr = blob->odb_object->buffer; + filtered.size = blob->odb_object->cached.size; /* ... and make sure it doesn't get unexpectedly freed */ dont_free_filtered = true; diff --git a/src/commit.c b/src/commit.c index dd416920d..2057364b5 100644 --- a/src/commit.c +++ b/src/commit.c @@ -244,7 +244,7 @@ bad_buffer: int git_commit__parse(git_commit *commit, git_odb_object *obj) { assert(commit); - return git_commit__parse_buffer(commit, obj->raw.data, obj->raw.len); + return git_commit__parse_buffer(commit, obj->buffer, obj->cached.size); } #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \ diff --git a/src/commit_list.c b/src/commit_list.c index 603dd754a..baabbbafb 100644 --- a/src/commit_list.c +++ b/src/commit_list.c @@ -100,12 +100,15 @@ git_commit_list_node *git_commit_list_pop(git_commit_list **stack) return item; } -static int commit_quick_parse(git_revwalk *walk, git_commit_list_node *commit, git_rawobj *raw) +static int commit_quick_parse( + git_revwalk *walk, + git_commit_list_node *commit, + uint8_t *buffer, + size_t buffer_len) { const size_t parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1; - unsigned char *buffer = raw->data; - unsigned char *buffer_end = buffer + raw->len; - unsigned char *parents_start, *committer_start; + uint8_t *buffer_end = buffer + buffer_len; + uint8_t *parents_start, *committer_start; int i, parents = 0; int commit_time; @@ -182,11 +185,11 @@ int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit) if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < 0) return error; - if (obj->raw.type != GIT_OBJ_COMMIT) { + if (obj->cached.type != GIT_OBJ_COMMIT) { giterr_set(GITERR_INVALID, "Object is no commit object"); error = -1; } else - error = commit_quick_parse(walk, commit, &obj->raw); + error = commit_quick_parse(walk, commit, obj->buffer, obj->cached.size); git_odb_object_free(obj); return error; diff --git a/src/object.c b/src/object.c index 54ceea33c..2667fcaf1 100644 --- a/src/object.c +++ b/src/object.c @@ -86,19 +86,20 @@ int git_object__from_odb_object( int error; git_object *object = NULL; - if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) { - giterr_set(GITERR_INVALID, "The requested type does not match the type in the ODB"); + if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) { + giterr_set(GITERR_INVALID, + "The requested type does not match the type in the ODB"); return GIT_ENOTFOUND; } - type = odb_obj->raw.type; + type = odb_obj->cached.type; if ((error = create_object(&object, type)) < 0) return error; /* Initialize parent object */ git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); - object->cached.cache_size = (uint32_t)odb_obj->raw.len; + object->cached.size = odb_obj->cached.size; object->repo = repo; switch (type) { diff --git a/src/odb.c b/src/odb.c index 821fbd70c..16a842aa8 100644 --- a/src/odb.c +++ b/src/odb.c @@ -65,6 +65,7 @@ int git_odb__hashobj(git_oid *id, git_rawobj *obj) if (!git_object_typeisloose(obj->type)) return -1; + if (!obj->data && obj->len != 0) return -1; @@ -87,7 +88,9 @@ static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source) memset(object, 0x0, sizeof(git_odb_object)); git_oid_cpy(&object->cached.oid, oid); - memcpy(&object->raw, source, sizeof(git_rawobj)); + object->cached.size = source->len; + object->cached.type = source->type; + object->buffer = source->data; return object; } @@ -95,7 +98,7 @@ static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source) void git_odb_object__free(git_odb_object *object) { if (object != NULL) { - git__free(object->raw.data); + git__free(object->buffer); git__free(object); } } @@ -107,17 +110,17 @@ const git_oid *git_odb_object_id(git_odb_object *object) const void *git_odb_object_data(git_odb_object *object) { - return object->raw.data; + return object->buffer; } size_t git_odb_object_size(git_odb_object *object) { - return object->raw.len; + return object->cached.size; } git_otype git_odb_object_type(git_odb_object *object) { - return object->raw.type; + return object->cached.type; } void git_odb_object_free(git_odb_object *object) @@ -637,8 +640,8 @@ int git_odb__read_header_or_object( assert(db && id && out && len_p && type_p); if ((object = git_cache_get_raw(odb_cache(db), id)) != NULL) { - *len_p = object->raw.len; - *type_p = object->raw.type; + *len_p = object->cached.size; + *type_p = object->cached.type; *out = object; return 0; } @@ -663,8 +666,8 @@ int git_odb__read_header_or_object( if ((error = git_odb_read(&object, db, id)) < 0) return error; /* error already set - pass along */ - *len_p = object->raw.len; - *type_p = object->raw.type; + *len_p = object->cached.size; + *type_p = object->cached.type; *out = object; return 0; diff --git a/src/odb.h b/src/odb.h index 9abf594e8..22c6e1668 100644 --- a/src/odb.h +++ b/src/odb.h @@ -29,7 +29,7 @@ typedef struct { /* EXPORT */ struct git_odb_object { git_cached_obj cached; - git_rawobj raw; + void *buffer; }; /* EXPORT */ diff --git a/src/tag.c b/src/tag.c index c82decbe3..3095d1287 100644 --- a/src/tag.c +++ b/src/tag.c @@ -324,7 +324,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu if (git_odb_read(&target_obj, odb, &tag.target) < 0) goto on_error; - if (tag.type != target_obj->raw.type) { + if (tag.type != target_obj->cached.type) { giterr_set(GITERR_TAG, "The type for the given target is invalid"); goto on_error; } @@ -397,7 +397,7 @@ int git_tag_delete(git_repository *repo, const char *tag_name) int git_tag__parse(git_tag *tag, git_odb_object *obj) { assert(tag); - return git_tag__parse_buffer(tag, obj->raw.data, obj->raw.len); + return git_tag__parse_buffer(tag, obj->buffer, obj->cached.size); } typedef struct { diff --git a/src/tree.c b/src/tree.c index d2db84055..6ffb07c69 100644 --- a/src/tree.c +++ b/src/tree.c @@ -419,7 +419,9 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf int git_tree__parse(git_tree *tree, git_odb_object *obj) { assert(tree); - return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len); + return tree_parse_buffer(tree, + (char *)obj->buffer, + (char *)obj->buffer + obj->cached.size); } static size_t find_next_dir(const char *dirname, git_index *index, size_t start) diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c index 9d92d8d60..435bd4f2c 100644 --- a/tests-clar/diff/workdir.c +++ b/tests-clar/diff/workdir.c @@ -908,7 +908,6 @@ void test_diff_workdir__can_diff_empty_file(void) /* baseline - make sure there are no outstanding diffs */ cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); - git_tree_free(tree); cl_assert_equal_i(2, (int)git_diff_num_deltas(diff)); git_diff_list_free(diff); @@ -935,6 +934,8 @@ void test_diff_workdir__can_diff_empty_file(void) cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 1)); git_diff_patch_free(patch); git_diff_list_free(diff); + + git_tree_free(tree); } void test_diff_workdir__to_index_issue_1397(void) diff --git a/tests-clar/object/raw/write.c b/tests-clar/object/raw/write.c index 60aa31f6a..9709c0302 100644 --- a/tests-clar/object/raw/write.c +++ b/tests-clar/object/raw/write.c @@ -63,6 +63,7 @@ void test_body(object_data *d, git_rawobj *o) git_odb *db; git_oid id1, id2; git_odb_object *obj; + git_rawobj tmp; make_odb_dir(); cl_git_pass(git_odb_open(&db, odb_dir)); @@ -73,7 +74,12 @@ void test_body(object_data *d, git_rawobj *o) check_object_files(d); cl_git_pass(git_odb_read(&obj, db, &id1)); - cmp_objects(&obj->raw, o); + + tmp.data = obj->buffer; + tmp.len = obj->cached.size; + tmp.type = obj->cached.type; + + cmp_objects(&tmp, o); git_odb_object_free(obj); git_odb_free(db); diff --git a/tests-clar/odb/loose.c b/tests-clar/odb/loose.c index f95dc28d4..9539bb24c 100644 --- a/tests-clar/odb/loose.c +++ b/tests-clar/odb/loose.c @@ -30,6 +30,7 @@ static void test_read_object(object_data *data) git_oid id; git_odb_object *obj; git_odb *odb; + git_rawobj tmp; write_object_files(data); @@ -37,7 +38,11 @@ static void test_read_object(object_data *data) cl_git_pass(git_oid_fromstr(&id, data->id)); cl_git_pass(git_odb_read(&obj, odb, &id)); - cmp_objects((git_rawobj *)&obj->raw, data); + tmp.data = obj->buffer; + tmp.len = obj->cached.size; + tmp.type = obj->cached.type; + + cmp_objects(&tmp, data); git_odb_object_free(obj); git_odb_free(odb); diff --git a/tests-clar/odb/packed.c b/tests-clar/odb/packed.c index 90e9f3abd..b4f549b58 100644 --- a/tests-clar/odb/packed.c +++ b/tests-clar/odb/packed.c @@ -46,8 +46,8 @@ void test_odb_packed__read_header_0(void) cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); - cl_assert(obj->raw.len == len); - cl_assert(obj->raw.type == type); + cl_assert(obj->cached.size == len); + cl_assert(obj->cached.type == type); git_odb_object_free(obj); } @@ -70,8 +70,8 @@ void test_odb_packed__read_header_1(void) cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); - cl_assert(obj->raw.len == len); - cl_assert(obj->raw.type == type); + cl_assert(obj->cached.size == len); + cl_assert(obj->cached.type == type); git_odb_object_free(obj); } diff --git a/tests-clar/odb/packed_one.c b/tests-clar/odb/packed_one.c index 4f9bde9ed..0c6ed387b 100644 --- a/tests-clar/odb/packed_one.c +++ b/tests-clar/odb/packed_one.c @@ -52,8 +52,8 @@ void test_odb_packed_one__read_header_0(void) cl_git_pass(git_odb_read(&obj, _odb, &id)); cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); - cl_assert(obj->raw.len == len); - cl_assert(obj->raw.type == type); + cl_assert(obj->cached.size == len); + cl_assert(obj->cached.type == type); git_odb_object_free(obj); } From cf7850a4f70a1153ed640744750391d99000d546 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 3 Apr 2013 23:09:54 +0200 Subject: [PATCH 045/134] Duplicated type object --- src/cache.h | 4 ++-- src/object.c | 15 ++++++--------- src/object.h | 1 - 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/cache.h b/src/cache.h index 3633f62a7..d57f244dd 100644 --- a/src/cache.h +++ b/src/cache.h @@ -22,9 +22,9 @@ enum { typedef struct { git_oid oid; - int32_t type; + int16_t type; + uint16_t flags; size_t size; - uint32_t flags; git_atomic refcount; } git_cached_obj; diff --git a/src/object.c b/src/object.c index 2667fcaf1..80b765ef9 100644 --- a/src/object.c +++ b/src/object.c @@ -71,8 +71,6 @@ static int create_object(git_object **object_out, git_otype type) return -1; } - object->type = type; - *object_out = object; return 0; } @@ -92,17 +90,16 @@ int git_object__from_odb_object( return GIT_ENOTFOUND; } - type = odb_obj->cached.type; - - if ((error = create_object(&object, type)) < 0) + if ((error = create_object(&object, odb_obj->cached.type)) < 0) return error; /* Initialize parent object */ git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); object->cached.size = odb_obj->cached.size; + object->cached.type = odb_obj->cached.type; object->repo = repo; - switch (type) { + switch (object->cached.type) { case GIT_OBJ_COMMIT: error = git_commit__parse((git_commit *)object, odb_obj); break; @@ -167,7 +164,7 @@ int git_object_lookup_prefix( if (cached->flags == GIT_CACHE_STORE_PARSED) { object = (git_object *)cached; - if (type != GIT_OBJ_ANY && type != object->type) { + if (type != GIT_OBJ_ANY && type != object->cached.type) { git_object_free(object); giterr_set(GITERR_INVALID, "The requested type does not match the type in ODB"); @@ -231,7 +228,7 @@ void git_object__free(void *_obj) assert(object); - switch (object->type) { + switch (object->cached.type) { case GIT_OBJ_COMMIT: git_commit__free((git_commit *)object); break; @@ -271,7 +268,7 @@ const git_oid *git_object_id(const git_object *obj) git_otype git_object_type(const git_object *obj) { assert(obj); - return obj->type; + return obj->cached.type; } git_repository *git_object_owner(const git_object *obj) diff --git a/src/object.h b/src/object.h index c1e50593c..d187c55b7 100644 --- a/src/object.h +++ b/src/object.h @@ -11,7 +11,6 @@ struct git_object { git_cached_obj cached; git_repository *repo; - git_otype type; }; /* fully free the object; internal method, DO NOT EXPORT */ From 064236ca45067c9a7189e0d30790b8f3541b91ad Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 3 Apr 2013 23:39:42 +0200 Subject: [PATCH 046/134] Per-object max size --- src/cache.c | 56 ++++++++++++++++++++++++++--------------------------- src/cache.h | 1 + 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/cache.c b/src/cache.c index 316007bdf..c6e983597 100644 --- a/src/cache.c +++ b/src/cache.c @@ -17,21 +17,20 @@ GIT__USE_OIDMAP -bool git_cache__store_types[8] = { - false, /* GIT_OBJ__EXT1 */ - true, /* GIT_OBJ_COMMIT */ - true, /* GIT_OBJ_TREE */ - false, /* GIT_OBJ_BLOB */ - true, /* GIT_OBJ_TAG */ - false, /* GIT_OBJ__EXT2 */ - false, /* GIT_OBJ_OFS_DELTA */ - false /* GIT_OBJ_REF_DELTA */ +size_t git_cache__max_object_size[8] = { + 0, /* GIT_OBJ__EXT1 */ + 4096, /* GIT_OBJ_COMMIT */ + 4096, /* GIT_OBJ_TREE */ + 0, /* GIT_OBJ_BLOB */ + 4096, /* GIT_OBJ_TAG */ + 0, /* GIT_OBJ__EXT2 */ + 0, /* GIT_OBJ_OFS_DELTA */ + 0 /* GIT_OBJ_REF_DELTA */ }; -size_t git_cache__max_object_size = 4096; - int git_cache_init(git_cache *cache) { + cache->used_memory = 0; cache->map = git_oidmap_alloc(); git_mutex_init(&cache->lock); return 0; @@ -43,30 +42,35 @@ void git_cache_free(git_cache *cache) git_mutex_free(&cache->lock); } -static void cache_evict_entries(git_cache *cache, size_t evict) +/* Call with lock, yo */ +static void cache_evict_entries(git_cache *cache, size_t evict_count) { uint32_t seed = rand(); /* do not infinite loop if there's not enough entries to evict */ - if (evict > kh_size(cache->map)) + if (evict_count > kh_size(cache->map)) return; - while (evict > 0) { + while (evict_count > 0) { khiter_t pos = seed++ % kh_end(cache->map); if (kh_exist(cache->map, pos)) { + git_cached_obj *evict = kh_val(cache->map, pos); + + evict_count--; + cache->used_memory -= evict->size; + git_cached_obj_decref(evict); + kh_del(oid, cache->map, pos); - evict--; } } } static bool cache_should_store(git_otype object_type, size_t object_size) { - if (!git_cache__store_types[object_type]) - return false; + size_t max_size = git_cache__max_object_size[object_type]; - if (object_size > git_cache__max_object_size) + if (max_size == 0 || object_size > max_size) return false; return true; @@ -100,6 +104,11 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) { khiter_t pos; + git_cached_obj_incref(entry); + + if (!cache_should_store(entry->type, entry->size)) + return entry; + if (git_mutex_lock(&cache->lock) < 0) return entry; @@ -114,6 +123,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) kh_key(cache->map, pos) = &entry->oid; kh_val(cache->map, pos) = entry; git_cached_obj_incref(entry); + cache->used_memory += entry->size; } } /* found */ @@ -142,22 +152,12 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) void *git_cache_store_raw(git_cache *cache, git_odb_object *entry) { - git_cached_obj_incref(entry); - - if (!cache_should_store(entry->cached.type, entry->cached.size)) - return entry; - entry->cached.flags = GIT_CACHE_STORE_RAW; return cache_store(cache, (git_cached_obj *)entry); } void *git_cache_store_parsed(git_cache *cache, git_object *entry) { - git_cached_obj_incref(entry); - - if (!cache_should_store(entry->cached.type, entry->cached.size)) - return entry; - entry->cached.flags = GIT_CACHE_STORE_PARSED; return cache_store(cache, (git_cached_obj *)entry); } diff --git a/src/cache.h b/src/cache.h index d57f244dd..65a6e5766 100644 --- a/src/cache.h +++ b/src/cache.h @@ -31,6 +31,7 @@ typedef struct { typedef struct { git_oidmap *map; git_mutex lock; + size_t used_memory; } git_cache; int git_cache_init(git_cache *cache); From d9d423e4215ac3cc17def7b1a353d03031b811f8 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 3 Apr 2013 23:53:32 +0200 Subject: [PATCH 047/134] Some stats --- src/cache.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/cache.c b/src/cache.c index c6e983597..f3ab8a684 100644 --- a/src/cache.c +++ b/src/cache.c @@ -28,6 +28,27 @@ size_t git_cache__max_object_size[8] = { 0 /* GIT_OBJ_REF_DELTA */ }; +void git_cache_dump_stats(git_cache *cache) +{ + git_cached_obj *object; + + if (kh_size(cache->map) == 0) + return; + + printf("Cache %p: %d items cached, %d bytes\n", + cache, kh_size(cache->map), (int)cache->used_memory); + + kh_foreach_value(cache->map, object, { + char oid_str[9]; + printf(" %s%c %s (%d)\n", + git_object_type2string(object->type), + object->flags == GIT_CACHE_STORE_PARSED ? '*' : ' ', + git_oid_tostr(oid_str, sizeof(oid_str), &object->oid), + (int)object->size + ); + }); +} + int git_cache_init(git_cache *cache) { cache->used_memory = 0; From e16e268457ab4ab8a4edc8153deca2c8c22dc757 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 4 Apr 2013 02:09:32 +0200 Subject: [PATCH 048/134] No longer needed --- include/git2/common.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 5318e66b7..b8c3e42ce 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -131,8 +131,6 @@ enum { GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, GIT_OPT_GET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH, - GIT_OPT_GET_ODB_CACHE_SIZE, - GIT_OPT_SET_ODB_CACHE_SIZE, }; /** @@ -169,15 +167,6 @@ enum { * - `level` must be GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_GLOBAL, * or GIT_CONFIG_LEVEL_XDG. * - * opts(GIT_OPT_GET_ODB_CACHE_SIZE): - * Get the size of the libgit2 odb cache. - * - * opts(GIT_OPT_SET_ODB_CACHE_SIZE): - * Set the size of the of the libgit2 odb cache. This needs - * to be done before git_repository_open is called, since - * git_repository_open initializes the odb layer. Defaults - * to 128. - * * @param option Option key * @param ... value to set the option * @return 0 on success, <0 on failure From e183e375b83044d7852b8253553c4f782d73c140 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 5 Apr 2013 22:38:14 +0200 Subject: [PATCH 049/134] Clear the cache when there are too many items to expire --- src/cache.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/cache.c b/src/cache.c index f3ab8a684..9f3290f01 100644 --- a/src/cache.c +++ b/src/cache.c @@ -63,14 +63,33 @@ void git_cache_free(git_cache *cache) git_mutex_free(&cache->lock); } +void git_cache_clear(git_cache *cache) +{ + git_cached_obj *evict = NULL; + + if (git_mutex_lock(&cache->lock) < 0) + return; + + kh_foreach_value(cache->map, evict, { + git_cached_obj_decref(evict); + }); + + kh_clear(oid, cache->map); + cache->used_memory = 0; + + git_mutex_unlock(&cache->lock); +} + /* Call with lock, yo */ static void cache_evict_entries(git_cache *cache, size_t evict_count) { uint32_t seed = rand(); /* do not infinite loop if there's not enough entries to evict */ - if (evict_count > kh_size(cache->map)) + if (evict_count > kh_size(cache->map)) { + git_cache_clear(cache); return; + } while (evict_count > 0) { khiter_t pos = seed++ % kh_end(cache->map); From ee12272d170d6a9d60f13d6de6129f56bfb2fbf6 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 5 Apr 2013 22:48:39 +0200 Subject: [PATCH 050/134] Global option setters --- include/git2/common.h | 2 ++ src/cache.c | 10 ++++------ src/cache.h | 3 +++ src/util.c | 11 +++++++++++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index b8c3e42ce..80d83d345 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -131,6 +131,8 @@ enum { GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, GIT_OPT_GET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH, + GIT_OPT_SET_CACHE_LIMIT, + GIT_OPT_ENABLE_CACHING }; /** diff --git a/src/cache.c b/src/cache.c index 9f3290f01..f8cddeaca 100644 --- a/src/cache.c +++ b/src/cache.c @@ -17,6 +17,8 @@ GIT__USE_OIDMAP +bool git_cache__enabled = true; + size_t git_cache__max_object_size[8] = { 0, /* GIT_OBJ__EXT1 */ 4096, /* GIT_OBJ_COMMIT */ @@ -109,11 +111,7 @@ static void cache_evict_entries(git_cache *cache, size_t evict_count) static bool cache_should_store(git_otype object_type, size_t object_size) { size_t max_size = git_cache__max_object_size[object_type]; - - if (max_size == 0 || object_size > max_size) - return false; - - return true; + return git_cache__enabled && object_size < max_size; } static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags) @@ -121,7 +119,7 @@ static void *cache_get(git_cache *cache, const git_oid *oid, unsigned int flags) khiter_t pos; git_cached_obj *entry = NULL; - if (git_mutex_lock(&cache->lock) < 0) + if (!git_cache__enabled || git_mutex_lock(&cache->lock) < 0) return NULL; pos = kh_get(oid, cache->map, oid); diff --git a/src/cache.h b/src/cache.h index 65a6e5766..8b2aa1f79 100644 --- a/src/cache.h +++ b/src/cache.h @@ -20,6 +20,9 @@ enum { GIT_CACHE_STORE_PARSED = 2 }; +extern bool git_cache__enabled; +extern size_t git_cache__max_object_size[8]; + typedef struct { git_oid oid; int16_t type; diff --git a/src/util.c b/src/util.c index c4a8c786d..0b5fbdc5a 100644 --- a/src/util.c +++ b/src/util.c @@ -11,6 +11,7 @@ #include #include "posix.h" #include "fileops.h" +#include "cache.h" #ifdef _MSC_VER # include @@ -93,6 +94,16 @@ int git_libgit2_opts(int key, ...) if ((error = config_level_to_futils_dir(va_arg(ap, int))) >= 0) error = git_futils_dirs_set(error, va_arg(ap, const char *)); break; + + case GIT_OPT_SET_CACHE_LIMIT: { + git_otype type = (git_otype)va_arg(ap, int); + git_cache__max_object_size[type] = va_arg(ap, size_t); + break; + } + + case GIT_OPT_ENABLE_CACHING: + git_cache__enabled = va_arg(ap, int); + break; } va_end(ap); From badd85a61354ef7b62c5f8e53d740738e5ef1e57 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Wed, 10 Apr 2013 17:10:17 -0700 Subject: [PATCH 051/134] Use git_odb_object_data/_size whereever possible This uses the odb object accessors so we can change the internals more easily... --- src/blob.c | 8 +++++--- src/checkout.c | 4 ++-- src/commit.c | 3 ++- src/commit_list.c | 13 ++++++++----- src/tag.c | 3 ++- src/tree.c | 14 +++++++++----- 6 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/blob.c b/src/blob.c index 7dce4f7ee..732b0f3de 100644 --- a/src/blob.c +++ b/src/blob.c @@ -18,19 +18,21 @@ const void *git_blob_rawcontent(const git_blob *blob) { assert(blob); - return blob->odb_object->buffer; + return git_odb_object_data(blob->odb_object); } git_off_t git_blob_rawsize(const git_blob *blob) { assert(blob); - return (git_off_t)blob->odb_object->cached.size; + return (git_off_t)git_odb_object_size(blob->odb_object); } int git_blob__getbuf(git_buf *buffer, git_blob *blob) { return git_buf_set( - buffer, blob->odb_object->buffer, blob->odb_object->cached.size); + buffer, + git_odb_object_data(blob->odb_object), + git_odb_object_size(blob->odb_object)); } void git_blob__free(git_blob *blob) diff --git a/src/checkout.c b/src/checkout.c index bb2f90606..62a73d6d0 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -710,8 +710,8 @@ static int blob_content_to_file( git_vector filters = GIT_VECTOR_INIT; /* Create a fake git_buf from the blob raw data... */ - filtered.ptr = blob->odb_object->buffer; - filtered.size = blob->odb_object->cached.size; + filtered.ptr = (void *)git_blob_rawcontent(blob); + filtered.size = (size_t)git_blob_rawsize(blob); /* ... and make sure it doesn't get unexpectedly freed */ dont_free_filtered = true; diff --git a/src/commit.c b/src/commit.c index 2057364b5..2cee44cd2 100644 --- a/src/commit.c +++ b/src/commit.c @@ -244,7 +244,8 @@ bad_buffer: int git_commit__parse(git_commit *commit, git_odb_object *obj) { assert(commit); - return git_commit__parse_buffer(commit, obj->buffer, obj->cached.size); + return git_commit__parse_buffer( + commit, git_odb_object_data(obj), git_odb_object_size(obj)); } #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \ diff --git a/src/commit_list.c b/src/commit_list.c index baabbbafb..bd5b5201a 100644 --- a/src/commit_list.c +++ b/src/commit_list.c @@ -103,12 +103,12 @@ git_commit_list_node *git_commit_list_pop(git_commit_list **stack) static int commit_quick_parse( git_revwalk *walk, git_commit_list_node *commit, - uint8_t *buffer, + const uint8_t *buffer, size_t buffer_len) { const size_t parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1; - uint8_t *buffer_end = buffer + buffer_len; - uint8_t *parents_start, *committer_start; + const uint8_t *buffer_end = buffer + buffer_len; + const uint8_t *parents_start, *committer_start; int i, parents = 0; int commit_time; @@ -127,7 +127,7 @@ static int commit_quick_parse( for (i = 0; i < parents; ++i) { git_oid oid; - if (git_oid_fromstr(&oid, (char *)buffer + strlen("parent ")) < 0) + if (git_oid_fromstr(&oid, (const char *)buffer + strlen("parent ")) < 0) return -1; commit->parents[i] = git_revwalk__commit_lookup(walk, &oid); @@ -189,7 +189,10 @@ int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit) giterr_set(GITERR_INVALID, "Object is no commit object"); error = -1; } else - error = commit_quick_parse(walk, commit, obj->buffer, obj->cached.size); + error = commit_quick_parse( + walk, commit, + (const uint8_t *)git_odb_object_data(obj), + git_odb_object_size(obj)); git_odb_object_free(obj); return error; diff --git a/src/tag.c b/src/tag.c index 3095d1287..b76895d0c 100644 --- a/src/tag.c +++ b/src/tag.c @@ -397,7 +397,8 @@ int git_tag_delete(git_repository *repo, const char *tag_name) int git_tag__parse(git_tag *tag, git_odb_object *obj) { assert(tag); - return git_tag__parse_buffer(tag, obj->buffer, obj->cached.size); + return git_tag__parse_buffer( + tag, git_odb_object_data(obj), git_odb_object_size(obj)); } typedef struct { diff --git a/src/tree.c b/src/tree.c index 6ffb07c69..cc43b920c 100644 --- a/src/tree.c +++ b/src/tree.c @@ -371,7 +371,8 @@ static int tree_error(const char *str, const char *path) return -1; } -static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buffer_end) +static int tree_parse_buffer( + git_tree *tree, const char *buffer, const char *buffer_end) { if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) return -1; @@ -418,10 +419,13 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf int git_tree__parse(git_tree *tree, git_odb_object *obj) { - assert(tree); - return tree_parse_buffer(tree, - (char *)obj->buffer, - (char *)obj->buffer + obj->cached.size); + const char *buf; + + assert(tree && obj); + + buf = (const char *)git_odb_object_data(obj); + + return tree_parse_buffer(tree, buf, buf + git_odb_object_size(obj)); } static size_t find_next_dir(const char *dirname, git_index *index, size_t start) From b12b72ea82776bbbd4296eeac1376055b0487edf Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 12 Apr 2013 12:44:51 -0700 Subject: [PATCH 052/134] Add range checking around cache opts Add a git_cache_set_max_object_size method that does more checking around setting the max object size. Also add a git_cache_size to read the number of objects currently in the cache. This makes it easier to write tests. --- src/cache.c | 23 +++++++++++++++++------ src/cache.h | 12 +++++++++--- src/util.c | 8 +++++--- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/cache.c b/src/cache.c index f8cddeaca..263f736fa 100644 --- a/src/cache.c +++ b/src/cache.c @@ -19,17 +19,28 @@ GIT__USE_OIDMAP bool git_cache__enabled = true; -size_t git_cache__max_object_size[8] = { - 0, /* GIT_OBJ__EXT1 */ +static size_t git_cache__max_object_size[8] = { + 0, /* GIT_OBJ__EXT1 */ 4096, /* GIT_OBJ_COMMIT */ 4096, /* GIT_OBJ_TREE */ - 0, /* GIT_OBJ_BLOB */ + 0, /* GIT_OBJ_BLOB */ 4096, /* GIT_OBJ_TAG */ - 0, /* GIT_OBJ__EXT2 */ - 0, /* GIT_OBJ_OFS_DELTA */ - 0 /* GIT_OBJ_REF_DELTA */ + 0, /* GIT_OBJ__EXT2 */ + 0, /* GIT_OBJ_OFS_DELTA */ + 0 /* GIT_OBJ_REF_DELTA */ }; +int git_cache_set_max_object_size(git_otype type, size_t size) +{ + if (type < 0 || (size_t)type >= ARRAY_SIZE(git_cache__max_object_size)) { + giterr_set(GITERR_INVALID, "type out of range"); + return -1; + } + + git_cache__max_object_size[type] = size; + return 0; +} + void git_cache_dump_stats(git_cache *cache) { git_cached_obj *object; diff --git a/src/cache.h b/src/cache.h index 8b2aa1f79..13b630e89 100644 --- a/src/cache.h +++ b/src/cache.h @@ -20,9 +20,6 @@ enum { GIT_CACHE_STORE_PARSED = 2 }; -extern bool git_cache__enabled; -extern size_t git_cache__max_object_size[8]; - typedef struct { git_oid oid; int16_t type; @@ -37,6 +34,10 @@ typedef struct { size_t used_memory; } git_cache; +extern bool git_cache__enabled; + +int git_cache_set_max_object_size(git_otype type, size_t size); + int git_cache_init(git_cache *cache); void git_cache_free(git_cache *cache); @@ -47,6 +48,11 @@ git_odb_object *git_cache_get_raw(git_cache *cache, const git_oid *oid); git_object *git_cache_get_parsed(git_cache *cache, const git_oid *oid); void *git_cache_get_any(git_cache *cache, const git_oid *oid); +GIT_INLINE(size_t) git_cache_size(git_cache *cache) +{ + return (size_t)kh_size(cache->map); +} + GIT_INLINE(void) git_cached_obj_incref(void *_obj) { git_cached_obj *obj = _obj; diff --git a/src/util.c b/src/util.c index 0b5fbdc5a..1ed5d5d16 100644 --- a/src/util.c +++ b/src/util.c @@ -95,14 +95,16 @@ int git_libgit2_opts(int key, ...) error = git_futils_dirs_set(error, va_arg(ap, const char *)); break; - case GIT_OPT_SET_CACHE_LIMIT: { + case GIT_OPT_SET_CACHE_LIMIT: + { git_otype type = (git_otype)va_arg(ap, int); - git_cache__max_object_size[type] = va_arg(ap, size_t); + size_t size = va_arg(ap, size_t); + error = git_cache_set_max_object_size(type, size); break; } case GIT_OPT_ENABLE_CACHING: - git_cache__enabled = va_arg(ap, int); + git_cache__enabled = (va_arg(ap, int) != 0); break; } From 24c70804e87523df99f4740ed2829976ec1a9c1b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 12 Apr 2013 12:59:38 -0700 Subject: [PATCH 053/134] Add mutex around mapping and unmapping pack files When I was writing threading tests for the new cache, the main error I kept running into was a pack file having it's content unmapped underneath the running thread. This adds a lock around the routines that map and unmap the pack data so that threads can effectively reload the data when they need it. This also required reworking the error handling paths in a couple places in the code which I tried to make consistent. --- src/pack.c | 67 +++++++++++++++++++++++++++++++++++------------------- src/pack.h | 1 + 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/pack.c b/src/pack.c index 75ac98186..1bffb4778 100644 --- a/src/pack.c +++ b/src/pack.c @@ -296,24 +296,34 @@ static int pack_index_check(const char *path, struct git_pack_file *p) static int pack_index_open(struct git_pack_file *p) { char *idx_name; - int error; - size_t name_len, offset; + int error = 0; + size_t name_len, base_len; + + if ((error = git_mutex_lock(&p->lock)) < 0) + return error; if (p->index_map.data) - return 0; + goto done; - idx_name = git__strdup(p->pack_name); - GITERR_CHECK_ALLOC(idx_name); + name_len = strlen(p->pack_name); + assert(name_len > strlen(".pack")); /* checked by git_pack_file alloc */ - name_len = strlen(idx_name); - offset = name_len - strlen(".pack"); - assert(offset < name_len); /* make sure no underflow */ + if ((idx_name = git__malloc(name_len)) == NULL) { + error = -1; + goto done; + } - strncpy(idx_name + offset, ".idx", name_len - offset); + base_len = name_len - strlen(".pack"); + memcpy(idx_name, p->pack_name, base_len); + memcpy(idx_name + base_len, ".idx", sizeof(".idx")); error = pack_index_check(idx_name, p); + git__free(idx_name); +done: + git_mutex_unlock(&p->lock); + return error; } @@ -389,7 +399,7 @@ int git_packfile_unpack_header( * the maximum deflated object size is 2^137, which is just * insane, so we know won't exceed what we have been given. */ -// base = pack_window_open(p, w_curs, *curpos, &left); +/* base = pack_window_open(p, w_curs, *curpos, &left); */ base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left); if (base == NULL) return GIT_EBUFS; @@ -789,15 +799,23 @@ git_off_t get_delta_base( static struct git_pack_file *packfile_alloc(size_t extra) { struct git_pack_file *p = git__calloc(1, sizeof(*p) + extra); - if (p != NULL) - p->mwf.fd = -1; + if (!p) + return NULL; + + p->mwf.fd = -1; + git_mutex_init(&p->lock); + return p; } void git_packfile_free(struct git_pack_file *p) { - assert(p); + if (!p) + return; + + if (git_mutex_lock(&p->lock) < 0) + return; cache_free(&p->bases); @@ -810,6 +828,10 @@ void git_packfile_free(struct git_pack_file *p) pack_index_free(p); git__free(p->bad_object_sha1); + + git_mutex_unlock(&p->lock); + + git_mutex_free(&p->lock); git__free(p); } @@ -820,8 +842,6 @@ static int packfile_open(struct git_pack_file *p) git_oid sha1; unsigned char *idx_sha1; - assert(p->index_map.data); - if (!p->index_map.data && pack_index_open(p) < 0) return git_odb__error_notfound("failed to open packfile", NULL); @@ -888,7 +908,10 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) size_t path_len; *pack_out = NULL; - path_len = strlen(path); + + if (!path || (path_len = strlen(path)) <= strlen(".idx")) + return git_odb__error_notfound("invalid packfile path", NULL); + p = packfile_alloc(path_len + 2); GITERR_CHECK_ALLOC(p); @@ -897,18 +920,13 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) * the index looks sane. */ path_len -= strlen(".idx"); - if (path_len < 1) { - git__free(p); - return git_odb__error_notfound("invalid packfile path", NULL); - } - memcpy(p->pack_name, path, path_len); - strcpy(p->pack_name + path_len, ".keep"); + memcpy(p->pack_name + path_len, ".keep", sizeof(".keep")); if (git_path_exists(p->pack_name) == true) p->pack_keep = 1; - strcpy(p->pack_name + path_len, ".pack"); + memcpy(p->pack_name + path_len, ".pack", sizeof(".pack")); if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) { git__free(p); return git_odb__error_notfound("packfile not found", NULL); @@ -1039,7 +1057,6 @@ static int pack_entry_find_offset( if ((error = pack_index_open(p)) < 0) return error; - assert(p->index_map.data); index = p->index_map.data; @@ -1099,6 +1116,7 @@ static int pack_entry_find_offset( return git_odb__error_notfound("failed to find offset for pack entry", short_oid); if (found > 1) return git_odb__error_ambiguous("found multiple offsets for pack entry"); + *offset_out = nth_packed_object_offset(p, pos); git_oid_fromraw(found_oid, current); @@ -1110,6 +1128,7 @@ static int pack_entry_find_offset( printf("found lo=%d %s\n", lo, hex_sha1); } #endif + return 0; } diff --git a/src/pack.h b/src/pack.h index 8d7e33dfe..b734ac163 100644 --- a/src/pack.h +++ b/src/pack.h @@ -79,6 +79,7 @@ typedef struct { struct git_pack_file { git_mwindow_file mwf; git_map index_map; + git_mutex lock; uint32_t num_objects; uint32_t num_bad_objects; From 917f60c50bce09f789aeb927b45ba3bca5a23877 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 12 Apr 2013 13:04:08 -0700 Subject: [PATCH 054/134] Add tests for oidmap and new cache with threading This adds some basic tests for the oidmap just to make sure that collisions, etc. are dealt with correctly. This also adds some tests for the new caching that check if items are inserted (or not inserted) properly into the cache, and that the cache can hold up in a multithreaded environment without error. --- tests-clar/core/oidmap.c | 110 ++++++++++++++++++ tests-clar/object/cache.c | 232 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 342 insertions(+) create mode 100644 tests-clar/core/oidmap.c create mode 100644 tests-clar/object/cache.c diff --git a/tests-clar/core/oidmap.c b/tests-clar/core/oidmap.c new file mode 100644 index 000000000..ec4b5e775 --- /dev/null +++ b/tests-clar/core/oidmap.c @@ -0,0 +1,110 @@ +#include "clar_libgit2.h" +#include "oidmap.h" + +GIT__USE_OIDMAP; + +typedef struct { + git_oid oid; + size_t extra; +} oidmap_item; + +#define NITEMS 0x0fff + +void test_core_oidmap__basic(void) +{ + git_oidmap *map; + oidmap_item items[NITEMS]; + uint32_t i, j; + + for (i = 0; i < NITEMS; ++i) { + items[i].extra = i; + for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) { + items[i].oid.id[j * 4 ] = (unsigned char)i; + items[i].oid.id[j * 4 + 1] = (unsigned char)(i >> 8); + items[i].oid.id[j * 4 + 2] = (unsigned char)(i >> 16); + items[i].oid.id[j * 4 + 3] = (unsigned char)(i >> 24); + } + } + + map = git_oidmap_alloc(); + cl_assert(map != NULL); + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + int ret; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos == kh_end(map)); + + pos = kh_put(oid, map, &items[i].oid, &ret); + cl_assert(ret != 0); + + kh_val(map, pos) = &items[i]; + } + + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos != kh_end(map)); + + cl_assert_equal_p(kh_val(map, pos), &items[i]); + } + + git_oidmap_free(map); +} + +void test_core_oidmap__hash_collision(void) +{ + git_oidmap *map; + oidmap_item items[NITEMS]; + uint32_t i, j; + + for (i = 0; i < NITEMS; ++i) { + uint32_t segment = i / 8; + int modi = i - (segment * 8); + + items[i].extra = i; + + for (j = 0; j < GIT_OID_RAWSZ / 4; ++j) { + items[i].oid.id[j * 4 ] = (unsigned char)modi; + items[i].oid.id[j * 4 + 1] = (unsigned char)(modi >> 8); + items[i].oid.id[j * 4 + 2] = (unsigned char)(modi >> 16); + items[i].oid.id[j * 4 + 3] = (unsigned char)(modi >> 24); + } + + items[i].oid.id[ 8] = (unsigned char)i; + items[i].oid.id[ 9] = (unsigned char)(i >> 8); + items[i].oid.id[10] = (unsigned char)(i >> 16); + items[i].oid.id[11] = (unsigned char)(i >> 24); + } + + map = git_oidmap_alloc(); + cl_assert(map != NULL); + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + int ret; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos == kh_end(map)); + + pos = kh_put(oid, map, &items[i].oid, &ret); + cl_assert(ret != 0); + + kh_val(map, pos) = &items[i]; + } + + + for (i = 0; i < NITEMS; ++i) { + khiter_t pos; + + pos = kh_get(oid, map, &items[i].oid); + cl_assert(pos != kh_end(map)); + + cl_assert_equal_p(kh_val(map, pos), &items[i]); + } + + git_oidmap_free(map); +} diff --git a/tests-clar/object/cache.c b/tests-clar/object/cache.c new file mode 100644 index 000000000..8121247c9 --- /dev/null +++ b/tests-clar/object/cache.c @@ -0,0 +1,232 @@ +#include "clar_libgit2.h" +#include "repository.h" + +static git_repository *g_repo; + +void test_object_cache__initialize(void) +{ + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); +} + +void test_object_cache__cleanup(void) +{ + git_repository_free(g_repo); + g_repo = NULL; + + git_libgit2_opts(GIT_OPT_SET_CACHE_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); +} + +static struct { + git_otype type; + const char *sha; +} g_data[] = { + /* HEAD */ + { GIT_OBJ_BLOB, "a8233120f6ad708f843d861ce2b7228ec4e3dec6" }, /* README */ + { GIT_OBJ_BLOB, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc" }, /* branch_file.txt */ + { GIT_OBJ_BLOB, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd" }, /* new.txt */ + + /* refs/heads/subtrees */ + { GIT_OBJ_BLOB, "1385f264afb75a56a5bec74243be9b367ba4ca08" }, /* README */ + { GIT_OBJ_TREE, "f1425cef211cc08caa31e7b545ffb232acb098c3" }, /* ab */ + { GIT_OBJ_BLOB, "d6c93164c249c8000205dd4ec5cbca1b516d487f" }, /* ab/4.txt */ + { GIT_OBJ_TREE, "9a03079b8a8ee85a0bee58bf9be3da8b62414ed4" }, /* ab/c */ + { GIT_OBJ_BLOB, "270b8ea76056d5cad83af921837702d3e3c2924d" }, /* ab/c/3.txt */ + { GIT_OBJ_TREE, "b6361fc6a97178d8fc8639fdeed71c775ab52593" }, /* ab/de */ + { GIT_OBJ_BLOB, "e7b4ad382349ff96dd8199000580b9b1e2042eb0" }, /* ab/de/2.txt */ + { GIT_OBJ_TREE, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54" }, /* ab/de/fgh */ + { GIT_OBJ_BLOB, "1f67fc4386b2d171e0d21be1c447e12660561f9b" }, /* ab/de/fgh/1.txt */ + { GIT_OBJ_BLOB, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057" }, /* branch_file.txt */ + { GIT_OBJ_BLOB, "fa49b077972391ad58037050f2a75f74e3671e92" }, /* new.txt */ + + /* refs/heads/chomped */ + { GIT_OBJ_BLOB, "0266163a49e280c4f5ed1e08facd36a2bd716bcf" }, /* readme.txt */ + + { 0, NULL }, + { 0, NULL } +}; + +void test_object_cache__cache_everything(void) +{ + int i, start; + git_oid oid; + git_odb_object *odb_obj; + git_object *obj; + git_odb *odb; + + git_libgit2_opts( + GIT_OPT_SET_CACHE_LIMIT, (int)GIT_OBJ_BLOB, (size_t)32767); + + cl_git_pass(git_repository_odb(&odb, g_repo)); + + start = (int)git_cache_size(&g_repo->objects); + + for (i = 0; g_data[i].sha != NULL; ++i) { + int count = (int)git_cache_size(&g_repo->objects); + + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + + /* alternate between loading raw and parsed objects */ + if ((i & 1) == 0) { + cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); + cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); + git_odb_object_free(odb_obj); + } else { + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + } + + cl_assert_equal_i(count + 1, (int)git_cache_size(&g_repo->objects)); + } + + cl_assert_equal_i(i, git_cache_size(&g_repo->objects) - start); + + git_odb_free(odb); + + for (i = 0; g_data[i].sha != NULL; ++i) { + int count = (int)git_cache_size(&g_repo->objects); + + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + + cl_assert_equal_i(count, (int)git_cache_size(&g_repo->objects)); + } +} + +void test_object_cache__cache_no_blobs(void) +{ + int i, start, nonblobs = 0; + git_oid oid; + git_odb_object *odb_obj; + git_object *obj; + git_odb *odb; + + git_libgit2_opts(GIT_OPT_SET_CACHE_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); + + cl_git_pass(git_repository_odb(&odb, g_repo)); + + start = (int)git_cache_size(&g_repo->objects); + + for (i = 0; g_data[i].sha != NULL; ++i) { + int count = (int)git_cache_size(&g_repo->objects); + + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + + /* alternate between loading raw and parsed objects */ + if ((i & 1) == 0) { + cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); + cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); + git_odb_object_free(odb_obj); + } else { + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + } + + if (g_data[i].type == GIT_OBJ_BLOB) + cl_assert_equal_i(count, (int)git_cache_size(&g_repo->objects)); + else { + cl_assert_equal_i(count + 1, (int)git_cache_size(&g_repo->objects)); + nonblobs++; + } + } + + cl_assert_equal_i(nonblobs, git_cache_size(&g_repo->objects) - start); + + git_odb_free(odb); +} + +static void *cache_parsed(void *arg) +{ + int i; + git_oid oid; + git_object *obj; + + for (i = ((int *)arg)[1]; g_data[i].sha != NULL; i += 2) { + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + } + + for (i = 0; i < ((int *)arg)[1]; i += 2) { + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[i].type == git_object_type(obj)); + git_object_free(obj); + } + + return arg; +} + +static void *cache_raw(void *arg) +{ + int i; + git_oid oid; + git_odb *odb; + git_odb_object *odb_obj; + + cl_git_pass(git_repository_odb(&odb, g_repo)); + + for (i = ((int *)arg)[1]; g_data[i].sha != NULL; i += 2) { + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); + cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); + git_odb_object_free(odb_obj); + } + + for (i = 0; i < ((int *)arg)[1]; i += 2) { + cl_git_pass(git_oid_fromstr(&oid, g_data[i].sha)); + cl_git_pass(git_odb_read(&odb_obj, odb, &oid)); + cl_assert(g_data[i].type == git_odb_object_type(odb_obj)); + git_odb_object_free(odb_obj); + } + + git_odb_free(odb); + + return arg; +} + +#define REPEAT 50 +#define THREADCOUNT 20 + +void test_object_cache__threadmania(void) +{ + int try, th, max_i; + git_thread t[THREADCOUNT]; + void *data; + void *(*fn)(void *); + + for (max_i = 0; g_data[max_i].sha != NULL; ++max_i) + /* count up */; + + for (try = 0; try < REPEAT; ++try) { + + for (th = 0; th < THREADCOUNT; ++th) { + data = git__malloc(2 * sizeof(int)); + + ((int *)data)[0] = th; + ((int *)data)[1] = th % max_i; + + fn = (th & 1) ? cache_parsed : cache_raw; + +#ifdef GIT_THREADS + git_thread_create(&t[th], NULL, fn, data); +#else + fn(data); + git__free(data); +#endif + } + +#ifdef GIT_THREADS + for (th = 0; th < THREADCOUNT; ++th) { + git_thread_join(t[th], &data); + cl_assert_equal_i(th, ((int *)data)[0]); + git__free(data); + } +#endif + + } +} From 786062639f05e361da977f3f1f6286141fa12fca Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 15 Apr 2013 00:05:44 -0700 Subject: [PATCH 055/134] Add callback to git_objects_table This adds create and free callback to the git_objects_table so that more of the creation and destruction of objects can be table driven instead of using switch statements. This also makes the semantics of certain object creation functions consistent so that we can make better use of function pointers. This also fixes a theoretical error case where an object allocation fails and we end up storing NULL into the cache. --- src/blob.c | 8 +-- src/blob.h | 4 +- src/cache.c | 14 ++-- src/cache.h | 12 ++-- src/commit.c | 16 ++--- src/commit.h | 5 +- src/object.c | 145 ++++++++++++++------------------------ src/odb.c | 31 +++++--- src/odb.h | 5 +- src/oidmap.h | 4 +- src/tag.c | 19 ++--- src/tag.h | 5 +- src/tree.c | 27 +++---- src/tree.h | 4 +- tests-clar/commit/parse.c | 13 ++-- 15 files changed, 128 insertions(+), 184 deletions(-) diff --git a/src/blob.c b/src/blob.c index 732b0f3de..501c13d1a 100644 --- a/src/blob.c +++ b/src/blob.c @@ -35,17 +35,17 @@ int git_blob__getbuf(git_buf *buffer, git_blob *blob) git_odb_object_size(blob->odb_object)); } -void git_blob__free(git_blob *blob) +void git_blob__free(void *blob) { - git_odb_object_free(blob->odb_object); + git_odb_object_free(((git_blob *)blob)->odb_object); git__free(blob); } -int git_blob__parse(git_blob *blob, git_odb_object *odb_obj) +int git_blob__from_odb_object(void *blob, git_odb_object *odb_obj) { assert(blob); git_cached_obj_incref((git_cached_obj *)odb_obj); - blob->odb_object = odb_obj; + ((git_blob *)blob)->odb_object = odb_obj; return 0; } diff --git a/src/blob.h b/src/blob.h index 524734b1f..4873505fd 100644 --- a/src/blob.h +++ b/src/blob.h @@ -17,8 +17,8 @@ struct git_blob { git_odb_object *odb_object; }; -void git_blob__free(git_blob *blob); -int git_blob__parse(git_blob *blob, git_odb_object *obj); +void git_blob__free(void *blob); +int git_blob__from_odb_object(void *blob, git_odb_object *obj); int git_blob__getbuf(git_buf *buffer, git_blob *blob); #endif diff --git a/src/cache.c b/src/cache.c index 263f736fa..c51be895e 100644 --- a/src/cache.c +++ b/src/cache.c @@ -70,12 +70,6 @@ int git_cache_init(git_cache *cache) return 0; } -void git_cache_free(git_cache *cache) -{ - git_oidmap_free(cache->map); - git_mutex_free(&cache->lock); -} - void git_cache_clear(git_cache *cache) { git_cached_obj *evict = NULL; @@ -93,6 +87,14 @@ void git_cache_clear(git_cache *cache) git_mutex_unlock(&cache->lock); } +void git_cache_free(git_cache *cache) +{ + git_cache_clear(cache); + + git_oidmap_free(cache->map); + git_mutex_free(&cache->lock); +} + /* Call with lock, yo */ static void cache_evict_entries(git_cache *cache, size_t evict_count) { diff --git a/src/cache.h b/src/cache.h index 13b630e89..e95d521fe 100644 --- a/src/cache.h +++ b/src/cache.h @@ -21,17 +21,17 @@ enum { }; typedef struct { - git_oid oid; - int16_t type; - uint16_t flags; - size_t size; + git_oid oid; + int16_t type; /* git_otype value */ + uint16_t flags; /* GIT_CACHE_STORE value */ + size_t size; git_atomic refcount; } git_cached_obj; typedef struct { git_oidmap *map; - git_mutex lock; - size_t used_memory; + git_mutex lock; + size_t used_memory; } git_cache; extern bool git_cache__enabled; diff --git a/src/commit.c b/src/commit.c index 2cee44cd2..3eca5b341 100644 --- a/src/commit.c +++ b/src/commit.c @@ -31,8 +31,10 @@ static void clear_parents(git_commit *commit) git_vector_clear(&commit->parent_ids); } -void git_commit__free(git_commit *commit) +void git_commit__free(void *_commit) { + git_commit *commit = _commit; + clear_parents(commit); git_vector_free(&commit->parent_ids); @@ -166,10 +168,9 @@ int git_commit_create( return retval; } -int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) +int git_commit__parse(void *_commit, const char *buffer, const char *buffer_end) { - const char *buffer = data; - const char *buffer_end = (const char *)data + len; + git_commit *commit = _commit; git_oid parent_id; if (git_vector_init(&commit->parent_ids, 4, NULL) < 0) @@ -241,13 +242,6 @@ bad_buffer: return -1; } -int git_commit__parse(git_commit *commit, git_odb_object *obj) -{ - assert(commit); - return git_commit__parse_buffer( - commit, git_odb_object_data(obj), git_odb_object_size(obj)); -} - #define GIT_COMMIT_GETTER(_rvalue, _name, _return) \ _rvalue git_commit_##_name(const git_commit *commit) \ {\ diff --git a/src/commit.h b/src/commit.h index 1ab164c0b..0c2c3ab5d 100644 --- a/src/commit.h +++ b/src/commit.h @@ -27,8 +27,7 @@ struct git_commit { char *message; }; -void git_commit__free(git_commit *c); -int git_commit__parse(git_commit *commit, git_odb_object *obj); +void git_commit__free(void *commit); +int git_commit__parse(void *commit, const char *buf, const char *bufend); -int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len); #endif diff --git a/src/object.c b/src/object.c index 80b765ef9..3698808c3 100644 --- a/src/object.c +++ b/src/object.c @@ -18,63 +18,39 @@ static const int OBJECT_BASE_SIZE = 4096; -static struct { +typedef struct { const char *str; /* type name string */ - int loose; /* valid loose object type flag */ size_t size; /* size in bytes of the object structure */ -} git_objects_table[] = { + + int (*from_odb)(void *self, git_odb_object *obj); + int (*parse)(void *self, const char *buf, const char *buf_end); + void (*free)(void *self); +} git_object_def; + +static git_object_def git_objects_table[] = { /* 0 = GIT_OBJ__EXT1 */ - { "", 0, 0}, + { "", 0, NULL, NULL, NULL }, /* 1 = GIT_OBJ_COMMIT */ - { "commit", 1, sizeof(struct git_commit)}, + { "commit", sizeof(git_commit), NULL, git_commit__parse, git_commit__free }, /* 2 = GIT_OBJ_TREE */ - { "tree", 1, sizeof(struct git_tree) }, + { "tree", sizeof(git_tree), NULL, git_tree__parse, git_tree__free }, /* 3 = GIT_OBJ_BLOB */ - { "blob", 1, sizeof(struct git_blob) }, + { "blob", sizeof(git_blob), git_blob__from_odb_object, NULL, git_blob__free }, /* 4 = GIT_OBJ_TAG */ - { "tag", 1, sizeof(struct git_tag) }, + { "tag", sizeof(git_tag), NULL, git_tag__parse, git_tag__free }, /* 5 = GIT_OBJ__EXT2 */ - { "", 0, 0 }, - + { "", 0, NULL, NULL, NULL }, /* 6 = GIT_OBJ_OFS_DELTA */ - { "OFS_DELTA", 0, 0 }, - + { "OFS_DELTA", 0, NULL, NULL, NULL }, /* 7 = GIT_OBJ_REF_DELTA */ - { "REF_DELTA", 0, 0 } + { "REF_DELTA", 0, NULL, NULL, NULL }, }; -static int create_object(git_object **object_out, git_otype type) -{ - git_object *object = NULL; - - assert(object_out); - - *object_out = NULL; - - switch (type) { - case GIT_OBJ_COMMIT: - case GIT_OBJ_TAG: - case GIT_OBJ_BLOB: - case GIT_OBJ_TREE: - object = git__malloc(git_object__size(type)); - GITERR_CHECK_ALLOC(object); - memset(object, 0x0, git_object__size(type)); - break; - - default: - giterr_set(GITERR_INVALID, "The given type is invalid"); - return -1; - } - - *object_out = object; - return 0; -} - int git_object__from_odb_object( git_object **object_out, git_repository *repo, @@ -82,46 +58,47 @@ int git_object__from_odb_object( git_otype type) { int error; + size_t object_size; + git_object_def *def; git_object *object = NULL; + assert(object_out); + *object_out = NULL; + + /* Validate type match */ if (type != GIT_OBJ_ANY && type != odb_obj->cached.type) { giterr_set(GITERR_INVALID, "The requested type does not match the type in the ODB"); return GIT_ENOTFOUND; } - if ((error = create_object(&object, odb_obj->cached.type)) < 0) - return error; + if ((object_size = git_object__size(odb_obj->cached.type)) == 0) { + giterr_set(GITERR_INVALID, "The requested type is invalid"); + return GIT_ENOTFOUND; + } + + /* Allocate and initialize base object */ + object = git__calloc(1, object_size); + GITERR_CHECK_ALLOC(object); - /* Initialize parent object */ git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); - object->cached.size = odb_obj->cached.size; object->cached.type = odb_obj->cached.type; + object->cached.size = odb_obj->cached.size; object->repo = repo; - switch (object->cached.type) { - case GIT_OBJ_COMMIT: - error = git_commit__parse((git_commit *)object, odb_obj); - break; + /* Parse raw object data */ + def = &git_objects_table[odb_obj->cached.type]; + assert(def->free && (def->from_odb || def->parse)); - case GIT_OBJ_TREE: - error = git_tree__parse((git_tree *)object, odb_obj); - break; - - case GIT_OBJ_TAG: - error = git_tag__parse((git_tag *)object, odb_obj); - break; - - case GIT_OBJ_BLOB: - error = git_blob__parse((git_blob *)object, odb_obj); - break; - - default: - break; + if (def->from_odb) { + error = def->from_odb(object, odb_obj); + } else { + const char *data = (const char *)git_odb_object_data(odb_obj); + error = def->parse(object, data, data + git_odb_object_size(odb_obj)); } if (error < 0) { - git_object__free(object); + def->free(object); return error; } @@ -129,6 +106,17 @@ int git_object__from_odb_object( return 0; } +void git_object__free(void *obj) +{ + git_otype type = ((git_object *)obj)->cached.type; + + if (type < 0 || ((size_t)type) >= ARRAY_SIZE(git_objects_table) || + !git_objects_table[type].free) + git__free(obj); + else + git_objects_table[type].free(obj); +} + int git_object_lookup_prefix( git_object **object_out, git_repository *repo, @@ -222,35 +210,6 @@ int git_object_lookup(git_object **object_out, git_repository *repo, const git_o return git_object_lookup_prefix(object_out, repo, id, GIT_OID_HEXSZ, type); } -void git_object__free(void *_obj) -{ - git_object *object = (git_object *)_obj; - - assert(object); - - switch (object->cached.type) { - case GIT_OBJ_COMMIT: - git_commit__free((git_commit *)object); - break; - - case GIT_OBJ_TREE: - git_tree__free((git_tree *)object); - break; - - case GIT_OBJ_TAG: - git_tag__free((git_tag *)object); - break; - - case GIT_OBJ_BLOB: - git_blob__free((git_blob *)object); - break; - - default: - git__free(object); - break; - } -} - void git_object_free(git_object *object) { if (object == NULL) @@ -304,7 +263,7 @@ int git_object_typeisloose(git_otype type) if (type < 0 || ((size_t) type) >= ARRAY_SIZE(git_objects_table)) return 0; - return git_objects_table[type].loose; + return (git_objects_table[type].size > 0) ? 1 : 0; } size_t git_object__size(git_otype type) diff --git a/src/odb.c b/src/odb.c index 16a842aa8..53630dddc 100644 --- a/src/odb.c +++ b/src/odb.c @@ -82,23 +82,24 @@ int git_odb__hashobj(git_oid *id, git_rawobj *obj) } -static git_odb_object *new_odb_object(const git_oid *oid, git_rawobj *source) +static git_odb_object *odb_object__alloc(const git_oid *oid, git_rawobj *source) { - git_odb_object *object = git__malloc(sizeof(git_odb_object)); - memset(object, 0x0, sizeof(git_odb_object)); + git_odb_object *object = git__calloc(1, sizeof(git_odb_object)); - git_oid_cpy(&object->cached.oid, oid); - object->cached.size = source->len; - object->cached.type = source->type; - object->buffer = source->data; + if (object != NULL) { + git_oid_cpy(&object->cached.oid, oid); + object->cached.type = source->type; + object->cached.size = source->len; + object->buffer = source->data; + } return object; } -void git_odb_object__free(git_odb_object *object) +void git_odb_object__free(void *object) { if (object != NULL) { - git__free(object->buffer); + git__free(((git_odb_object *)object)->buffer); git__free(object); } } @@ -679,6 +680,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) int error; bool refreshed = false; git_rawobj raw; + git_odb_object *object; assert(out && db && id); @@ -713,7 +715,10 @@ attempt_lookup: if (error && error != GIT_PASSTHROUGH) return error; - *out = git_cache_store_raw(odb_cache(db), new_odb_object(id, &raw)); + if ((object = odb_object__alloc(id, &raw)) == NULL) + return -1; + + *out = git_cache_store_raw(odb_cache(db), object); return 0; } @@ -726,6 +731,7 @@ int git_odb_read_prefix( git_rawobj raw; void *data = NULL; bool found = false, refreshed = false; + git_odb_object *object; assert(out && db); @@ -777,7 +783,10 @@ attempt_lookup: if (!found) return git_odb__error_notfound("no match for prefix", short_id); - *out = git_cache_store_raw(odb_cache(db), new_odb_object(&found_full_oid, &raw)); + if ((object = odb_object__alloc(&found_full_oid, &raw)) == NULL) + return -1; + + *out = git_cache_store_raw(odb_cache(db), object); return 0; } diff --git a/src/odb.h b/src/odb.h index 22c6e1668..0d9f9e2ea 100644 --- a/src/odb.h +++ b/src/odb.h @@ -39,8 +39,6 @@ struct git_odb { git_cache own_cache; }; -void git_odb_object__free(git_odb_object *object); - /* * Hash a git_rawobj internally. * The `git_rawobj` is supposed to be previously initialized @@ -98,4 +96,7 @@ int git_odb__read_header_or_object( git_odb_object **out, size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id); +/* fully free the object; internal method, DO NOT EXPORT */ +void git_odb_object__free(void *object); + #endif diff --git a/src/oidmap.h b/src/oidmap.h index dfa951af3..a29c7cd35 100644 --- a/src/oidmap.h +++ b/src/oidmap.h @@ -19,7 +19,7 @@ __KHASH_TYPE(oid, const git_oid *, void *); typedef khash_t(oid) git_oidmap; -GIT_INLINE(khint_t) hash_git_oid(const git_oid *oid) +GIT_INLINE(khint_t) git_oidmap_hash(const git_oid *oid) { khint_t h; memcpy(&h, oid, sizeof(khint_t)); @@ -27,7 +27,7 @@ GIT_INLINE(khint_t) hash_git_oid(const git_oid *oid) } #define GIT__USE_OIDMAP \ - __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, hash_git_oid, git_oid_equal) + __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, git_oidmap_hash, git_oid_equal) #define git_oidmap_alloc() kh_init(oid) #define git_oidmap_free(h) kh_destroy(oid,h), h = NULL diff --git a/src/tag.c b/src/tag.c index b76895d0c..7dadc7e60 100644 --- a/src/tag.c +++ b/src/tag.c @@ -15,8 +15,9 @@ #include "git2/signature.h" #include "git2/odb_backend.h" -void git_tag__free(git_tag *tag) +void git_tag__free(void *_tag) { + git_tag *tag = _tag; git_signature_free(tag->tagger); git__free(tag->message); git__free(tag->tag_name); @@ -69,18 +70,17 @@ static int tag_error(const char *str) return -1; } -int git_tag__parse_buffer(git_tag *tag, const char *buffer, size_t length) +int git_tag__parse(void *_tag, const char *buffer, const char *buffer_end) { static const char *tag_types[] = { NULL, "commit\n", "tree\n", "blob\n", "tag\n" }; + git_tag *tag = _tag; unsigned int i; size_t text_len; char *search; - const char *buffer_end = buffer + length; - if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0) return tag_error("Object field invalid"); @@ -317,7 +317,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu return -1; /* validate the buffer */ - if (git_tag__parse_buffer(&tag, buffer, strlen(buffer)) < 0) + if (git_tag__parse(&tag, buffer, buffer + strlen(buffer)) < 0) return -1; /* validate the target */ @@ -390,15 +390,8 @@ int git_tag_delete(git_repository *repo, const char *tag_name) if ((error = git_reference_delete(tag_ref)) == 0) git_reference_free(tag_ref); - - return error; -} -int git_tag__parse(git_tag *tag, git_odb_object *obj) -{ - assert(tag); - return git_tag__parse_buffer( - tag, git_odb_object_data(obj), git_odb_object_size(obj)); + return error; } typedef struct { diff --git a/src/tag.h b/src/tag.h index c8e421ee6..fb01a6f75 100644 --- a/src/tag.h +++ b/src/tag.h @@ -22,8 +22,7 @@ struct git_tag { char *message; }; -void git_tag__free(git_tag *tag); -int git_tag__parse(git_tag *tag, git_odb_object *obj); -int git_tag__parse_buffer(git_tag *tag, const char *data, size_t len); +void git_tag__free(void *tag); +int git_tag__parse(void *tag, const char *buf, const char *buf_end); #endif diff --git a/src/tree.c b/src/tree.c index cc43b920c..e66fa2370 100644 --- a/src/tree.c +++ b/src/tree.c @@ -219,15 +219,16 @@ git_tree_entry *git_tree_entry_dup(const git_tree_entry *entry) return copy; } -void git_tree__free(git_tree *tree) +void git_tree__free(void *tree) { + git_vector *entries = &((git_tree *)tree)->entries; size_t i; git_tree_entry *e; - git_vector_foreach(&tree->entries, i, e) + git_vector_foreach(entries, i, e) git_tree_entry_free(e); - git_vector_free(&tree->entries); + git_vector_free(entries); git__free(tree); } @@ -371,10 +372,11 @@ static int tree_error(const char *str, const char *path) return -1; } -static int tree_parse_buffer( - git_tree *tree, const char *buffer, const char *buffer_end) +int git_tree__parse(void *tree, const char *buffer, const char *buffer_end) { - if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) + git_vector *tree_entries = &((git_tree *)tree)->entries; + + if (git_vector_init(tree_entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) return -1; while (buffer < buffer_end) { @@ -397,7 +399,7 @@ static int tree_parse_buffer( entry = alloc_entry(buffer); GITERR_CHECK_ALLOC(entry); - if (git_vector_insert(&tree->entries, entry) < 0) { + if (git_vector_insert(tree_entries, entry) < 0) { git__free(entry); return -1; } @@ -417,17 +419,6 @@ static int tree_parse_buffer( return 0; } -int git_tree__parse(git_tree *tree, git_odb_object *obj) -{ - const char *buf; - - assert(tree && obj); - - buf = (const char *)git_odb_object_data(obj); - - return tree_parse_buffer(tree, buf, buf + git_odb_object_size(obj)); -} - static size_t find_next_dir(const char *dirname, git_index *index, size_t start) { size_t dirlen, i, entries = git_index_entrycount(index); diff --git a/src/tree.h b/src/tree.h index b77bfd961..cf47fb478 100644 --- a/src/tree.h +++ b/src/tree.h @@ -37,8 +37,8 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) extern int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2); -void git_tree__free(git_tree *tree); -int git_tree__parse(git_tree *tree, git_odb_object *obj); +void git_tree__free(void *tree); +int git_tree__parse(void *tree, const char *buf, const char *buf_end); /** * Lookup the first position in the tree with a given prefix. diff --git a/tests-clar/commit/parse.c b/tests-clar/commit/parse.c index b99d27991..792b57626 100644 --- a/tests-clar/commit/parse.c +++ b/tests-clar/commit/parse.c @@ -269,6 +269,7 @@ void test_commit_parse__entire_commit(void) const int broken_commit_count = sizeof(failing_commit_cases) / sizeof(*failing_commit_cases); const int working_commit_count = sizeof(passing_commit_cases) / sizeof(*passing_commit_cases); int i; + const char *buf; for (i = 0; i < broken_commit_count; ++i) { git_commit *commit; @@ -276,9 +277,8 @@ void test_commit_parse__entire_commit(void) memset(commit, 0x0, sizeof(git_commit)); commit->object.repo = g_repo; - cl_git_fail(git_commit__parse_buffer( - commit, failing_commit_cases[i], strlen(failing_commit_cases[i])) - ); + buf = failing_commit_cases[i]; + cl_git_fail(git_commit__parse(commit, buf, buf + strlen(buf))); git_commit__free(commit); } @@ -290,11 +290,8 @@ void test_commit_parse__entire_commit(void) memset(commit, 0x0, sizeof(git_commit)); commit->object.repo = g_repo; - cl_git_pass(git_commit__parse_buffer( - commit, - passing_commit_cases[i], - strlen(passing_commit_cases[i])) - ); + buf = passing_commit_cases[i]; + cl_git_pass(git_commit__parse(commit, buf, buf + strlen(buf))); if (!i) cl_assert_equal_s("", git_commit_message(commit)); From 3f27127d15dfe69943d3c9ddf96d09a2300de3a9 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 16 Apr 2013 11:51:02 -0700 Subject: [PATCH 056/134] Simplify object table parse functions This unifies the object parse functions into one signature that takes an odb_object. --- src/blob.c | 2 +- src/blob.h | 2 +- src/commit.c | 4 +++- src/commit.h | 2 +- src/object.c | 37 ++++++++++++++----------------------- src/tag.c | 38 +++++++++++++++++++++++--------------- src/tag.h | 2 +- src/tree.c | 4 +++- src/tree.h | 2 +- tests-clar/commit/parse.c | 27 +++++++++++++++------------ 10 files changed, 63 insertions(+), 57 deletions(-) diff --git a/src/blob.c b/src/blob.c index 501c13d1a..a68c4cc3e 100644 --- a/src/blob.c +++ b/src/blob.c @@ -41,7 +41,7 @@ void git_blob__free(void *blob) git__free(blob); } -int git_blob__from_odb_object(void *blob, git_odb_object *odb_obj) +int git_blob__parse(void *blob, git_odb_object *odb_obj) { assert(blob); git_cached_obj_incref((git_cached_obj *)odb_obj); diff --git a/src/blob.h b/src/blob.h index 4873505fd..22e37cc3a 100644 --- a/src/blob.h +++ b/src/blob.h @@ -18,7 +18,7 @@ struct git_blob { }; void git_blob__free(void *blob); -int git_blob__from_odb_object(void *blob, git_odb_object *obj); +int git_blob__parse(void *blob, git_odb_object *obj); int git_blob__getbuf(git_buf *buffer, git_blob *blob); #endif diff --git a/src/commit.c b/src/commit.c index 3eca5b341..46c02c292 100644 --- a/src/commit.c +++ b/src/commit.c @@ -168,9 +168,11 @@ int git_commit_create( return retval; } -int git_commit__parse(void *_commit, const char *buffer, const char *buffer_end) +int git_commit__parse(void *_commit, git_odb_object *odb_obj) { git_commit *commit = _commit; + const char *buffer = git_odb_object_data(odb_obj); + const char *buffer_end = buffer + git_odb_object_size(odb_obj); git_oid parent_id; if (git_vector_init(&commit->parent_ids, 4, NULL) < 0) diff --git a/src/commit.h b/src/commit.h index 0c2c3ab5d..d0981b125 100644 --- a/src/commit.h +++ b/src/commit.h @@ -28,6 +28,6 @@ struct git_commit { }; void git_commit__free(void *commit); -int git_commit__parse(void *commit, const char *buf, const char *bufend); +int git_commit__parse(void *commit, git_odb_object *obj); #endif diff --git a/src/object.c b/src/object.c index 3698808c3..b87a07404 100644 --- a/src/object.c +++ b/src/object.c @@ -22,33 +22,32 @@ typedef struct { const char *str; /* type name string */ size_t size; /* size in bytes of the object structure */ - int (*from_odb)(void *self, git_odb_object *obj); - int (*parse)(void *self, const char *buf, const char *buf_end); + int (*parse)(void *self, git_odb_object *obj); void (*free)(void *self); } git_object_def; static git_object_def git_objects_table[] = { /* 0 = GIT_OBJ__EXT1 */ - { "", 0, NULL, NULL, NULL }, + { "", 0, NULL, NULL }, /* 1 = GIT_OBJ_COMMIT */ - { "commit", sizeof(git_commit), NULL, git_commit__parse, git_commit__free }, + { "commit", sizeof(git_commit), git_commit__parse, git_commit__free }, /* 2 = GIT_OBJ_TREE */ - { "tree", sizeof(git_tree), NULL, git_tree__parse, git_tree__free }, + { "tree", sizeof(git_tree), git_tree__parse, git_tree__free }, /* 3 = GIT_OBJ_BLOB */ - { "blob", sizeof(git_blob), git_blob__from_odb_object, NULL, git_blob__free }, + { "blob", sizeof(git_blob), git_blob__parse, git_blob__free }, /* 4 = GIT_OBJ_TAG */ - { "tag", sizeof(git_tag), NULL, git_tag__parse, git_tag__free }, + { "tag", sizeof(git_tag), git_tag__parse, git_tag__free }, /* 5 = GIT_OBJ__EXT2 */ - { "", 0, NULL, NULL, NULL }, + { "", 0, NULL, NULL }, /* 6 = GIT_OBJ_OFS_DELTA */ - { "OFS_DELTA", 0, NULL, NULL, NULL }, + { "OFS_DELTA", 0, NULL, NULL }, /* 7 = GIT_OBJ_REF_DELTA */ - { "REF_DELTA", 0, NULL, NULL, NULL }, + { "REF_DELTA", 0, NULL, NULL }, }; int git_object__from_odb_object( @@ -88,22 +87,14 @@ int git_object__from_odb_object( /* Parse raw object data */ def = &git_objects_table[odb_obj->cached.type]; - assert(def->free && (def->from_odb || def->parse)); + assert(def->free && def->parse); - if (def->from_odb) { - error = def->from_odb(object, odb_obj); - } else { - const char *data = (const char *)git_odb_object_data(odb_obj); - error = def->parse(object, data, data + git_odb_object_size(odb_obj)); - } - - if (error < 0) { + if ((error = def->parse(object, odb_obj)) < 0) def->free(object); - return error; - } + else + *object_out = git_cache_store_parsed(&repo->objects, object); - *object_out = git_cache_store_parsed(&repo->objects, object); - return 0; + return error; } void git_object__free(void *obj) diff --git a/src/tag.c b/src/tag.c index 7dadc7e60..b9a806cd1 100644 --- a/src/tag.c +++ b/src/tag.c @@ -70,13 +70,12 @@ static int tag_error(const char *str) return -1; } -int git_tag__parse(void *_tag, const char *buffer, const char *buffer_end) +static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end) { static const char *tag_types[] = { NULL, "commit\n", "tree\n", "blob\n", "tag\n" }; - git_tag *tag = _tag; unsigned int i; size_t text_len; char *search; @@ -157,6 +156,15 @@ int git_tag__parse(void *_tag, const char *buffer, const char *buffer_end) return 0; } +int git_tag__parse(void *_tag, git_odb_object *odb_obj) +{ + git_tag *tag = _tag; + const char *buffer = git_odb_object_data(odb_obj); + const char *buffer_end = buffer + git_odb_object_size(odb_obj); + + return tag_parse(tag, buffer, buffer_end); +} + static int retrieve_tag_reference( git_reference **tag_reference_out, git_buf *ref_name_out, @@ -277,23 +285,23 @@ cleanup: } int git_tag_create( - git_oid *oid, - git_repository *repo, - const char *tag_name, - const git_object *target, - const git_signature *tagger, - const char *message, - int allow_ref_overwrite) + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_object *target, + const git_signature *tagger, + const char *message, + int allow_ref_overwrite) { return git_tag_create__internal(oid, repo, tag_name, target, tagger, message, allow_ref_overwrite, 1); } int git_tag_create_lightweight( - git_oid *oid, - git_repository *repo, - const char *tag_name, - const git_object *target, - int allow_ref_overwrite) + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_object *target, + int allow_ref_overwrite) { return git_tag_create__internal(oid, repo, tag_name, target, NULL, NULL, allow_ref_overwrite, 0); } @@ -317,7 +325,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu return -1; /* validate the buffer */ - if (git_tag__parse(&tag, buffer, buffer + strlen(buffer)) < 0) + if (tag_parse(&tag, buffer, buffer + strlen(buffer)) < 0) return -1; /* validate the target */ diff --git a/src/tag.h b/src/tag.h index fb01a6f75..d0cd393c7 100644 --- a/src/tag.h +++ b/src/tag.h @@ -23,6 +23,6 @@ struct git_tag { }; void git_tag__free(void *tag); -int git_tag__parse(void *tag, const char *buf, const char *buf_end); +int git_tag__parse(void *tag, git_odb_object *obj); #endif diff --git a/src/tree.c b/src/tree.c index e66fa2370..d6d4b77d3 100644 --- a/src/tree.c +++ b/src/tree.c @@ -372,8 +372,10 @@ static int tree_error(const char *str, const char *path) return -1; } -int git_tree__parse(void *tree, const char *buffer, const char *buffer_end) +int git_tree__parse(void *tree, git_odb_object *odb_obj) { + const char *buffer = git_odb_object_data(odb_obj); + const char *buffer_end = buffer + git_odb_object_size(odb_obj); git_vector *tree_entries = &((git_tree *)tree)->entries; if (git_vector_init(tree_entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) diff --git a/src/tree.h b/src/tree.h index cf47fb478..7cb2dd36c 100644 --- a/src/tree.h +++ b/src/tree.h @@ -38,7 +38,7 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) extern int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2); void git_tree__free(void *tree); -int git_tree__parse(void *tree, const char *buf, const char *buf_end); +int git_tree__parse(void *tree, git_odb_object *obj); /** * Lookup the first position in the tree with a given prefix. diff --git a/tests-clar/commit/parse.c b/tests-clar/commit/parse.c index 792b57626..ad2c746ca 100644 --- a/tests-clar/commit/parse.c +++ b/tests-clar/commit/parse.c @@ -266,32 +266,35 @@ a simple commit which works\n", void test_commit_parse__entire_commit(void) { - const int broken_commit_count = sizeof(failing_commit_cases) / sizeof(*failing_commit_cases); - const int working_commit_count = sizeof(passing_commit_cases) / sizeof(*passing_commit_cases); + const int failing_commit_count = ARRAY_SIZE(failing_commit_cases); + const int passing_commit_count = ARRAY_SIZE(passing_commit_cases); int i; - const char *buf; + git_commit *commit; + git_odb_object fake_odb_object; + memset(&fake_odb_object, 0, sizeof(fake_odb_object)); - for (i = 0; i < broken_commit_count; ++i) { - git_commit *commit; + for (i = 0; i < failing_commit_count; ++i) { commit = (git_commit*)git__malloc(sizeof(git_commit)); memset(commit, 0x0, sizeof(git_commit)); commit->object.repo = g_repo; - buf = failing_commit_cases[i]; - cl_git_fail(git_commit__parse(commit, buf, buf + strlen(buf))); + fake_odb_object.buffer = failing_commit_cases[i]; + fake_odb_object.cached.size = strlen(fake_odb_object.buffer); + + cl_git_fail(git_commit__parse(commit, &fake_odb_object)); git_commit__free(commit); } - for (i = 0; i < working_commit_count; ++i) { - git_commit *commit; - + for (i = 0; i < passing_commit_count; ++i) { commit = (git_commit*)git__malloc(sizeof(git_commit)); memset(commit, 0x0, sizeof(git_commit)); commit->object.repo = g_repo; - buf = passing_commit_cases[i]; - cl_git_pass(git_commit__parse(commit, buf, buf + strlen(buf))); + fake_odb_object.buffer = passing_commit_cases[i]; + fake_odb_object.cached.size = strlen(fake_odb_object.buffer); + + cl_git_pass(git_commit__parse(commit, &fake_odb_object)); if (!i) cl_assert_equal_s("", git_commit_message(commit)); From 116bbdf0446cd5335b73e691c3352f368eac9b8f Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 16 Apr 2013 12:08:21 -0700 Subject: [PATCH 057/134] clean up tree pointer casting --- src/tree.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tree.c b/src/tree.c index d6d4b77d3..58eb92f35 100644 --- a/src/tree.c +++ b/src/tree.c @@ -219,16 +219,16 @@ git_tree_entry *git_tree_entry_dup(const git_tree_entry *entry) return copy; } -void git_tree__free(void *tree) +void git_tree__free(void *_tree) { - git_vector *entries = &((git_tree *)tree)->entries; + git_tree *tree = _tree; size_t i; git_tree_entry *e; - git_vector_foreach(entries, i, e) + git_vector_foreach(&tree->entries, i, e) git_tree_entry_free(e); - git_vector_free(entries); + git_vector_free(&tree->entries); git__free(tree); } @@ -372,13 +372,13 @@ static int tree_error(const char *str, const char *path) return -1; } -int git_tree__parse(void *tree, git_odb_object *odb_obj) +int git_tree__parse(void *_tree, git_odb_object *odb_obj) { + git_tree *tree = _tree; const char *buffer = git_odb_object_data(odb_obj); const char *buffer_end = buffer + git_odb_object_size(odb_obj); - git_vector *tree_entries = &((git_tree *)tree)->entries; - if (git_vector_init(tree_entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) + if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) return -1; while (buffer < buffer_end) { @@ -401,7 +401,7 @@ int git_tree__parse(void *tree, git_odb_object *odb_obj) entry = alloc_entry(buffer); GITERR_CHECK_ALLOC(entry); - if (git_vector_insert(tree_entries, entry) < 0) { + if (git_vector_insert(&tree->entries, entry) < 0) { git__free(entry); return -1; } From 536078688549ac3d50483eecdec5a8169d921927 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 15 Apr 2013 00:09:03 -0700 Subject: [PATCH 058/134] Further threading fixes This builds on the earlier thread safety work to make it so that setting the odb, index, refdb, or config for a repository is done in a threadsafe manner with minimized locking time. This is done by adding a lock to the repository object and using it to guard the assignment of the above listed pointers. The lock is only held to assign the pointer value. This also contains some minor fixes to the other work with pack files to reduce the time that locks are being held to and fix an apparently memory leak. --- src/global.c | 6 ++ src/mwindow.c | 2 +- src/pack.c | 19 ++--- src/pack.h | 2 +- src/refdb_fs.c | 1 - src/repository.c | 214 ++++++++++++++++++++++++++++------------------- src/repository.h | 1 + src/util.h | 21 ++++- 8 files changed, 166 insertions(+), 100 deletions(-) diff --git a/src/global.c b/src/global.c index b7fd8e257..a0571d127 100644 --- a/src/global.c +++ b/src/global.c @@ -135,6 +135,12 @@ int git_threads_init(void) void git_threads_shutdown(void) { + if (_tls_init) { + void *ptr = pthread_getspecific(_tls_key); + pthread_setspecific(_tls_key, NULL); + git__free(ptr); + } + pthread_key_delete(_tls_key); _tls_init = 0; git_mutex_free(&git__mwindow_mutex); diff --git a/src/mwindow.c b/src/mwindow.c index b35503d46..7e5fcdfbc 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -162,7 +162,7 @@ static git_mwindow *new_window( git_mwindow *w; w = git__malloc(sizeof(*w)); - + if (w == NULL) return NULL; diff --git a/src/pack.c b/src/pack.c index 1bffb4778..3a2e7fb5a 100644 --- a/src/pack.c +++ b/src/pack.c @@ -299,29 +299,27 @@ static int pack_index_open(struct git_pack_file *p) int error = 0; size_t name_len, base_len; - if ((error = git_mutex_lock(&p->lock)) < 0) - return error; - if (p->index_map.data) - goto done; + return 0; name_len = strlen(p->pack_name); assert(name_len > strlen(".pack")); /* checked by git_pack_file alloc */ - if ((idx_name = git__malloc(name_len)) == NULL) { - error = -1; - goto done; - } + if ((idx_name = git__malloc(name_len)) == NULL) + return -1; base_len = name_len - strlen(".pack"); memcpy(idx_name, p->pack_name, base_len); memcpy(idx_name + base_len, ".idx", sizeof(".idx")); - error = pack_index_check(idx_name, p); + if ((error = git_mutex_lock(&p->lock)) < 0) + return error; + + if (!p->index_map.data) + error = pack_index_check(idx_name, p); git__free(idx_name); -done: git_mutex_unlock(&p->lock); return error; @@ -820,7 +818,6 @@ void git_packfile_free(struct git_pack_file *p) cache_free(&p->bases); git_mwindow_free_all(&p->mwf); - git_mwindow_file_deregister(&p->mwf); if (p->mwf.fd != -1) p_close(p->mwf.fd); diff --git a/src/pack.h b/src/pack.h index b734ac163..b8014b1ea 100644 --- a/src/pack.h +++ b/src/pack.h @@ -79,7 +79,7 @@ typedef struct { struct git_pack_file { git_mwindow_file mwf; git_map index_map; - git_mutex lock; + git_mutex lock; /* protect updates to mwf and index_map */ uint32_t num_objects; uint32_t num_bad_objects; diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 443871005..742ac6260 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -11,7 +11,6 @@ #include "fileops.h" #include "pack.h" #include "reflog.h" -#include "config.h" #include "refdb.h" #include "refdb_fs.h" diff --git a/src/repository.c b/src/repository.c index cda75b85f..8744b91e6 100644 --- a/src/repository.c +++ b/src/repository.c @@ -32,41 +32,43 @@ #define GIT_TEMPLATE_DIR "/usr/share/git-core/templates" +#define repo_swap_ptr(repo,item_ptr,new_value) \ + git__swap(&repo->lock, (void **)item_ptr, new_value) + static void drop_odb(git_repository *repo) { - if (repo->_odb != NULL) { - GIT_REFCOUNT_OWN(repo->_odb, NULL); - git_odb_free(repo->_odb); - repo->_odb = NULL; + git_odb *dropme = repo_swap_ptr(repo, &repo->_odb, NULL); + if (dropme != NULL) { + GIT_REFCOUNT_OWN(dropme, NULL); + git_odb_free(dropme); } } static void drop_refdb(git_repository *repo) { - if (repo->_refdb != NULL) { - GIT_REFCOUNT_OWN(repo->_refdb, NULL); - git_refdb_free(repo->_refdb); - repo->_refdb = NULL; + git_refdb *dropme = repo_swap_ptr(repo, &repo->_refdb, NULL); + if (dropme != NULL) { + GIT_REFCOUNT_OWN(dropme, NULL); + git_refdb_free(dropme); } } static void drop_config(git_repository *repo) { - if (repo->_config != NULL) { - GIT_REFCOUNT_OWN(repo->_config, NULL); - git_config_free(repo->_config); - repo->_config = NULL; + git_config *dropme = repo_swap_ptr(repo, &repo->_config, NULL); + if (dropme != NULL) { + GIT_REFCOUNT_OWN(dropme, NULL); + git_config_free(dropme); + git_repository__cvar_cache_clear(repo); } - - git_repository__cvar_cache_clear(repo); } static void drop_index(git_repository *repo) { - if (repo->_index != NULL) { - GIT_REFCOUNT_OWN(repo->_index, NULL); - git_index_free(repo->_index); - repo->_index = NULL; + git_index *dropme = repo_swap_ptr(repo, &repo->_index, NULL); + if (dropme != NULL) { + GIT_REFCOUNT_OWN(dropme, NULL); + git_index_free(dropme); } } @@ -79,14 +81,15 @@ void git_repository_free(git_repository *repo) git_attr_cache_flush(repo); git_submodule_config_free(repo); - git__free(repo->path_repository); - git__free(repo->workdir); - drop_config(repo); drop_index(repo); drop_odb(repo); drop_refdb(repo); + git__free(repo->path_repository); + git__free(repo->workdir); + + git_mutex_free(&repo->lock); git__free(repo); } @@ -119,6 +122,8 @@ static git_repository *repository_alloc(void) memset(repo, 0x0, sizeof(git_repository)); + git_mutex_init(&repo->lock); + if (git_cache_init(&repo->objects) < 0) { git__free(repo); return NULL; @@ -549,39 +554,47 @@ on_error: return error; } +static const char *path_unless_empty(git_buf *buf) +{ + return git_buf_len(buf) > 0 ? git_buf_cstr(buf) : NULL; +} + int git_repository_config__weakptr(git_config **out, git_repository *repo) { + int error = 0; + if (repo->_config == NULL) { - git_buf global_buf = GIT_BUF_INIT, xdg_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT; - int res; + git_buf global_buf = GIT_BUF_INIT; + git_buf xdg_buf = GIT_BUF_INIT; + git_buf system_buf = GIT_BUF_INIT; + git_config *config; - const char *global_config_path = NULL; - const char *xdg_config_path = NULL; - const char *system_config_path = NULL; + git_config_find_global_r(&global_buf); + git_config_find_xdg_r(&xdg_buf); + git_config_find_system_r(&system_buf); - if (git_config_find_global_r(&global_buf) == 0) - global_config_path = global_buf.ptr; + error = load_config( + &config, repo, + path_unless_empty(&global_buf), + path_unless_empty(&xdg_buf), + path_unless_empty(&system_buf)); + if (!error) { + GIT_REFCOUNT_OWN(config, repo); - if (git_config_find_xdg_r(&xdg_buf) == 0) - xdg_config_path = xdg_buf.ptr; - - if (git_config_find_system_r(&system_buf) == 0) - system_config_path = system_buf.ptr; - - res = load_config(&repo->_config, repo, global_config_path, xdg_config_path, system_config_path); + config = repo_swap_ptr(repo, &repo->_config, config); + if (config != NULL) { + GIT_REFCOUNT_OWN(config, NULL); + git_config_free(config); + } + } git_buf_free(&global_buf); git_buf_free(&xdg_buf); git_buf_free(&system_buf); - - if (res < 0) - return -1; - - GIT_REFCOUNT_OWN(repo->_config, repo); } *out = repo->_config; - return 0; + return error; } int git_repository_config(git_config **out, git_repository *repo) @@ -597,35 +610,46 @@ void git_repository_set_config(git_repository *repo, git_config *config) { assert(repo && config); - drop_config(repo); + GIT_REFCOUNT_OWN(config, repo); + GIT_REFCOUNT_INC(config); - repo->_config = config; - GIT_REFCOUNT_OWN(repo->_config, repo); - GIT_REFCOUNT_INC(repo->_config); + config = repo_swap_ptr(repo, &repo->_config, config); + if (config != NULL) { + GIT_REFCOUNT_OWN(config, NULL); + git_config_free(config); + } + + git_repository__cvar_cache_clear(repo); } int git_repository_odb__weakptr(git_odb **out, git_repository *repo) { + int error = 0; + assert(repo && out); if (repo->_odb == NULL) { git_buf odb_path = GIT_BUF_INIT; - int res; + git_odb *odb; - if (git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR) < 0) - return -1; + git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR); - res = git_odb_open(&repo->_odb, odb_path.ptr); - git_buf_free(&odb_path); /* done with path */ + error = git_odb_open(&odb, odb_path.ptr); + if (!error) { + GIT_REFCOUNT_OWN(odb, repo); - if (res < 0) - return -1; + odb = repo_swap_ptr(repo, &repo->_odb, odb); + if (odb != NULL) { + GIT_REFCOUNT_OWN(odb, NULL); + git_odb_free(odb); + } + } - GIT_REFCOUNT_OWN(repo->_odb, repo); + git_buf_free(&odb_path); } *out = repo->_odb; - return 0; + return error; } int git_repository_odb(git_odb **out, git_repository *repo) @@ -641,30 +665,39 @@ void git_repository_set_odb(git_repository *repo, git_odb *odb) { assert(repo && odb); - drop_odb(repo); - - repo->_odb = odb; - GIT_REFCOUNT_OWN(repo->_odb, repo); + GIT_REFCOUNT_OWN(odb, repo); GIT_REFCOUNT_INC(odb); + + odb = repo_swap_ptr(repo, &repo->_odb, odb); + if (odb != NULL) { + GIT_REFCOUNT_OWN(odb, NULL); + git_odb_free(odb); + } } int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo) { + int error = 0; + assert(out && repo); if (repo->_refdb == NULL) { - int res; + git_refdb *refdb; - res = git_refdb_open(&repo->_refdb, repo); + error = git_refdb_open(&refdb, repo); + if (!error) { + GIT_REFCOUNT_OWN(refdb, repo); - if (res < 0) - return -1; - - GIT_REFCOUNT_OWN(repo->_refdb, repo); + refdb = repo_swap_ptr(repo, &repo->_refdb, refdb); + if (refdb != NULL) { + GIT_REFCOUNT_OWN(refdb, NULL); + git_refdb_free(refdb); + } + } } *out = repo->_refdb; - return 0; + return error; } int git_repository_refdb(git_refdb **out, git_repository *repo) @@ -678,40 +711,48 @@ int git_repository_refdb(git_refdb **out, git_repository *repo) void git_repository_set_refdb(git_repository *repo, git_refdb *refdb) { - assert (repo && refdb); + assert(repo && refdb); - drop_refdb(repo); - - repo->_refdb = refdb; - GIT_REFCOUNT_OWN(repo->_refdb, repo); + GIT_REFCOUNT_OWN(refdb, repo); GIT_REFCOUNT_INC(refdb); + + refdb = repo_swap_ptr(repo, &repo->_refdb, refdb); + if (refdb != NULL) { + GIT_REFCOUNT_OWN(refdb, NULL); + git_refdb_free(refdb); + } } int git_repository_index__weakptr(git_index **out, git_repository *repo) { + int error = 0; + assert(out && repo); if (repo->_index == NULL) { - int res; git_buf index_path = GIT_BUF_INIT; + git_index *index; - if (git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE) < 0) - return -1; + git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE); - res = git_index_open(&repo->_index, index_path.ptr); - git_buf_free(&index_path); /* done with path */ + error = git_index_open(&index, index_path.ptr); + if (!error) { + GIT_REFCOUNT_OWN(index, repo); - if (res < 0) - return -1; + index = repo_swap_ptr(repo, &repo->_index, index); + if (index != NULL) { + GIT_REFCOUNT_OWN(index, NULL); + git_index_free(index); + } - GIT_REFCOUNT_OWN(repo->_index, repo); + error = git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER); + } - if (git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER) < 0) - return -1; + git_buf_free(&index_path); } *out = repo->_index; - return 0; + return error; } int git_repository_index(git_index **out, git_repository *repo) @@ -727,11 +768,14 @@ void git_repository_set_index(git_repository *repo, git_index *index) { assert(repo && index); - drop_index(repo); - - repo->_index = index; - GIT_REFCOUNT_OWN(repo->_index, repo); + GIT_REFCOUNT_OWN(index, repo); GIT_REFCOUNT_INC(index); + + index = repo_swap_ptr(repo, &repo->_index, index); + if (index != NULL) { + GIT_REFCOUNT_OWN(index, NULL); + git_index_free(index); + } } static int check_repositoryformatversion(git_config *config) diff --git a/src/repository.h b/src/repository.h index cc2f8c2b8..873498de0 100644 --- a/src/repository.h +++ b/src/repository.h @@ -83,6 +83,7 @@ struct git_repository { git_refdb *_refdb; git_config *_config; git_index *_index; + git_mutex lock; git_cache objects; git_attr_cache attrcache; diff --git a/src/util.h b/src/util.h index af3ef0b46..a2233a7e8 100644 --- a/src/util.h +++ b/src/util.h @@ -306,11 +306,30 @@ int git__date_parse(git_time_t *out, const char *date); /* * Unescapes a string in-place. - * + * * Edge cases behavior: * - "jackie\" -> "jacky\" * - "chan\\" -> "chan\" */ extern size_t git__unescape(char *str); +/* + * Swap a pointer with thread safety, returning old value. + */ +GIT_INLINE(void *) git__swap(git_mutex *lock, void **ptr_ptr, void *new_ptr) +{ + void *old_ptr; + + if (*ptr_ptr == new_ptr) + return NULL; + if (git_mutex_lock(lock) < 0) + return new_ptr; + + old_ptr = *ptr_ptr; + *ptr_ptr = new_ptr; + + git_mutex_unlock(lock); + return old_ptr; +} + #endif /* INCLUDE_util_h__ */ From e976b56dda6ae3d7d81bd114b61750e97cc918d3 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 15 Apr 2013 14:27:53 -0700 Subject: [PATCH 059/134] Add git__compare_and_swap and use it This removes the lock from the repository object and changes the internals to use the new atomic git__compare_and_swap to update the _odb, _config, _index, and _refdb variables in a threadsafe manner. --- src/global.h | 8 --- src/repository.c | 132 +++++++++++++++++++-------------------------- src/repository.h | 1 - src/thread-utils.h | 41 ++++++++++++++ src/util.h | 19 ------- 5 files changed, 95 insertions(+), 106 deletions(-) diff --git a/src/global.h b/src/global.h index f0ad1df29..badbc0883 100644 --- a/src/global.h +++ b/src/global.h @@ -10,14 +10,6 @@ #include "mwindow.h" #include "hash.h" -#if defined(GIT_THREADS) && defined(_MSC_VER) -# define GIT_MEMORY_BARRIER MemoryBarrier() -#elif defined(GIT_THREADS) -# define GIT_MEMORY_BARRIER __sync_synchronize() -#else -# define GIT_MEMORY_BARRIER /* noop */ -#endif - typedef struct { git_error *last_error; git_error error_t; diff --git a/src/repository.c b/src/repository.c index 8744b91e6..59479dc92 100644 --- a/src/repository.c +++ b/src/repository.c @@ -32,43 +32,57 @@ #define GIT_TEMPLATE_DIR "/usr/share/git-core/templates" -#define repo_swap_ptr(repo,item_ptr,new_value) \ - git__swap(&repo->lock, (void **)item_ptr, new_value) - -static void drop_odb(git_repository *repo) +static void set_odb(git_repository *repo, git_odb *odb) { - git_odb *dropme = repo_swap_ptr(repo, &repo->_odb, NULL); - if (dropme != NULL) { - GIT_REFCOUNT_OWN(dropme, NULL); - git_odb_free(dropme); + if (odb) { + GIT_REFCOUNT_OWN(odb, repo); + GIT_REFCOUNT_INC(odb); + } + + if ((odb = git__swap(repo->_odb, odb)) != NULL) { + GIT_REFCOUNT_OWN(odb, NULL); + git_odb_free(odb); } } -static void drop_refdb(git_repository *repo) +static void set_refdb(git_repository *repo, git_refdb *refdb) { - git_refdb *dropme = repo_swap_ptr(repo, &repo->_refdb, NULL); - if (dropme != NULL) { - GIT_REFCOUNT_OWN(dropme, NULL); - git_refdb_free(dropme); + if (refdb) { + GIT_REFCOUNT_OWN(refdb, repo); + GIT_REFCOUNT_INC(refdb); + } + + if ((refdb = git__swap(repo->_refdb, refdb)) != NULL) { + GIT_REFCOUNT_OWN(refdb, NULL); + git_refdb_free(refdb); } } -static void drop_config(git_repository *repo) +static void set_config(git_repository *repo, git_config *config) { - git_config *dropme = repo_swap_ptr(repo, &repo->_config, NULL); - if (dropme != NULL) { - GIT_REFCOUNT_OWN(dropme, NULL); - git_config_free(dropme); - git_repository__cvar_cache_clear(repo); + if (config) { + GIT_REFCOUNT_OWN(config, repo); + GIT_REFCOUNT_INC(config); } + + if ((config = git__swap(repo->_config, config)) != NULL) { + GIT_REFCOUNT_OWN(config, NULL); + git_config_free(config); + } + + git_repository__cvar_cache_clear(repo); } -static void drop_index(git_repository *repo) +static void set_index(git_repository *repo, git_index *index) { - git_index *dropme = repo_swap_ptr(repo, &repo->_index, NULL); - if (dropme != NULL) { - GIT_REFCOUNT_OWN(dropme, NULL); - git_index_free(dropme); + if (index) { + GIT_REFCOUNT_OWN(index, repo); + GIT_REFCOUNT_INC(index); + } + + if ((index = git__swap(repo->_index, index)) != NULL) { + GIT_REFCOUNT_OWN(index, NULL); + git_index_free(index); } } @@ -81,15 +95,14 @@ void git_repository_free(git_repository *repo) git_attr_cache_flush(repo); git_submodule_config_free(repo); - drop_config(repo); - drop_index(repo); - drop_odb(repo); - drop_refdb(repo); + set_config(repo, NULL); + set_index(repo, NULL); + set_odb(repo, NULL); + set_refdb(repo, NULL); git__free(repo->path_repository); git__free(repo->workdir); - git_mutex_free(&repo->lock); git__free(repo); } @@ -122,8 +135,6 @@ static git_repository *repository_alloc(void) memset(repo, 0x0, sizeof(git_repository)); - git_mutex_init(&repo->lock); - if (git_cache_init(&repo->objects) < 0) { git__free(repo); return NULL; @@ -581,7 +592,7 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo) if (!error) { GIT_REFCOUNT_OWN(config, repo); - config = repo_swap_ptr(repo, &repo->_config, config); + config = git__compare_and_swap(&repo->_config, NULL, config); if (config != NULL) { GIT_REFCOUNT_OWN(config, NULL); git_config_free(config); @@ -609,17 +620,7 @@ int git_repository_config(git_config **out, git_repository *repo) void git_repository_set_config(git_repository *repo, git_config *config) { assert(repo && config); - - GIT_REFCOUNT_OWN(config, repo); - GIT_REFCOUNT_INC(config); - - config = repo_swap_ptr(repo, &repo->_config, config); - if (config != NULL) { - GIT_REFCOUNT_OWN(config, NULL); - git_config_free(config); - } - - git_repository__cvar_cache_clear(repo); + set_config(repo, config); } int git_repository_odb__weakptr(git_odb **out, git_repository *repo) @@ -638,7 +639,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo) if (!error) { GIT_REFCOUNT_OWN(odb, repo); - odb = repo_swap_ptr(repo, &repo->_odb, odb); + odb = git__compare_and_swap(&repo->_odb, NULL, odb); if (odb != NULL) { GIT_REFCOUNT_OWN(odb, NULL); git_odb_free(odb); @@ -664,15 +665,7 @@ int git_repository_odb(git_odb **out, git_repository *repo) void git_repository_set_odb(git_repository *repo, git_odb *odb) { assert(repo && odb); - - GIT_REFCOUNT_OWN(odb, repo); - GIT_REFCOUNT_INC(odb); - - odb = repo_swap_ptr(repo, &repo->_odb, odb); - if (odb != NULL) { - GIT_REFCOUNT_OWN(odb, NULL); - git_odb_free(odb); - } + set_odb(repo, odb); } int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo) @@ -688,7 +681,7 @@ int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo) if (!error) { GIT_REFCOUNT_OWN(refdb, repo); - refdb = repo_swap_ptr(repo, &repo->_refdb, refdb); + refdb = git__compare_and_swap(&repo->_refdb, NULL, refdb); if (refdb != NULL) { GIT_REFCOUNT_OWN(refdb, NULL); git_refdb_free(refdb); @@ -712,15 +705,7 @@ int git_repository_refdb(git_refdb **out, git_repository *repo) void git_repository_set_refdb(git_repository *repo, git_refdb *refdb) { assert(repo && refdb); - - GIT_REFCOUNT_OWN(refdb, repo); - GIT_REFCOUNT_INC(refdb); - - refdb = repo_swap_ptr(repo, &repo->_refdb, refdb); - if (refdb != NULL) { - GIT_REFCOUNT_OWN(refdb, NULL); - git_refdb_free(refdb); - } + set_refdb(repo, refdb); } int git_repository_index__weakptr(git_index **out, git_repository *repo) @@ -739,7 +724,7 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo) if (!error) { GIT_REFCOUNT_OWN(index, repo); - index = repo_swap_ptr(repo, &repo->_index, index); + index = git__compare_and_swap(&repo->_index, NULL, index); if (index != NULL) { GIT_REFCOUNT_OWN(index, NULL); git_index_free(index); @@ -767,15 +752,7 @@ int git_repository_index(git_index **out, git_repository *repo) void git_repository_set_index(git_repository *repo, git_index *index) { assert(repo && index); - - GIT_REFCOUNT_OWN(index, repo); - GIT_REFCOUNT_INC(index); - - index = repo_swap_ptr(repo, &repo->_index, index); - if (index != NULL) { - GIT_REFCOUNT_OWN(index, NULL); - git_index_free(index); - } + set_index(repo, index); } static int check_repositoryformatversion(git_config *config) @@ -1465,14 +1442,13 @@ static int at_least_one_cb(const char *refname, void *payload) static int repo_contains_no_reference(git_repository *repo) { - int error; - - error = git_reference_foreach(repo, GIT_REF_LISTALL, at_least_one_cb, NULL); + int error = git_reference_foreach(repo, GIT_REF_LISTALL, at_least_one_cb, NULL); if (error == GIT_EUSER) return 0; - - return error == 0 ? 1 : error; + if (!error) + return 1; + return error; } int git_repository_is_empty(git_repository *repo) diff --git a/src/repository.h b/src/repository.h index 873498de0..cc2f8c2b8 100644 --- a/src/repository.h +++ b/src/repository.h @@ -83,7 +83,6 @@ struct git_repository { git_refdb *_refdb; git_config *_config; git_index *_index; - git_mutex lock; git_cache objects; git_attr_cache attrcache; diff --git a/src/thread-utils.h b/src/thread-utils.h index 2ca290adf..7b663182d 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -68,6 +68,21 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a) #endif } +GIT_INLINE(void *) git___compare_and_swap( + volatile void **ptr, void *oldval, void *newval) +{ + bool swapped; +#if defined(GIT_WIN32) + swapped = ((LONGLONG)oldval == InterlockedCompareExchange64( + (LONGLONG volatile *)ptr, (LONGLONG)newval, (LONGLONG)oldval)); +#elif defined(__GNUC__) + swapped = (__sync_val_compare_and_swap(ptr, oldval, newval) == oldval); +#else +# error "Unsupported architecture for atomic operations" +#endif + return swapped ? oldval : newval; +} + #else #define git_thread unsigned int @@ -101,8 +116,34 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a) return --a->val; } +GIT_INLINE(void *) git___compare_and_swap( + volatile void **ptr, void *oldval, void *newval) +{ + if (*ptr == oldval) + *ptr = newval; + else + oldval = newval; + return oldval; +} + #endif +/* Atomically replace oldval with newval + * @return oldval if it was replaced or newval if it was not + */ +#define git__compare_and_swap(P,O,N) \ + git___compare_and_swap((volatile void **)P, O, N) + +#define git__swap(ptr, val) git__compare_and_swap(&ptr, ptr, val) + extern int git_online_cpus(void); +#if defined(GIT_THREADS) && defined(GIT_WIN32) +# define GIT_MEMORY_BARRIER MemoryBarrier() +#elif defined(GIT_THREADS) +# define GIT_MEMORY_BARRIER __sync_synchronize() +#else +# define GIT_MEMORY_BARRIER /* noop */ +#endif + #endif /* INCLUDE_thread_utils_h__ */ diff --git a/src/util.h b/src/util.h index a2233a7e8..82435aee8 100644 --- a/src/util.h +++ b/src/util.h @@ -313,23 +313,4 @@ int git__date_parse(git_time_t *out, const char *date); */ extern size_t git__unescape(char *str); -/* - * Swap a pointer with thread safety, returning old value. - */ -GIT_INLINE(void *) git__swap(git_mutex *lock, void **ptr_ptr, void *new_ptr) -{ - void *old_ptr; - - if (*ptr_ptr == new_ptr) - return NULL; - if (git_mutex_lock(lock) < 0) - return new_ptr; - - old_ptr = *ptr_ptr; - *ptr_ptr = new_ptr; - - git_mutex_unlock(lock); - return old_ptr; -} - #endif /* INCLUDE_util_h__ */ From c628918625c7f779d2050a56998fb2b675f097fb Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 15 Apr 2013 16:31:04 -0700 Subject: [PATCH 060/134] Fixes for Windows cas/threading stuff --- src/thread-utils.h | 9 ++++----- src/win32/pthread.c | 17 +++++++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/thread-utils.h b/src/thread-utils.h index 7b663182d..e53a60c05 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -71,16 +71,15 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a) GIT_INLINE(void *) git___compare_and_swap( volatile void **ptr, void *oldval, void *newval) { - bool swapped; + void *foundval; #if defined(GIT_WIN32) - swapped = ((LONGLONG)oldval == InterlockedCompareExchange64( - (LONGLONG volatile *)ptr, (LONGLONG)newval, (LONGLONG)oldval)); + foundval = InterlockedCompareExchangePointer(ptr, newval, oldval); #elif defined(__GNUC__) - swapped = (__sync_val_compare_and_swap(ptr, oldval, newval) == oldval); + foundval = __sync_val_compare_and_swap(ptr, oldval, newval); #else # error "Unsupported architecture for atomic operations" #endif - return swapped ? oldval : newval; + return (foundval == oldval) ? oldval : newval; } #else diff --git a/src/win32/pthread.c b/src/win32/pthread.c index 105f4b89e..c78213f15 100644 --- a/src/win32/pthread.c +++ b/src/win32/pthread.c @@ -14,18 +14,23 @@ int pthread_create( void *GIT_RESTRICT arg) { GIT_UNUSED(attr); - *thread = (pthread_t) CreateThread( + *thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL); return *thread ? 0 : -1; } int pthread_join(pthread_t thread, void **value_ptr) { - int ret; - ret = WaitForSingleObject(thread, INFINITE); - if (ret && value_ptr) - GetExitCodeThread(thread, (void*) value_ptr); - return -(!!ret); + DWORD ret = WaitForSingleObject(thread, INFINITE); + + if (ret == WAIT_OBJECT_0) { + if (value_ptr != NULL) + GetExitCodeThread(thread, (void *)value_ptr); + CloseHandle(thread); + return 0; + } + + return -1; } int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT mutex, From 38eef6113d8523abfe6746bf727cee2651398ad3 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 16 Apr 2013 14:19:27 -0700 Subject: [PATCH 061/134] Make indexer use shared packfile open code The indexer was creating a packfile object separately from the code in pack.c which was a problem since I put a call to git_mutex_init into just pack.c. This commit updates the pack function for creating a new pack object (i.e. git_packfile_check()) so that it can be used in both places and then makes indexer.c use the shared initialization routine. There are also a few minor formatting and warning message fixes. --- src/indexer.c | 30 ++++++------------------------ src/pack.c | 39 +++++++++++++++++---------------------- src/thread-utils.h | 2 +- src/win32/pthread.c | 5 +++-- src/win32/pthread.h | 11 +++++++---- tests-clar/object/cache.c | 6 +++--- 6 files changed, 37 insertions(+), 56 deletions(-) diff --git a/src/indexer.c b/src/indexer.c index 2cfbd3a5a..50a9d3a37 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -60,36 +60,19 @@ const git_oid *git_indexer_stream_hash(const git_indexer_stream *idx) static int open_pack(struct git_pack_file **out, const char *filename) { - size_t namelen; struct git_pack_file *pack; - struct stat st; - int fd; - namelen = strlen(filename); - pack = git__calloc(1, sizeof(struct git_pack_file) + namelen + 1); - GITERR_CHECK_ALLOC(pack); + if (git_packfile_check(&pack, filename) < 0) + return -1; - memcpy(pack->pack_name, filename, namelen + 1); - - if (p_stat(filename, &st) < 0) { - giterr_set(GITERR_OS, "Failed to stat packfile."); - goto cleanup; - } - - if ((fd = p_open(pack->pack_name, O_RDONLY)) < 0) { + if ((pack->mwf.fd = p_open(pack->pack_name, O_RDONLY)) < 0) { giterr_set(GITERR_OS, "Failed to open packfile."); - goto cleanup; + git_packfile_free(pack); + return -1; } - pack->mwf.fd = fd; - pack->mwf.size = (git_off_t)st.st_size; - *out = pack; return 0; - -cleanup: - git__free(pack); - return -1; } static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack) @@ -391,7 +374,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz { int error = -1; struct git_pack_header hdr; - size_t processed; + size_t processed; git_mwindow_file *mwf = &idx->pack->mwf; assert(idx && data && stats); @@ -404,7 +387,6 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz /* Make sure we set the new size of the pack */ if (idx->opened_pack) { idx->pack->mwf.size += size; - //printf("\nadding %zu for %zu\n", size, idx->pack->mwf.size); } else { if (open_pack(&idx->pack, idx->pack_file.path_lock) < 0) return -1; diff --git a/src/pack.c b/src/pack.c index 3a2e7fb5a..8e8a01aa9 100644 --- a/src/pack.c +++ b/src/pack.c @@ -794,19 +794,6 @@ git_off_t get_delta_base( * ***********************************************************/ -static struct git_pack_file *packfile_alloc(size_t extra) -{ - struct git_pack_file *p = git__calloc(1, sizeof(*p) + extra); - if (!p) - return NULL; - - p->mwf.fd = -1; - git_mutex_init(&p->lock); - - return p; -} - - void git_packfile_free(struct git_pack_file *p) { if (!p) @@ -902,28 +889,33 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) { struct stat st; struct git_pack_file *p; - size_t path_len; + size_t path_len = path ? strlen(path) : 0; *pack_out = NULL; - if (!path || (path_len = strlen(path)) <= strlen(".idx")) + if (path_len < strlen(".idx")) return git_odb__error_notfound("invalid packfile path", NULL); - p = packfile_alloc(path_len + 2); + p = git__calloc(1, sizeof(*p) + path_len + 2); GITERR_CHECK_ALLOC(p); + memcpy(p->pack_name, path, path_len + 1); + /* * Make sure a corresponding .pack file exists and that * the index looks sane. */ - path_len -= strlen(".idx"); - memcpy(p->pack_name, path, path_len); + if (git__suffixcmp(path, ".idx") == 0) { + size_t root_len = path_len - strlen(".idx"); - memcpy(p->pack_name + path_len, ".keep", sizeof(".keep")); - if (git_path_exists(p->pack_name) == true) - p->pack_keep = 1; + memcpy(p->pack_name + root_len, ".keep", sizeof(".keep")); + if (git_path_exists(p->pack_name) == true) + p->pack_keep = 1; + + memcpy(p->pack_name + root_len, ".pack", sizeof(".pack")); + path_len = path_len - strlen(".idx") + strlen(".pack"); + } - memcpy(p->pack_name + path_len, ".pack", sizeof(".pack")); if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) { git__free(p); return git_odb__error_notfound("packfile not found", NULL); @@ -932,10 +924,13 @@ int git_packfile_check(struct git_pack_file **pack_out, const char *path) /* ok, it looks sane as far as we can check without * actually mapping the pack file. */ + p->mwf.fd = -1; p->mwf.size = st.st_size; p->pack_local = 1; p->mtime = (git_time_t)st.st_mtime; + git_mutex_init(&p->lock); + /* see if we can parse the sha1 oid in the packfile name */ if (path_len < 40 || git_oid_fromstr(&p->sha1, path + path_len - GIT_OID_HEXSZ) < 0) diff --git a/src/thread-utils.h b/src/thread-utils.h index e53a60c05..dafe70ad6 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -71,7 +71,7 @@ GIT_INLINE(int) git_atomic_dec(git_atomic *a) GIT_INLINE(void *) git___compare_and_swap( volatile void **ptr, void *oldval, void *newval) { - void *foundval; + volatile void *foundval; #if defined(GIT_WIN32) foundval = InterlockedCompareExchangePointer(ptr, newval, oldval); #elif defined(__GNUC__) diff --git a/src/win32/pthread.c b/src/win32/pthread.c index c78213f15..232709e54 100644 --- a/src/win32/pthread.c +++ b/src/win32/pthread.c @@ -33,8 +33,9 @@ int pthread_join(pthread_t thread, void **value_ptr) return -1; } -int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT mutex, - const pthread_mutexattr_t *GIT_RESTRICT mutexattr) +int pthread_mutex_init( + pthread_mutex_t *GIT_RESTRICT mutex, + const pthread_mutexattr_t *GIT_RESTRICT mutexattr) { GIT_UNUSED(mutexattr); InitializeCriticalSection(mutex); diff --git a/src/win32/pthread.h b/src/win32/pthread.h index a219a0137..8277ecf6e 100644 --- a/src/win32/pthread.h +++ b/src/win32/pthread.h @@ -25,13 +25,16 @@ typedef HANDLE pthread_cond_t; #define PTHREAD_MUTEX_INITIALIZER {(void*)-1}; -int pthread_create(pthread_t *GIT_RESTRICT, - const pthread_attr_t *GIT_RESTRICT, - void *(*start_routine)(void*), void *__restrict); +int pthread_create( + pthread_t *GIT_RESTRICT, + const pthread_attr_t *GIT_RESTRICT, + void *(*start_routine)(void*), + void *__restrict); int pthread_join(pthread_t, void **); -int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT, const pthread_mutexattr_t *GIT_RESTRICT); +int pthread_mutex_init( + pthread_mutex_t *GIT_RESTRICT, const pthread_mutexattr_t *GIT_RESTRICT); int pthread_mutex_destroy(pthread_mutex_t *); int pthread_mutex_lock(pthread_mutex_t *); int pthread_mutex_unlock(pthread_mutex_t *); diff --git a/tests-clar/object/cache.c b/tests-clar/object/cache.c index 8121247c9..ed13a6fa8 100644 --- a/tests-clar/object/cache.c +++ b/tests-clar/object/cache.c @@ -213,16 +213,16 @@ void test_object_cache__threadmania(void) fn = (th & 1) ? cache_parsed : cache_raw; #ifdef GIT_THREADS - git_thread_create(&t[th], NULL, fn, data); + cl_git_pass(git_thread_create(&t[th], NULL, fn, data)); #else - fn(data); + cl_assert(fn(data) == data); git__free(data); #endif } #ifdef GIT_THREADS for (th = 0; th < THREADCOUNT; ++th) { - git_thread_join(t[th], &data); + cl_git_pass(git_thread_join(t[th], &data)); cl_assert_equal_i(th, ((int *)data)[0]); git__free(data); } From 5d2d21e536b83ca2cbf8c026b3149fdf776c3f58 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 16 Apr 2013 15:00:43 -0700 Subject: [PATCH 062/134] Consolidate packfile allocation further Rename git_packfile_check to git_packfile_alloc since it is now being used more in that capacity. Fix the various places that use it. Consolidate some repeated code in odb_pack.c related to the allocation of a new pack_backend. --- src/indexer.c | 2 +- src/odb_pack.c | 107 +++++++++++++++++++++++-------------------------- src/pack.c | 2 +- src/pack.h | 3 +- 4 files changed, 55 insertions(+), 59 deletions(-) diff --git a/src/indexer.c b/src/indexer.c index 50a9d3a37..606771927 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -62,7 +62,7 @@ static int open_pack(struct git_pack_file **out, const char *filename) { struct git_pack_file *pack; - if (git_packfile_check(&pack, filename) < 0) + if (git_packfile_alloc(&pack, filename) < 0) return -1; if ((pack->mwf.fd = p_open(pack->pack_name, O_RDONLY)) < 0) { diff --git a/src/odb_pack.c b/src/odb_pack.c index 773e14974..eec79259b 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -207,7 +207,7 @@ static int packfile_load__cb(void *_data, git_buf *path) return 0; } - error = git_packfile_check(&pack, path->ptr); + error = git_packfile_alloc(&pack, path->ptr); if (error == GIT_ENOTFOUND) /* ignore missing .pack file as git does */ return 0; @@ -527,67 +527,17 @@ static void pack_backend__free(git_odb_backend *_backend) git__free(backend); } -int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx) +static int pack_backend__alloc(struct pack_backend **out, size_t initial_size) { - struct pack_backend *backend = NULL; - struct git_pack_file *packfile = NULL; - - if (git_packfile_check(&packfile, idx) < 0) - return -1; - - backend = git__calloc(1, sizeof(struct pack_backend)); + struct pack_backend *backend = git__calloc(1, sizeof(struct pack_backend)); GITERR_CHECK_ALLOC(backend); - backend->parent.version = GIT_ODB_BACKEND_VERSION; - if (git_vector_init(&backend->packs, 1, NULL) < 0) - goto on_error; - - if (git_vector_insert(&backend->packs, packfile) < 0) - goto on_error; - - backend->parent.read = &pack_backend__read; - backend->parent.read_prefix = &pack_backend__read_prefix; - backend->parent.read_header = &pack_backend__read_header; - backend->parent.exists = &pack_backend__exists; - backend->parent.refresh = &pack_backend__refresh; - backend->parent.foreach = &pack_backend__foreach; - backend->parent.free = &pack_backend__free; - - *backend_out = (git_odb_backend *)backend; - - return 0; - -on_error: - git_vector_free(&backend->packs); - git__free(backend); - git__free(packfile); - return -1; -} - -int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) -{ - struct pack_backend *backend = NULL; - git_buf path = GIT_BUF_INIT; - - backend = git__calloc(1, sizeof(struct pack_backend)); - GITERR_CHECK_ALLOC(backend); - backend->parent.version = GIT_ODB_BACKEND_VERSION; - - if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < 0 || - git_buf_joinpath(&path, objects_dir, "pack") < 0) - { + if (git_vector_init(&backend->packs, initial_size, packfile_sort__cb) < 0) { git__free(backend); return -1; } - if (git_path_isdir(git_buf_cstr(&path)) == true) { - int error; - - backend->pack_folder = git_buf_detach(&path); - error = pack_backend__refresh((git_odb_backend *)backend); - if (error < 0) - return error; - } + backend->parent.version = GIT_ODB_BACKEND_VERSION; backend->parent.read = &pack_backend__read; backend->parent.read_prefix = &pack_backend__read_prefix; @@ -598,9 +548,54 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) backend->parent.writepack = &pack_backend__writepack; backend->parent.free = &pack_backend__free; + *out = backend; + return 0; +} + +int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx) +{ + struct pack_backend *backend = NULL; + struct git_pack_file *packfile = NULL; + + if (pack_backend__alloc(&backend, 1) < 0) + return -1; + + if (git_packfile_alloc(&packfile, idx) < 0 || + git_vector_insert(&backend->packs, packfile) < 0) + { + pack_backend__free((git_odb_backend *)backend); + return -1; + } + + *backend_out = (git_odb_backend *)backend; + return 0; +} + +int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) +{ + int error = 0; + struct pack_backend *backend = NULL; + git_buf path = GIT_BUF_INIT; + + if (pack_backend__alloc(&backend, 8) < 0) + return -1; + + if (!(error = git_buf_joinpath(&path, objects_dir, "pack")) && + git_path_isdir(git_buf_cstr(&path))) + { + backend->pack_folder = git_buf_detach(&path); + + error = pack_backend__refresh((git_odb_backend *)backend); + } + + if (error < 0) { + pack_backend__free((git_odb_backend *)backend); + backend = NULL; + } + *backend_out = (git_odb_backend *)backend; git_buf_free(&path); - return 0; + return error; } diff --git a/src/pack.c b/src/pack.c index 8e8a01aa9..33cdf760a 100644 --- a/src/pack.c +++ b/src/pack.c @@ -885,7 +885,7 @@ cleanup: return -1; } -int git_packfile_check(struct git_pack_file **pack_out, const char *path) +int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) { struct stat st; struct git_pack_file *p; diff --git a/src/pack.h b/src/pack.h index b8014b1ea..aeeac9ce1 100644 --- a/src/pack.h +++ b/src/pack.h @@ -143,7 +143,8 @@ git_off_t get_delta_base(struct git_pack_file *p, git_mwindow **w_curs, git_off_t delta_obj_offset); void git_packfile_free(struct git_pack_file *p); -int git_packfile_check(struct git_pack_file **pack_out, const char *path); +int git_packfile_alloc(struct git_pack_file **pack_out, const char *path); + int git_pack_entry_find( struct git_pack_entry *e, struct git_pack_file *p, From 865e2dd4440596d7cd874556a694eea30336c69b Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 17 Apr 2013 23:58:37 +0200 Subject: [PATCH 063/134] tests: Cleanup commit parse testing code --- tests-clar/commit/parse.c | 45 ++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/tests-clar/commit/parse.c b/tests-clar/commit/parse.c index ad2c746ca..8de4401dc 100644 --- a/tests-clar/commit/parse.c +++ b/tests-clar/commit/parse.c @@ -264,37 +264,40 @@ gpgsig -----BEGIN PGP SIGNATURE-----\n\ a simple commit which works\n", }; +static int parse_commit(git_commit **out, const char *buffer) +{ + git_commit *commit; + git_odb_object fake_odb_object; + int error; + + commit = (git_commit*)git__malloc(sizeof(git_commit)); + memset(commit, 0x0, sizeof(git_commit)); + commit->object.repo = g_repo; + + memset(&fake_odb_object, 0x0, sizeof(git_odb_object)); + fake_odb_object.buffer = (char *)buffer; + fake_odb_object.cached.size = strlen(fake_odb_object.buffer); + + error = git_commit__parse(commit, &fake_odb_object); + + *out = commit; + return error; +} + void test_commit_parse__entire_commit(void) { const int failing_commit_count = ARRAY_SIZE(failing_commit_cases); const int passing_commit_count = ARRAY_SIZE(passing_commit_cases); int i; git_commit *commit; - git_odb_object fake_odb_object; - memset(&fake_odb_object, 0, sizeof(fake_odb_object)); for (i = 0; i < failing_commit_count; ++i) { - commit = (git_commit*)git__malloc(sizeof(git_commit)); - memset(commit, 0x0, sizeof(git_commit)); - commit->object.repo = g_repo; - - fake_odb_object.buffer = failing_commit_cases[i]; - fake_odb_object.cached.size = strlen(fake_odb_object.buffer); - - cl_git_fail(git_commit__parse(commit, &fake_odb_object)); - + cl_git_fail(parse_commit(&commit, failing_commit_cases[i])); git_commit__free(commit); } for (i = 0; i < passing_commit_count; ++i) { - commit = (git_commit*)git__malloc(sizeof(git_commit)); - memset(commit, 0x0, sizeof(git_commit)); - commit->object.repo = g_repo; - - fake_odb_object.buffer = passing_commit_cases[i]; - fake_odb_object.cached.size = strlen(fake_odb_object.buffer); - - cl_git_pass(git_commit__parse(commit, &fake_odb_object)); + cl_git_pass(parse_commit(&commit, passing_commit_cases[i])); if (!i) cl_assert_equal_s("", git_commit_message(commit)); @@ -387,9 +390,7 @@ This commit has a few LF at the start of the commit message"; memset(commit, 0x0, sizeof(git_commit)); commit->object.repo = g_repo; - cl_git_pass(git_commit__parse_buffer(commit, buffer, strlen(buffer))); - + cl_git_pass(parse_commit(&commit, buffer)); cl_assert_equal_s(message, git_commit_message(commit)); - git_commit__free(commit); } From cf9709b64eb49d5a0ee1181b80c950e518fb45b0 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 22 Apr 2013 16:53:46 +0200 Subject: [PATCH 064/134] tests: Do not warn for unused variable --- tests-clar/object/cache.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests-clar/object/cache.c b/tests-clar/object/cache.c index ed13a6fa8..b36bf2726 100644 --- a/tests-clar/object/cache.c +++ b/tests-clar/object/cache.c @@ -195,10 +195,13 @@ static void *cache_raw(void *arg) void test_object_cache__threadmania(void) { int try, th, max_i; - git_thread t[THREADCOUNT]; void *data; void *(*fn)(void *); +#ifdef GIT_THREADS + git_thread t[THREADCOUNT]; +#endif + for (max_i = 0; g_data[max_i].sha != NULL; ++max_i) /* count up */; From d87715926049390a2417a2476742114ec966686a Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 22 Apr 2013 17:04:52 +0200 Subject: [PATCH 065/134] cache: Max cache size, and evict when the cache fills up --- include/git2/common.h | 3 ++- src/cache.c | 25 ++++++++++++++++++------- src/cache.h | 1 + src/util.c | 6 +++++- tests-clar/object/cache.c | 6 +++--- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 80d83d345..ccd252fda 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -131,7 +131,8 @@ enum { GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, GIT_OPT_GET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH, - GIT_OPT_SET_CACHE_LIMIT, + GIT_OPT_SET_CACHE_OBJECT_LIMIT, + GIT_OPT_SET_CACHE_MAX_SIZE, GIT_OPT_ENABLE_CACHING }; diff --git a/src/cache.c b/src/cache.c index c51be895e..ca122fb77 100644 --- a/src/cache.c +++ b/src/cache.c @@ -18,6 +18,7 @@ GIT__USE_OIDMAP bool git_cache__enabled = true; +size_t git_cache__max_storage = (4 * 1024 * 1024); static size_t git_cache__max_object_size[8] = { 0, /* GIT_OBJ__EXT1 */ @@ -70,19 +71,25 @@ int git_cache_init(git_cache *cache) return 0; } -void git_cache_clear(git_cache *cache) +/* called with lock */ +static void clear_cache(git_cache *cache) { git_cached_obj *evict = NULL; - if (git_mutex_lock(&cache->lock) < 0) - return; - kh_foreach_value(cache->map, evict, { git_cached_obj_decref(evict); }); kh_clear(oid, cache->map); cache->used_memory = 0; +} + +void git_cache_clear(git_cache *cache) +{ + if (git_mutex_lock(&cache->lock) < 0) + return; + + clear_cache(cache); git_mutex_unlock(&cache->lock); } @@ -95,14 +102,15 @@ void git_cache_free(git_cache *cache) git_mutex_free(&cache->lock); } -/* Call with lock, yo */ -static void cache_evict_entries(git_cache *cache, size_t evict_count) +/* Called with lock */ +static void cache_evict_entries(git_cache *cache) { uint32_t seed = rand(); + size_t evict_count = 8; /* do not infinite loop if there's not enough entries to evict */ if (evict_count > kh_size(cache->map)) { - git_cache_clear(cache); + clear_cache(cache); return; } @@ -163,6 +171,9 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) if (git_mutex_lock(&cache->lock) < 0) return entry; + if (cache->used_memory > git_cache__max_storage) + cache_evict_entries(cache); + pos = kh_get(oid, cache->map, &entry->oid); /* not found */ diff --git a/src/cache.h b/src/cache.h index e95d521fe..1715c7220 100644 --- a/src/cache.h +++ b/src/cache.h @@ -35,6 +35,7 @@ typedef struct { } git_cache; extern bool git_cache__enabled; +extern size_t git_cache__max_storage; int git_cache_set_max_object_size(git_otype type, size_t size); diff --git a/src/util.c b/src/util.c index 1ed5d5d16..c3fc69756 100644 --- a/src/util.c +++ b/src/util.c @@ -95,7 +95,7 @@ int git_libgit2_opts(int key, ...) error = git_futils_dirs_set(error, va_arg(ap, const char *)); break; - case GIT_OPT_SET_CACHE_LIMIT: + case GIT_OPT_SET_CACHE_OBJECT_LIMIT: { git_otype type = (git_otype)va_arg(ap, int); size_t size = va_arg(ap, size_t); @@ -103,6 +103,10 @@ int git_libgit2_opts(int key, ...) break; } + case GIT_OPT_SET_CACHE_MAX_SIZE: + git_cache__max_storage = va_arg(ap, size_t); + break; + case GIT_OPT_ENABLE_CACHING: git_cache__enabled = (va_arg(ap, int) != 0); break; diff --git a/tests-clar/object/cache.c b/tests-clar/object/cache.c index b36bf2726..a3eba8737 100644 --- a/tests-clar/object/cache.c +++ b/tests-clar/object/cache.c @@ -13,7 +13,7 @@ void test_object_cache__cleanup(void) git_repository_free(g_repo); g_repo = NULL; - git_libgit2_opts(GIT_OPT_SET_CACHE_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); + git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); } static struct { @@ -54,7 +54,7 @@ void test_object_cache__cache_everything(void) git_odb *odb; git_libgit2_opts( - GIT_OPT_SET_CACHE_LIMIT, (int)GIT_OBJ_BLOB, (size_t)32767); + GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)32767); cl_git_pass(git_repository_odb(&odb, g_repo)); @@ -103,7 +103,7 @@ void test_object_cache__cache_no_blobs(void) git_object *obj; git_odb *odb; - git_libgit2_opts(GIT_OPT_SET_CACHE_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); + git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); cl_git_pass(git_repository_odb(&odb, g_repo)); From 05b179648aca91799274afbd03d40f31783547ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 21 Apr 2013 19:26:35 +0200 Subject: [PATCH 066/134] Make refcounting atomic --- src/util.h | 8 ++++---- tests-clar/repo/getters.c | 4 ++-- tests-clar/repo/setters.c | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/util.h b/src/util.h index 82435aee8..687afe084 100644 --- a/src/util.h +++ b/src/util.h @@ -188,20 +188,20 @@ extern int git__strncmp(const char *a, const char *b, size_t sz); extern int git__strncasecmp(const char *a, const char *b, size_t sz); typedef struct { - short refcount; + git_atomic refcount; void *owner; } git_refcount; typedef void (*git_refcount_freeptr)(void *r); #define GIT_REFCOUNT_INC(r) { \ - ((git_refcount *)(r))->refcount++; \ + git_atomic_inc(&((git_refcount *)(r))->refcount); \ } #define GIT_REFCOUNT_DEC(_r, do_free) { \ git_refcount *r = (git_refcount *)(_r); \ - r->refcount--; \ - if (r->refcount <= 0 && r->owner == NULL) { do_free(_r); } \ + int val = git_atomic_dec(&r->refcount); \ + if (val <= 0 && r->owner == NULL) { do_free(_r); } \ } #define GIT_REFCOUNT_OWN(r, o) { \ diff --git a/tests-clar/repo/getters.c b/tests-clar/repo/getters.c index b372f5b70..b8ede126c 100644 --- a/tests-clar/repo/getters.c +++ b/tests-clar/repo/getters.c @@ -31,10 +31,10 @@ void test_repo_getters__retrieving_the_odb_honors_the_refcount(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_odb(&odb, repo)); - cl_assert(((git_refcount *)odb)->refcount == 2); + cl_assert(((git_refcount *)odb)->refcount.val == 2); git_repository_free(repo); - cl_assert(((git_refcount *)odb)->refcount == 1); + cl_assert(((git_refcount *)odb)->refcount.val == 1); git_odb_free(odb); } diff --git a/tests-clar/repo/setters.c b/tests-clar/repo/setters.c index 063d76c8d..f34f1e471 100644 --- a/tests-clar/repo/setters.c +++ b/tests-clar/repo/setters.c @@ -69,13 +69,13 @@ void test_repo_setters__setting_a_new_index_on_a_repo_which_has_already_loaded_o git_index *new_index; cl_git_pass(git_index_open(&new_index, "./my-index")); - cl_assert(((git_refcount *)new_index)->refcount == 1); + cl_assert(((git_refcount *)new_index)->refcount.val == 1); git_repository_set_index(repo, new_index); - cl_assert(((git_refcount *)new_index)->refcount == 2); + cl_assert(((git_refcount *)new_index)->refcount.val == 2); git_repository_free(repo); - cl_assert(((git_refcount *)new_index)->refcount == 1); + cl_assert(((git_refcount *)new_index)->refcount.val == 1); git_index_free(new_index); @@ -90,13 +90,13 @@ void test_repo_setters__setting_a_new_odb_on_a_repo_which_already_loaded_one_pro git_odb *new_odb; cl_git_pass(git_odb_open(&new_odb, "./testrepo.git/objects")); - cl_assert(((git_refcount *)new_odb)->refcount == 1); + cl_assert(((git_refcount *)new_odb)->refcount.val == 1); git_repository_set_odb(repo, new_odb); - cl_assert(((git_refcount *)new_odb)->refcount == 2); + cl_assert(((git_refcount *)new_odb)->refcount.val == 2); git_repository_free(repo); - cl_assert(((git_refcount *)new_odb)->refcount == 1); + cl_assert(((git_refcount *)new_odb)->refcount.val == 1); git_odb_free(new_odb); From f9774eea3a37e3a2a44d3c7e9dbc895280c3d90a Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 22 Apr 2013 17:22:31 +0200 Subject: [PATCH 067/134] atomic: Add an atomic type for 64-bit operations --- src/thread-utils.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/thread-utils.h b/src/thread-utils.h index dafe70ad6..28ecd297e 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -18,6 +18,14 @@ typedef struct { #endif } git_atomic; +typedef struct { +#if defined(GIT_WIN32) + __int64 val; +#else + int64_t val; +#endif +} git_atomic64; + GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) { a->val = val; @@ -57,6 +65,17 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a) #endif } +GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) +{ +#if defined(GIT_WIN32) + return _InterlockedExchangeAdd(&a->val, addend); +#elif defined(__GNUC__) + return __sync_add_and_fetch(&a->val, addend); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + GIT_INLINE(int) git_atomic_dec(git_atomic *a) { #if defined(GIT_WIN32) @@ -82,6 +101,17 @@ GIT_INLINE(void *) git___compare_and_swap( return (foundval == oldval) ? oldval : newval; } +GIT_INLINE(int) git_atomic64_add(git_atomic64 *a, int64_t addend) +{ +#if defined(GIT_WIN32) + return _InterlockedExchangeAdd64(&a->val, addend); +#elif defined(__GNUC__) + return __sync_add_and_fetch(&a->val, addend); +#else +# error "Unsupported architecture for atomic operations" +#endif +} + #else #define git_thread unsigned int @@ -110,6 +140,12 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a) return ++a->val; } +GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) +{ + a->val += addend; + return a->val; +} + GIT_INLINE(int) git_atomic_dec(git_atomic *a) { return --a->val; @@ -125,6 +161,12 @@ GIT_INLINE(void *) git___compare_and_swap( return oldval; } +GIT_INLINE(int) git_atomic64_add(git_atomic64 *a, int64_t addend) +{ + a->val += addend; + return a->val; +} + #endif /* Atomically replace oldval with newval From a14163a79d644f0fd2856b083f355f2df19f6bdd Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 22 Apr 2013 17:30:49 +0200 Subject: [PATCH 068/134] cache: Shared meter for memory usage --- src/cache.c | 16 ++++++++++++---- src/cache.h | 4 ++-- src/util.c | 3 +-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/cache.c b/src/cache.c index ca122fb77..4b26d4351 100644 --- a/src/cache.c +++ b/src/cache.c @@ -18,7 +18,9 @@ GIT__USE_OIDMAP bool git_cache__enabled = true; -size_t git_cache__max_storage = (4 * 1024 * 1024); +int64_t git_cache__max_storage = (4 * 1024 * 1024); + +static git_atomic64 git_cache__current_storage = {0}; static size_t git_cache__max_object_size[8] = { 0, /* GIT_OBJ__EXT1 */ @@ -81,6 +83,7 @@ static void clear_cache(git_cache *cache) }); kh_clear(oid, cache->map); + git_atomic64_add(&git_cache__current_storage, -cache->used_memory); cache->used_memory = 0; } @@ -106,7 +109,7 @@ void git_cache_free(git_cache *cache) static void cache_evict_entries(git_cache *cache) { uint32_t seed = rand(); - size_t evict_count = 8; + int64_t evicted_memory = 0, evict_count = 8; /* do not infinite loop if there's not enough entries to evict */ if (evict_count > kh_size(cache->map)) { @@ -121,12 +124,15 @@ static void cache_evict_entries(git_cache *cache) git_cached_obj *evict = kh_val(cache->map, pos); evict_count--; - cache->used_memory -= evict->size; + evicted_memory += evict->size; git_cached_obj_decref(evict); kh_del(oid, cache->map, pos); } } + + cache->used_memory -= evicted_memory; + git_atomic64_add(&git_cache__current_storage, -evicted_memory); } static bool cache_should_store(git_otype object_type, size_t object_size) @@ -171,7 +177,8 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) if (git_mutex_lock(&cache->lock) < 0) return entry; - if (cache->used_memory > git_cache__max_storage) + /* soften the load on the cache */ + if (git_cache__current_storage.val > git_cache__max_storage) cache_evict_entries(cache); pos = kh_get(oid, cache->map, &entry->oid); @@ -186,6 +193,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) kh_val(cache->map, pos) = entry; git_cached_obj_incref(entry); cache->used_memory += entry->size; + git_atomic64_add(&git_cache__current_storage, (int64_t)entry->size); } } /* found */ diff --git a/src/cache.h b/src/cache.h index 1715c7220..f74fddfc9 100644 --- a/src/cache.h +++ b/src/cache.h @@ -31,11 +31,11 @@ typedef struct { typedef struct { git_oidmap *map; git_mutex lock; - size_t used_memory; + int64_t used_memory; } git_cache; extern bool git_cache__enabled; -extern size_t git_cache__max_storage; +extern int64_t git_cache__max_storage; int git_cache_set_max_object_size(git_otype type, size_t size); diff --git a/src/util.c b/src/util.c index c3fc69756..2dec49f17 100644 --- a/src/util.c +++ b/src/util.c @@ -39,7 +39,6 @@ int git_libgit2_capabilities() /* Declarations for tuneable settings */ extern size_t git_mwindow__window_size; extern size_t git_mwindow__mapped_limit; -extern size_t git_odb__cache_size; static int config_level_to_futils_dir(int config_level) { @@ -104,7 +103,7 @@ int git_libgit2_opts(int key, ...) } case GIT_OPT_SET_CACHE_MAX_SIZE: - git_cache__max_storage = va_arg(ap, size_t); + git_cache__max_storage = va_arg(ap, int64_t); break; case GIT_OPT_ENABLE_CACHING: From 920cbc9846c526958f6b4a7f914bdde2da1d34ec Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 22 Apr 2013 17:31:47 +0200 Subject: [PATCH 069/134] cache: More aggressive default --- src/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cache.c b/src/cache.c index 4b26d4351..b462af408 100644 --- a/src/cache.c +++ b/src/cache.c @@ -18,7 +18,7 @@ GIT__USE_OIDMAP bool git_cache__enabled = true; -int64_t git_cache__max_storage = (4 * 1024 * 1024); +int64_t git_cache__max_storage = (256 * 1024 * 1024); static git_atomic64 git_cache__current_storage = {0}; From a5de9044270e29b2388185bec02d7c0de301e7d1 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 23 Apr 2013 02:24:44 +0200 Subject: [PATCH 070/134] refs: Better error name --- src/refdb_fs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 742ac6260..2f2e67104 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -240,7 +240,7 @@ parse_failed: return -1; } -static int loose_parse_oid(git_oid *oid, git_buf *file_content) +static int loose_parse_oid(git_oid *oid, const char *filename, git_buf *file_content) { size_t len; const char *str; @@ -262,7 +262,7 @@ static int loose_parse_oid(git_oid *oid, git_buf *file_content) return 0; corrupted: - giterr_set(GITERR_REFERENCE, "Corrupted loose reference file"); + giterr_set(GITERR_REFERENCE, "Corrupted loose reference file: %s", filename); return -1; } @@ -289,7 +289,7 @@ static int loose_lookup_to_packfile( memcpy(ref->name, name, name_len); ref->name[name_len] = 0; - if (loose_parse_oid(&ref->oid, &ref_file) < 0) { + if (loose_parse_oid(&ref->oid, name, &ref_file) < 0) { git_buf_free(&ref_file); git__free(ref); return -1; @@ -431,7 +431,7 @@ static int loose_lookup( *out = git_reference__alloc_symbolic(ref_name, target); } else { - if ((error = loose_parse_oid(&oid, &ref_file)) < 0) + if ((error = loose_parse_oid(&oid, ref_name, &ref_file)) < 0) goto done; *out = git_reference__alloc(ref_name, &oid, NULL); From 6c1b6b7abcef75d421e4d59c397eff54cc1f28aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 23 Apr 2013 16:21:47 +0200 Subject: [PATCH 071/134] examples: init the threading system --- examples/network/git2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/network/git2.c b/examples/network/git2.c index ecb16630b..5b32ac809 100644 --- a/examples/network/git2.c +++ b/examples/network/git2.c @@ -54,6 +54,8 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + git_threads_init(); + for (i = 0; commands[i].name != NULL; ++i) { if (!strcmp(argv[1], commands[i].name)) return run_command(commands[i].fn, --argc, ++argv); From f0e37a8b863c2e6caba2b15e4d723bddfe74b46c Mon Sep 17 00:00:00 2001 From: Xavier L Date: Tue, 23 Apr 2013 12:22:29 -0400 Subject: [PATCH 072/134] Added function to insert commit into pack --- include/git2/pack.h | 12 ++++++++++++ src/pack-objects.c | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/include/git2/pack.h b/include/git2/pack.h index 2f033bef6..118b8d554 100644 --- a/include/git2/pack.h +++ b/include/git2/pack.h @@ -94,6 +94,18 @@ GIT_EXTERN(int) git_packbuilder_insert(git_packbuilder *pb, const git_oid *id, c */ GIT_EXTERN(int) git_packbuilder_insert_tree(git_packbuilder *pb, const git_oid *id); +/** + * Insert a commit object + * + * This will add a commit as well as the completed referenced tree. + * + * @param pb The packbuilder + * @param id The oid of the commit + * + * @return 0 or an error code + */ +GIT_EXTERN(int) git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *id); + /** * Write the new pack and the corresponding index to path * diff --git a/src/pack-objects.c b/src/pack-objects.c index 459201f58..56240125b 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -1284,6 +1284,21 @@ static int cb_tree_walk(const char *root, const git_tree_entry *entry, void *pay git_buf_cstr(&ctx->buf)); } +int git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *oid) +{ +git_commit *commit; + +if (git_commit_lookup(&commit, pb->repo, oid) < 0 || +git_packbuilder_insert(pb, oid, NULL) < 0) +return -1; + +if (git_packbuilder_insert_tree(pb, git_commit_tree_id(commit)) < 0) +return -1; + +git_commit_free(commit); +return 0; +} + int git_packbuilder_insert_tree(git_packbuilder *pb, const git_oid *oid) { git_tree *tree; From 0b90366c3bf5c7149cf69b5fa1a8327032f8a60f Mon Sep 17 00:00:00 2001 From: Xavier L Date: Tue, 23 Apr 2013 12:27:38 -0400 Subject: [PATCH 073/134] Fixes indentation --- src/pack-objects.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pack-objects.c b/src/pack-objects.c index 56240125b..1329a9bc1 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -1286,17 +1286,17 @@ static int cb_tree_walk(const char *root, const git_tree_entry *entry, void *pay int git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *oid) { -git_commit *commit; + git_commit *commit; -if (git_commit_lookup(&commit, pb->repo, oid) < 0 || -git_packbuilder_insert(pb, oid, NULL) < 0) -return -1; + if (git_commit_lookup(&commit, pb->repo, oid) < 0 || + git_packbuilder_insert(pb, oid, NULL) < 0) + return -1; -if (git_packbuilder_insert_tree(pb, git_commit_tree_id(commit)) < 0) -return -1; + if (git_packbuilder_insert_tree(pb, git_commit_tree_id(commit)) < 0) + return -1; -git_commit_free(commit); -return 0; + git_commit_free(commit); + return 0; } int git_packbuilder_insert_tree(git_packbuilder *pb, const git_oid *oid) From 9a9de29d36c82d20a821b9b076ad388364bc5553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 23 Apr 2013 19:08:13 +0200 Subject: [PATCH 074/134] Document the odb backend constructors --- include/git2/odb_backend.h | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h index d38005d15..4c2493a25 100644 --- a/include/git2/odb_backend.h +++ b/include/git2/odb_backend.h @@ -19,11 +19,43 @@ */ GIT_BEGIN_DECL -/** +/* * Constructors for in-box ODB backends. */ + +/** + * Create a backend for the packfiles. + * + * @param out location to store the odb backend pointer + * @param objects_dir the Git repository's objects directory + * + * @return 0 or an error code + */ GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_dir); + +/** + * Create a backend for loose objects + * + * @param out location to store the odb backend pointer + * @param objects_dir the Git repository's objects directory + * @param compression_level zlib compression level to use + * @param do_fsync whether to do an fsync() after writing (currently ignored) + * + * @return 0 or an error code + */ GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects_dir, int compression_level, int do_fsync); + +/** + * Create a backend out of a single packfile + * + * This can be useful for inspecting the contents of a single + * packfile. + * + * @param out location to store the odb backend pointer + * @param index_file path to the packfile's .idx file + * + * @return 0 or an error code + */ GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file); /** Streaming mode */ From a952b9867d21b032655ac6c0eaabb558e7875926 Mon Sep 17 00:00:00 2001 From: Nikolai Vladimirov Date: Tue, 23 Apr 2013 21:28:28 +0300 Subject: [PATCH 075/134] remove git_remote_pushspec --- include/git2/remote.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 5dcd93099..f02b95678 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -181,15 +181,6 @@ GIT_EXTERN(int) git_remote_add_push(git_remote *remote, const char *refspec); */ GIT_EXTERN(int) git_remote_get_push_refspecs(git_strarray *array, git_remote *remote); -/** - * Get the push refspec - * - * @param remote the remote - * @return a pointer to the push refspec or NULL if it doesn't exist - */ - -GIT_EXTERN(const git_refspec *) git_remote_pushspec(const git_remote *remote); - /** * Clear the refspecs * From a2378ae4fee55c95eb9a1f6b44f5a837d39fa724 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 23 Apr 2013 20:42:29 +0200 Subject: [PATCH 076/134] opts: Add getter for cached memory --- include/git2/common.h | 3 ++- src/cache.c | 3 +-- src/cache.h | 1 + src/util.c | 5 +++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index ccd252fda..6101e13bc 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -133,7 +133,8 @@ enum { GIT_OPT_SET_SEARCH_PATH, GIT_OPT_SET_CACHE_OBJECT_LIMIT, GIT_OPT_SET_CACHE_MAX_SIZE, - GIT_OPT_ENABLE_CACHING + GIT_OPT_ENABLE_CACHING, + GIT_OPT_GET_CACHED_MEMORY }; /** diff --git a/src/cache.c b/src/cache.c index b462af408..88f643b35 100644 --- a/src/cache.c +++ b/src/cache.c @@ -19,8 +19,7 @@ GIT__USE_OIDMAP bool git_cache__enabled = true; int64_t git_cache__max_storage = (256 * 1024 * 1024); - -static git_atomic64 git_cache__current_storage = {0}; +git_atomic64 git_cache__current_storage = {0}; static size_t git_cache__max_object_size[8] = { 0, /* GIT_OBJ__EXT1 */ diff --git a/src/cache.h b/src/cache.h index f74fddfc9..1fb87dcea 100644 --- a/src/cache.h +++ b/src/cache.h @@ -36,6 +36,7 @@ typedef struct { extern bool git_cache__enabled; extern int64_t git_cache__max_storage; +extern git_atomic64 git_cache__current_storage; int git_cache_set_max_object_size(git_otype type, size_t size); diff --git a/src/util.c b/src/util.c index 2dec49f17..ce67c7e62 100644 --- a/src/util.c +++ b/src/util.c @@ -109,6 +109,11 @@ int git_libgit2_opts(int key, ...) case GIT_OPT_ENABLE_CACHING: git_cache__enabled = (va_arg(ap, int) != 0); break; + + case GIT_OPT_GET_CACHED_MEMORY: + *(va_arg(ap, int64_t *)) = git_cache__current_storage.val; + *(va_arg(ap, int64_t *)) = git_cache__max_storage; + break; } va_end(ap); From dfdf709e3f8aed5cb8ee54d9c508b65672c8a211 Mon Sep 17 00:00:00 2001 From: Nikolai Vladimirov Date: Tue, 23 Apr 2013 21:29:07 +0300 Subject: [PATCH 077/134] get last refspec in clone test --- tests-clar/clone/nonetwork.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-clar/clone/nonetwork.c b/tests-clar/clone/nonetwork.c index 02066e07d..506673737 100644 --- a/tests-clar/clone/nonetwork.c +++ b/tests-clar/clone/nonetwork.c @@ -149,7 +149,7 @@ void test_clone_nonetwork__custom_fetch_spec(void) cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); - actual_fs = git_vector_get(&g_remote->refspecs, 0); + actual_fs = git_vector_get(&g_remote->refspecs, g_remote->refspecs.length - 1); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); From bd0a07f4bb0b83a84127589f7385eb2309910b66 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Tue, 23 Apr 2013 12:28:59 -0700 Subject: [PATCH 078/134] Clone: replace fetch spec with custom value --- src/clone.c | 8 +++++--- tests-clar/clone/nonetwork.c | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/clone.c b/src/clone.c index 8f10ca819..0665576e3 100644 --- a/src/clone.c +++ b/src/clone.c @@ -323,9 +323,11 @@ static int create_and_configure_origin( (error = git_remote_set_callbacks(origin, options->remote_callbacks)) < 0) goto on_error; - if (options->fetch_spec && - (error = git_remote_add_fetch(origin, options->fetch_spec)) < 0) - goto on_error; + if (options->fetch_spec) { + git_remote_clear_refspecs(origin); + if ((error = git_remote_add_fetch(origin, options->fetch_spec)) < 0) + goto on_error; + } if (options->push_spec && (error = git_remote_add_push(origin, options->push_spec)) < 0) diff --git a/tests-clar/clone/nonetwork.c b/tests-clar/clone/nonetwork.c index 506673737..02066e07d 100644 --- a/tests-clar/clone/nonetwork.c +++ b/tests-clar/clone/nonetwork.c @@ -149,7 +149,7 @@ void test_clone_nonetwork__custom_fetch_spec(void) cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); - actual_fs = git_vector_get(&g_remote->refspecs, g_remote->refspecs.length - 1); + actual_fs = git_vector_get(&g_remote->refspecs, 0); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); From a5df71c11fef996d67593546fa1edb2865e6a5d9 Mon Sep 17 00:00:00 2001 From: Linquize Date: Fri, 19 Apr 2013 22:36:01 +0800 Subject: [PATCH 079/134] Support diff.context config --- src/diff.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/diff.c b/src/diff.c index 37c89f3f1..e6f5374e7 100644 --- a/src/diff.c +++ b/src/diff.c @@ -267,6 +267,16 @@ static int config_bool(git_config *cfg, const char *name, int defvalue) return val; } +static int config_int(git_config *cfg, const char *name, int defvalue) +{ + int val = defvalue; + + if (git_config_get_int32(&val, cfg, name) < 0) + giterr_clear(); + + return val; +} + static git_diff_list *git_diff_list_alloc( git_repository *repo, const git_diff_options *opts) { @@ -306,7 +316,8 @@ static git_diff_list *git_diff_list_alloc( if (opts == NULL) { /* Make sure we default to 3 lines */ - diff->opts.context_lines = 3; + int context = config_int(cfg, "diff.context", 3); + diff->opts.context_lines = max(context, 0); return diff; } From 608d04667ae08e991c1ffa6f33573d15930245b3 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 22 Apr 2013 13:51:35 -0700 Subject: [PATCH 080/134] Make tree to tree diffs case sensitive When case insensitive tree iterators were added, we started reading the case sensitivity of the index to decide if the tree should be case sensitive. This is good for index-to-tree comparisons, but for tree-to-tree comparisons, we should really default to doing a case sensitive comparison unless the user really wants otherwise. --- src/diff.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/diff.c b/src/diff.c index e6f5374e7..d9348bba8 100644 --- a/src/diff.c +++ b/src/diff.c @@ -870,12 +870,20 @@ int git_diff_tree_to_tree( const git_diff_options *opts) { int error = 0; + git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE; assert(diff && repo); + /* for tree to tree diff, be case sensitive even if the index is + * currently case insensitive, unless the user explicitly asked + * for case insensitivity + */ + if (opts && (opts->flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0) + iflag = GIT_ITERATOR_IGNORE_CASE; + DIFF_FROM_ITERATORS( - git_iterator_for_tree(&a, old_tree, 0, pfx, pfx), - git_iterator_for_tree(&b, new_tree, 0, pfx, pfx) + git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx), + git_iterator_for_tree(&b, new_tree, iflag, pfx, pfx) ); return error; From ab01cbd4ddd756c7beda3f483791cb5d4e211872 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 22 Apr 2013 14:24:12 -0700 Subject: [PATCH 081/134] Add configs to repo config cache This adds a bunch of additional config values to the repository config value cache and makes it easier to add a simple boolean config without creating enum values for each possible setting. Also, this fixes a bug in git_config_refresh where the config cache was not being cleared which could lead to potential incorrect values. The work to start using the new cached configs will come in the next couple of commits... --- src/config.c | 3 +++ src/config_cache.c | 31 ++++++++++++++++++++++++------- src/repository.h | 25 +++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/config.c b/src/config.c index 1283522ca..cb9d4014c 100644 --- a/src/config.c +++ b/src/config.c @@ -293,6 +293,9 @@ int git_config_refresh(git_config *cfg) error = file->refresh(file); } + if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) + git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg)); + return error; } diff --git a/src/config_cache.c b/src/config_cache.c index 2f36df7d1..84de3a5ed 100644 --- a/src/config_cache.c +++ b/src/config_cache.c @@ -26,7 +26,7 @@ struct map_data { * files that have the text property set. Alternatives are lf, crlf * and native, which uses the platform's native line ending. The default * value is native. See gitattributes(5) for more information on - * end-of-line conversion. + * end-of-line conversion. */ static git_cvar_map _cvar_map_eol[] = { {GIT_CVAR_FALSE, NULL, GIT_EOL_UNSET}, @@ -37,7 +37,7 @@ static git_cvar_map _cvar_map_eol[] = { /* * core.autocrlf - * Setting this variable to "true" is almost the same as setting + * Setting this variable to "true" is almost the same as setting * the text attribute to "auto" on all files except that text files are * not guaranteed to be normalized: files that contain CRLF in the * repository will not be touched. Use this setting if you want to have @@ -51,9 +51,22 @@ static git_cvar_map _cvar_map_autocrlf[] = { {GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT} }; +/* + * Generic map for integer values + */ +static git_cvar_map _cvar_map_int[] = { + {GIT_CVAR_INT32, NULL, 0}, +}; + static struct map_data _cvar_maps[] = { {"core.autocrlf", _cvar_map_autocrlf, ARRAY_SIZE(_cvar_map_autocrlf), GIT_AUTO_CRLF_DEFAULT}, - {"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT} + {"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT}, + {"core.symlinks", NULL, 0, GIT_SYMLINKS_DEFAULT }, + {"core.ignorecase", NULL, 0, GIT_IGNORECASE_DEFAULT }, + {"core.filemode", NULL, 0, GIT_FILEMODE_DEFAULT }, + {"core.ignorestat", NULL, 0, GIT_IGNORESTAT_DEFAULT }, + {"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT }, + {"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT }, }; int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) @@ -69,12 +82,16 @@ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) if (error < 0) return error; - error = git_config_get_mapped(out, - config, data->cvar_name, data->maps, data->map_count); + if (data->maps) + error = git_config_get_mapped( + out, config, data->cvar_name, data->maps, data->map_count); + else + error = git_config_get_bool(out, config, data->cvar_name); - if (error == GIT_ENOTFOUND) + if (error == GIT_ENOTFOUND) { + giterr_clear(); *out = data->default_value; - + } else if (error < 0) return error; diff --git a/src/repository.h b/src/repository.h index cc2f8c2b8..f7f9ecb1f 100644 --- a/src/repository.h +++ b/src/repository.h @@ -12,6 +12,7 @@ #include "git2/odb.h" #include "git2/repository.h" #include "git2/object.h" +#include "git2/config.h" #include "index.h" #include "cache.h" @@ -31,7 +32,13 @@ /** Cvar cache identifiers */ typedef enum { GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */ - GIT_CVAR_EOL, /* core.eol */ + GIT_CVAR_EOL, /* core.eol */ + GIT_CVAR_SYMLINKS, /* core.symlinks */ + GIT_CVAR_IGNORECASE, /* core.ignorecase */ + GIT_CVAR_FILEMODE, /* core.filemode */ + GIT_CVAR_IGNORESTAT, /* core.ignorestat */ + GIT_CVAR_TRUSTCTIME, /* core.trustctime */ + GIT_CVAR_ABBREV, /* core.abbrev */ GIT_CVAR_CACHE_MAX } git_cvar_cached; @@ -67,7 +74,21 @@ typedef enum { #else GIT_EOL_NATIVE = GIT_EOL_LF, #endif - GIT_EOL_DEFAULT = GIT_EOL_NATIVE + GIT_EOL_DEFAULT = GIT_EOL_NATIVE, + + /* core.symlinks: bool */ + GIT_SYMLINKS_DEFAULT = GIT_CVAR_TRUE, + /* core.ignorecase */ + GIT_IGNORECASE_DEFAULT = GIT_CVAR_FALSE, + /* core.filemode */ + GIT_FILEMODE_DEFAULT = GIT_CVAR_TRUE, + /* core.ignorestat */ + GIT_IGNORESTAT_DEFAULT = GIT_CVAR_FALSE, + /* core.trustctime */ + GIT_TRUSTCTIME_DEFAULT = GIT_CVAR_TRUE, + /* core.abbrev */ + GIT_ABBREV_DEFAULT = 7, + } git_cvar_value; /* internal repository init flags */ From eac76c230c92594eaa528e50746119bd3c33ffbb Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 22 Apr 2013 14:27:36 -0700 Subject: [PATCH 082/134] Use config cache where possible This converts many of the config lookups that are done around the library to use the repository config cache. This was everything I could find that wasn't part of diff (which requires a larger fix). --- src/checkout.c | 23 ++++++++--------------- src/ignore.c | 36 +++++++++--------------------------- src/ignore.h | 2 +- src/index.c | 17 ++++++++--------- 4 files changed, 26 insertions(+), 52 deletions(-) diff --git a/src/checkout.c b/src/checkout.c index 62a73d6d0..e29fccd05 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -1119,7 +1119,6 @@ static int checkout_data_init( git_checkout_opts *proposed) { int error = 0; - git_config *cfg; git_repository *repo = git_iterator_owner(target); memset(data, 0, sizeof(*data)); @@ -1132,9 +1131,6 @@ static int checkout_data_init( if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0) return error; - if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) - return error; - data->repo = repo; GITERR_CHECK_VERSION( @@ -1147,7 +1143,10 @@ static int checkout_data_init( /* refresh config and index content unless NO_REFRESH is given */ if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) { - if ((error = git_config_refresh(cfg)) < 0) + git_config *cfg; + + if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 || + (error = git_config_refresh(cfg)) < 0) goto cleanup; /* if we are checking out the index, don't reload, @@ -1184,19 +1183,13 @@ static int checkout_data_init( data->pfx = git_pathspec_prefix(&data->opts.paths); - error = git_config_get_bool(&data->can_symlink, cfg, "core.symlinks"); - if (error < 0) { - if (error != GIT_ENOTFOUND) - goto cleanup; - - /* If "core.symlinks" is not found anywhere, default to true. */ - data->can_symlink = true; - giterr_clear(); - error = 0; - } + if ((error = git_repository__cvar( + &data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0) + goto cleanup; if (!data->opts.baseline) { data->opts_free_baseline = true; + error = checkout_lookup_head_tree(&data->opts.baseline, repo); if (error == GIT_EORPHANEDHEAD) { diff --git a/src/ignore.c b/src/ignore.c index 17779522c..e150b9585 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -15,24 +15,14 @@ static int parse_ignore_file( git_attr_fnmatch *match = NULL; const char *scan = NULL; char *context = NULL; - bool ignore_case = false; - git_config *cfg = NULL; - int val; + int ignore_case = false; - /* Prefer to have the caller pass in a git_ignores as the parsedata object. - * If they did not, then we can (much more slowly) find the value of - * ignore_case by using the repository object. */ - if (parsedata != NULL) { + /* Prefer to have the caller pass in a git_ignores as the parsedata + * object. If they did not, then look up the value of ignore_case */ + if (parsedata != NULL) ignore_case = ((git_ignores *)parsedata)->ignore_case; - } else { - if ((error = git_repository_config(&cfg, repo)) < 0) - return error; - - if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0) - ignore_case = (val != 0); - - git_config_free(cfg); - } + else if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0) + return error; if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) { context = ignores->key + 2; @@ -109,8 +99,6 @@ int git_ignore__for_path( { int error = 0; const char *workdir = git_repository_workdir(repo); - git_config *cfg = NULL; - int val; assert(ignores); @@ -118,17 +106,11 @@ int git_ignore__for_path( git_buf_init(&ignores->dir, 0); ignores->ign_internal = NULL; - /* Set the ignore_case flag appropriately */ - if ((error = git_repository_config(&cfg, repo)) < 0) + /* Read the ignore_case flag */ + if ((error = git_repository__cvar( + &ignores->ignore_case, repo, GIT_CVAR_IGNORECASE)) < 0) goto cleanup; - if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0) - ignores->ignore_case = (val != 0); - else - ignores->ignore_case = 0; - - git_config_free(cfg); - if ((error = git_vector_init(&ignores->ign_path, 8, NULL)) < 0 || (error = git_vector_init(&ignores->ign_global, 2, NULL)) < 0 || (error = git_attr_cache__init(repo)) < 0) diff --git a/src/ignore.h b/src/ignore.h index 5af8e8e7d..e00e4a8c8 100644 --- a/src/ignore.h +++ b/src/ignore.h @@ -28,7 +28,7 @@ typedef struct { git_attr_file *ign_internal; git_vector ign_path; git_vector ign_global; - unsigned int ignore_case:1; + int ignore_case; } git_ignores; extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign); diff --git a/src/index.c b/src/index.c index 2afd28158..d8ca78e52 100644 --- a/src/index.c +++ b/src/index.c @@ -330,7 +330,7 @@ void git_index_clear(git_index *index) git_vector_clear(&index->entries); git_index_reuc_clear(index); - + git_futils_filestamp_set(&index->stamp, NULL); git_tree_cache_free(index->tree); @@ -352,19 +352,18 @@ int git_index_set_caps(git_index *index, unsigned int caps) old_ignore_case = index->ignore_case; if (caps == GIT_INDEXCAP_FROM_OWNER) { - git_config *cfg; + git_repository *repo = INDEX_OWNER(index); int val; - if (INDEX_OWNER(index) == NULL || - git_repository_config__weakptr(&cfg, INDEX_OWNER(index)) < 0) - return create_index_error(-1, - "Cannot get repository config to set index caps"); + if (!repo) + return create_index_error( + -1, "Cannot access repository to set index caps"); - if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0) + if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE)) index->ignore_case = (val != 0); - if (git_config_get_bool(&val, cfg, "core.filemode") == 0) + if (!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE)) index->distrust_filemode = (val == 0); - if (git_config_get_bool(&val, cfg, "core.symlinks") == 0) + if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS)) index->no_symlinks = (val == 0); } else { From 6be368bf16c86380ea84d7e39b65e0ebd9606174 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 22 Apr 2013 16:24:53 -0700 Subject: [PATCH 083/134] Clear repo config cache when cfgs are set This is a conservative change, but it seemed like the only safe thing to do -- i.e. clear the cvar cache when a config gets set. --- src/config.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index cb9d4014c..3c0bbe9a7 100644 --- a/src/config.c +++ b/src/config.c @@ -363,6 +363,7 @@ int git_config_set_bool(git_config *cfg, const char *name, int value) int git_config_set_string(git_config *cfg, const char *name, const char *value) { + int error; git_config_backend *file; file_internal *internal; @@ -374,7 +375,12 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) internal = git_vector_get(&cfg->files, 0); file = internal->file; - return file->set(file, name, value); + error = file->set(file, name, value); + + if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL) + git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg)); + + return error; } /*********** From b1ff7004ab132c8d4bddd181127f1c8d5ce9b7b4 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 22 Apr 2013 16:25:57 -0700 Subject: [PATCH 084/134] Improve diff config options handling This makes diff use the cvar cache for config options where possible, and also adds support for a number of other config options to diff including "diff.context", "diff.ignoreSubmodules", "diff.noprefix", "diff.mnemonicprefix", and "core.abbrev". To make this natural, this involved a rearrangement of the code that allocates the diff object vs. the code that initializes it based on the combination of options passed in by the user and read from the config. This commit includes tests for most of these new options as well. --- src/diff.c | 211 ++++++++++++++++++++++++---------------- src/diff_output.c | 17 +++- tests-clar/diff/patch.c | 78 +++++++++++++++ tests-clar/diff/tree.c | 74 ++++++++++++++ 4 files changed, 291 insertions(+), 89 deletions(-) diff --git a/src/diff.c b/src/diff.c index d9348bba8..bce2914d1 100644 --- a/src/diff.c +++ b/src/diff.c @@ -14,6 +14,8 @@ #define DIFF_FLAG_IS_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) != 0) #define DIFF_FLAG_ISNT_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) == 0) +#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \ + (VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL)) static git_diff_delta *diff_delta__alloc( git_diff_list *diff, @@ -277,68 +279,148 @@ static int config_int(git_config *cfg, const char *name, int defvalue) return val; } -static git_diff_list *git_diff_list_alloc( - git_repository *repo, const git_diff_options *opts) +static const char *diff_mnemonic_prefix( + git_iterator_type_t type, bool left_side) { - git_config *cfg; + const char *pfx = ""; + + switch (type) { + case GIT_ITERATOR_TYPE_EMPTY: pfx = "c"; break; + case GIT_ITERATOR_TYPE_TREE: pfx = "c"; break; + case GIT_ITERATOR_TYPE_INDEX: pfx = "i"; break; + case GIT_ITERATOR_TYPE_WORKDIR: pfx = "w"; break; + case GIT_ITERATOR_TYPE_FS: pfx = left_side ? "1" : "2"; break; + default: break; + } + + /* note: without a deeper look at pathspecs, there is no easy way + * to get the (o)bject / (w)ork tree mnemonics working... + */ + + return pfx; +} + +static git_diff_list *diff_list_alloc( + git_repository *repo, + git_iterator *old_iter, + git_iterator *new_iter) +{ + git_diff_options dflt = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff = git__calloc(1, sizeof(git_diff_list)); - if (diff == NULL) + if (!diff) return NULL; + assert(repo && old_iter && new_iter); + GIT_REFCOUNT_INC(diff); diff->repo = repo; + diff->old_src = old_iter->type; + diff->new_src = new_iter->type; + memcpy(&diff->opts, &dflt, sizeof(diff->opts)); if (git_vector_init(&diff->deltas, 0, git_diff_delta__cmp) < 0 || - git_pool_init(&diff->pool, 1, 0) < 0) - goto fail; + git_pool_init(&diff->pool, 1, 0) < 0) { + git_diff_list_free(diff); + return NULL; + } + + /* Use case-insensitive compare if either iterator has + * the ignore_case bit set */ + if (!git_iterator_ignore_case(old_iter) && + !git_iterator_ignore_case(new_iter)) + { + diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE; + + diff->strcomp = git__strcmp; + diff->strncomp = git__strncmp; + diff->pfxcomp = git__prefixcmp; + diff->entrycomp = git_index_entry__cmp; + } else { + diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE; + + diff->strcomp = git__strcasecmp; + diff->strncomp = git__strncasecmp; + diff->pfxcomp = git__prefixcmp_icase; + diff->entrycomp = git_index_entry__cmp_icase; + } + + return diff; +} + +static int diff_list_apply_options( + git_diff_list *diff, + const git_diff_options *opts) +{ + git_config *cfg; + git_repository *repo = diff->repo; + git_pool *pool = &diff->pool; + int val; + + if (opts) { + /* copy user options (except case sensitivity info from iterators) */ + bool icase = DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE); + memcpy(&diff->opts, opts, sizeof(diff->opts)); + DIFF_FLAG_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE, icase); + + /* initialize pathspec from options */ + if (git_pathspec_init(&diff->pathspec, &opts->pathspec, pool) < 0) + return -1; + } + + /* flag INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */ + if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES)) + diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; /* load config values that affect diff behavior */ if (git_repository_config__weakptr(&cfg, repo) < 0) - goto fail; - if (config_bool(cfg, "core.symlinks", 1)) + return -1; + + if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS; - if (config_bool(cfg, "core.ignorestat", 0)) + + if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORESTAT) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_ASSUME_UNCHANGED; - if (config_bool(cfg, "core.filemode", 1)) + + if ((diff->opts.flags & GIT_DIFF_IGNORE_FILEMODE) == 0 && + !git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_MODE_BITS; - if (config_bool(cfg, "core.trustctime", 1)) + + if (!git_repository__cvar(&val, repo, GIT_CVAR_TRUSTCTIME) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME; + /* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */ - /* TODO: there are certain config settings where even if we were - * not given an options structure, we need the diff list to have one - * so that we can store the altered default values. - * - * - diff.ignoreSubmodules - * - diff.mnemonicprefix - * - diff.noprefix - */ + /* If not given explicit `opts`, check `diff.xyz` configs */ + if (!opts) { + diff->opts.context_lines = config_int(cfg, "diff.context", 3); - if (opts == NULL) { - /* Make sure we default to 3 lines */ - int context = config_int(cfg, "diff.context", 3); - diff->opts.context_lines = max(context, 0); - return diff; + if (config_bool(cfg, "diff.ignoreSubmodules", 0)) + diff->opts.flags |= GIT_DIFF_IGNORE_SUBMODULES; } - memcpy(&diff->opts, opts, sizeof(git_diff_options)); + /* if either prefix is not set, figure out appropriate value */ + if (!diff->opts.old_prefix || !diff->opts.new_prefix) { + const char *use_old = DIFF_OLD_PREFIX_DEFAULT; + const char *use_new = DIFF_NEW_PREFIX_DEFAULT; - if(opts->flags & GIT_DIFF_IGNORE_FILEMODE) - diff->diffcaps = diff->diffcaps & ~GIT_DIFFCAPS_TRUST_MODE_BITS; + if (config_bool(cfg, "diff.noprefix", 0)) { + use_old = use_new = ""; + } else if (config_bool(cfg, "diff.mnemonicprefix", 0)) { + use_old = diff_mnemonic_prefix(diff->old_src, true); + use_new = diff_mnemonic_prefix(diff->new_src, false); + } - /* pathspec init will do nothing for empty pathspec */ - if (git_pathspec_init(&diff->pathspec, &opts->pathspec, &diff->pool) < 0) - goto fail; - - /* TODO: handle config diff.mnemonicprefix, diff.noprefix */ - - diff->opts.old_prefix = diff_strdup_prefix(&diff->pool, - opts->old_prefix ? opts->old_prefix : DIFF_OLD_PREFIX_DEFAULT); - diff->opts.new_prefix = diff_strdup_prefix(&diff->pool, - opts->new_prefix ? opts->new_prefix : DIFF_NEW_PREFIX_DEFAULT); + if (!diff->opts.old_prefix) + diff->opts.old_prefix = use_old; + if (!diff->opts.new_prefix) + diff->opts.new_prefix = use_new; + } + /* strdup prefix from pool so we're not dependent on external data */ + diff->opts.old_prefix = diff_strdup_prefix(pool, diff->opts.old_prefix); + diff->opts.new_prefix = diff_strdup_prefix(pool, diff->opts.new_prefix); if (!diff->opts.old_prefix || !diff->opts.new_prefix) - goto fail; + return -1; if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) { const char *swap = diff->opts.old_prefix; @@ -346,15 +428,7 @@ static git_diff_list *git_diff_list_alloc( diff->opts.new_prefix = swap; } - /* INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */ - if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES)) - diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; - - return diff; - -fail: - git_diff_list_free(diff); - return NULL; + return 0; } static void diff_list_free(git_diff_list *diff) @@ -618,37 +692,6 @@ static bool entry_is_prefixed( item->path[pathlen] == '/'); } -static int diff_list_init_from_iterators( - git_diff_list *diff, - git_iterator *old_iter, - git_iterator *new_iter) -{ - diff->old_src = old_iter->type; - diff->new_src = new_iter->type; - - /* Use case-insensitive compare if either iterator has - * the ignore_case bit set */ - if (!git_iterator_ignore_case(old_iter) && - !git_iterator_ignore_case(new_iter)) - { - diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE; - - diff->strcomp = git__strcmp; - diff->strncomp = git__strncmp; - diff->pfxcomp = git__prefixcmp; - diff->entrycomp = git_index_entry__cmp; - } else { - diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE; - - diff->strcomp = git__strcasecmp; - diff->strncomp = git__strncasecmp; - diff->pfxcomp = git__prefixcmp_icase; - diff->entrycomp = git_index_entry__cmp_icase; - } - - return 0; -} - int git_diff__from_iterators( git_diff_list **diff_ptr, git_repository *repo, @@ -659,20 +702,18 @@ int git_diff__from_iterators( int error = 0; const git_index_entry *oitem, *nitem; git_buf ignore_prefix = GIT_BUF_INIT; - git_diff_list *diff = git_diff_list_alloc(repo, opts); - - *diff_ptr = NULL; - - if (!diff || diff_list_init_from_iterators(diff, old_iter, new_iter) < 0) - goto fail; + git_diff_list *diff = diff_list_alloc(repo, old_iter, new_iter); + GITERR_CHECK_ALLOC(diff); + /* make iterators have matching icase behavior */ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) { if (git_iterator_set_ignore_case(old_iter, true) < 0 || git_iterator_set_ignore_case(new_iter, true) < 0) goto fail; } - if (git_iterator_current(&oitem, old_iter) < 0 || + if (diff_list_apply_options(diff, opts) < 0 || + git_iterator_current(&oitem, old_iter) < 0 || git_iterator_current(&nitem, new_iter) < 0) goto fail; diff --git a/src/diff_output.c b/src/diff_output.c index 34a3e506c..b8bb73bf7 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -1114,11 +1114,20 @@ int git_diff_print_compact( static int print_oid_range(diff_print_info *pi, const git_diff_delta *delta) { - char start_oid[8], end_oid[8]; + int abbrevlen; + char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1]; - /* TODO: Determine a good actual OID range to print */ - git_oid_tostr(start_oid, sizeof(start_oid), &delta->old_file.oid); - git_oid_tostr(end_oid, sizeof(end_oid), &delta->new_file.oid); + if (git_repository__cvar(&abbrevlen, pi->diff->repo, GIT_CVAR_ABBREV) < 0) + return -1; + + abbrevlen += 1; /* for NUL byte */ + if (abbrevlen < 2) + abbrevlen = 2; + else if (abbrevlen > (int)sizeof(start_oid)) + abbrevlen = (int)sizeof(start_oid); + + git_oid_tostr(start_oid, abbrevlen, &delta->old_file.oid); + git_oid_tostr(end_oid, abbrevlen, &delta->new_file.oid); /* TODO: Match git diff more closely */ if (delta->old_file.mode == delta->new_file.mode) { diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c index d41f3f12d..40b191dd5 100644 --- a/tests-clar/diff/patch.c +++ b/tests-clar/diff/patch.c @@ -135,6 +135,84 @@ void test_diff_patch__to_string(void) git_tree_free(one); } +void test_diff_patch__config_options(void) +{ + const char *one_sha = "26a125e"; /* current HEAD */ + git_tree *one; + git_config *cfg; + git_diff_list *diff; + git_diff_patch *patch; + char *text; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + char *onefile = "staged_changes_modified_file"; + const char *expected1 = "diff --git c/staged_changes_modified_file i/staged_changes_modified_file\nindex 70bd944..906ee77 100644\n--- c/staged_changes_modified_file\n+++ i/staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n"; + const char *expected2 = "diff --git i/staged_changes_modified_file w/staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- i/staged_changes_modified_file\n+++ w/staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n"; + const char *expected3 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n"; + const char *expected4 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 70bd9443ada0..906ee7711f4f 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n"; + + g_repo = cl_git_sandbox_init("status"); + cl_git_pass(git_repository_config(&cfg, g_repo)); + one = resolve_commit_oid_to_tree(g_repo, one_sha); + opts.pathspec.count = 1; + opts.pathspec.strings = &onefile; + + + cl_git_pass(git_config_set_string(cfg, "diff.mnemonicprefix", "true")); + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts)); + + cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); + cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); + cl_git_pass(git_diff_patch_to_str(&text, patch)); + cl_assert_equal_s(expected1, text); + + git__free(text); + git_diff_patch_free(patch); + git_diff_list_free(diff); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); + cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); + cl_git_pass(git_diff_patch_to_str(&text, patch)); + cl_assert_equal_s(expected2, text); + + git__free(text); + git_diff_patch_free(patch); + git_diff_list_free(diff); + + + cl_git_pass(git_config_set_string(cfg, "diff.noprefix", "true")); + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); + cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); + cl_git_pass(git_diff_patch_to_str(&text, patch)); + cl_assert_equal_s(expected3, text); + + git__free(text); + git_diff_patch_free(patch); + git_diff_list_free(diff); + + + cl_git_pass(git_config_set_int32(cfg, "core.abbrev", 12)); + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts)); + + cl_assert_equal_i(1, (int)git_diff_num_deltas(diff)); + cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0)); + cl_git_pass(git_diff_patch_to_str(&text, patch)); + cl_assert_equal_s(expected4, text); + + git__free(text); + git_diff_patch_free(patch); + git_diff_list_free(diff); + + git_tree_free(one); + git_config_free(cfg); +} + void test_diff_patch__hunks_have_correct_line_numbers(void) { git_config *cfg; diff --git a/tests-clar/diff/tree.c b/tests-clar/diff/tree.c index 850feefde..f05c7869e 100644 --- a/tests-clar/diff/tree.c +++ b/tests-clar/diff/tree.c @@ -454,3 +454,77 @@ void test_diff_tree__issue_1397(void) cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]); } + +static void set_config_int(git_repository *repo, const char *name, int value) +{ + git_config *cfg; + + cl_git_pass(git_repository_config(&cfg, repo)); + cl_git_pass(git_config_set_int32(cfg, name, value)); + git_config_free(cfg); +} + +void test_diff_tree__diff_configs(void) +{ + const char *a_commit = "d70d245e"; + const char *b_commit = "7a9e0b02"; + + g_repo = cl_git_sandbox_init("diff"); + + cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); + cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); + + cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); + + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); + + cl_assert_equal_i(2, expect.files); + cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(6, expect.hunks); + cl_assert_equal_i(55, expect.lines); + cl_assert_equal_i(33, expect.line_ctxt); + cl_assert_equal_i(7, expect.line_adds); + cl_assert_equal_i(15, expect.line_dels); + + git_diff_list_free(diff); + diff = NULL; + + set_config_int(g_repo, "diff.context", 1); + + memset(&expect, 0, sizeof(expect)); + + cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); + + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); + + cl_assert_equal_i(2, expect.files); + cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(7, expect.hunks); + cl_assert_equal_i(34, expect.lines); + cl_assert_equal_i(12, expect.line_ctxt); + cl_assert_equal_i(7, expect.line_adds); + cl_assert_equal_i(15, expect.line_dels); + + git_diff_list_free(diff); + diff = NULL; + + set_config_int(g_repo, "diff.context", 0); + set_config_int(g_repo, "diff.noprefix", 1); + + memset(&expect, 0, sizeof(expect)); + + cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL)); + + cl_git_pass(git_diff_foreach( + diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect)); + + cl_assert_equal_i(2, expect.files); + cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(7, expect.hunks); + cl_assert_equal_i(22, expect.lines); + cl_assert_equal_i(0, expect.line_ctxt); + cl_assert_equal_i(7, expect.line_adds); + cl_assert_equal_i(15, expect.line_dels); +} From 687db88faf8bcfe7bccfedf65fa304f59987089c Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 22 Apr 2013 16:45:36 -0700 Subject: [PATCH 085/134] Make sure diff output is cleared on error --- src/diff.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/diff.c b/src/diff.c index bce2914d1..881173cde 100644 --- a/src/diff.c +++ b/src/diff.c @@ -702,7 +702,11 @@ int git_diff__from_iterators( int error = 0; const git_index_entry *oitem, *nitem; git_buf ignore_prefix = GIT_BUF_INIT; - git_diff_list *diff = diff_list_alloc(repo, old_iter, new_iter); + git_diff_list *diff; + + *diff_ptr = NULL; + + diff = diff_list_alloc(repo, old_iter, new_iter); GITERR_CHECK_ALLOC(diff); /* make iterators have matching icase behavior */ From 879458e7cf87374241da300a864493761bf48e7c Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 24 Apr 2013 15:52:33 +0200 Subject: [PATCH 086/134] repo: Add `git_repository__cleanup` --- include/git2/sys/repository.h | 14 ++++++++++++++ src/cache.c | 3 +++ src/cache.h | 1 + src/repository.c | 19 ++++++++++++++----- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/include/git2/sys/repository.h b/include/git2/sys/repository.h index 34bc17516..ba3d65ae5 100644 --- a/include/git2/sys/repository.h +++ b/include/git2/sys/repository.h @@ -27,6 +27,20 @@ GIT_BEGIN_DECL */ GIT_EXTERN(int) git_repository_new(git_repository **out); + +/** + * Reset all the internal state in a repository. + * + * This will free all the mapped memory and internal objects + * of the repository and leave it in a "blank" state. + * + * There's no need to call this function directly unless you're + * trying to aggressively cleanup the repo before its + * deallocation. `git_repository_free` already performs this operation + * before deallocation the repo. + */ +GIT_EXTERN(void) git_repository__cleanup(git_repository *repo); + /** * Set the configuration file for this repository * diff --git a/src/cache.c b/src/cache.c index 88f643b35..be4b037a3 100644 --- a/src/cache.c +++ b/src/cache.c @@ -77,6 +77,9 @@ static void clear_cache(git_cache *cache) { git_cached_obj *evict = NULL; + if (kh_size(cache->map) == 0) + return; + kh_foreach_value(cache->map, evict, { git_cached_obj_decref(evict); }); diff --git a/src/cache.h b/src/cache.h index 1fb87dcea..16470e9c8 100644 --- a/src/cache.h +++ b/src/cache.h @@ -42,6 +42,7 @@ int git_cache_set_max_object_size(git_otype type, size_t size); int git_cache_init(git_cache *cache); void git_cache_free(git_cache *cache); +void git_cache_clear(git_cache *cache); void *git_cache_store_raw(git_cache *cache, git_odb_object *entry); void *git_cache_store_parsed(git_cache *cache, git_object *entry); diff --git a/src/repository.c b/src/repository.c index 59479dc92..2161aa697 100644 --- a/src/repository.c +++ b/src/repository.c @@ -86,19 +86,28 @@ static void set_index(git_repository *repo, git_index *index) } } -void git_repository_free(git_repository *repo) +void git_repository__cleanup(git_repository *repo) { - if (repo == NULL) - return; + assert(repo); - git_cache_free(&repo->objects); + git_cache_clear(&repo->objects); git_attr_cache_flush(repo); - git_submodule_config_free(repo); set_config(repo, NULL); set_index(repo, NULL); set_odb(repo, NULL); set_refdb(repo, NULL); +} + +void git_repository_free(git_repository *repo) +{ + if (repo == NULL) + return; + + git_repository__cleanup(repo); + + git_cache_free(&repo->objects); + git_submodule_config_free(repo); git__free(repo->path_repository); git__free(repo->workdir); From b4117e19b7a968f8e6b878d81c58a462093cf1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 24 Apr 2013 20:09:42 +0200 Subject: [PATCH 087/134] docs: formatting fixes --- include/git2/attr.h | 2 +- include/git2/common.h | 52 +++++++++++++++++++++---------------- include/git2/cred_helpers.h | 4 +-- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/include/git2/attr.h b/include/git2/attr.h index dea44f0e3..f099245b0 100644 --- a/include/git2/attr.h +++ b/include/git2/attr.h @@ -228,7 +228,7 @@ GIT_EXTERN(void) git_attr_cache_flush( * function allows you to add others. For example, to add the default * macro, you would call: * - * git_attr_add_macro(repo, "binary", "-diff -crlf"); + * git_attr_add_macro(repo, "binary", "-diff -crlf"); */ GIT_EXTERN(int) git_attr_add_macro( git_repository *repo, diff --git a/include/git2/common.h b/include/git2/common.h index 6101e13bc..f9e9929ea 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -142,34 +142,42 @@ enum { * * Available options: * - * opts(GIT_OPT_GET_MWINDOW_SIZE, size_t *): - * Get the maximum mmap window size + * * opts(GIT_OPT_GET_MWINDOW_SIZE, size_t *): * - * opts(GIT_OPT_SET_MWINDOW_SIZE, size_t): - * Set the maximum mmap window size + * > Get the maximum mmap window size * - * opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, size_t *): - * Get the maximum memory that will be mapped in total by the library + * * opts(GIT_OPT_SET_MWINDOW_SIZE, size_t): * - * opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size_t): - * Set the maximum amount of memory that can be mapped at any time + * > Set the maximum mmap window size + * + * * opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, size_t *): + * + * > Get the maximum memory that will be mapped in total by the library + * + * * opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size_t): + * + * >Set the maximum amount of memory that can be mapped at any time * by the library * - * opts(GIT_OPT_GET_SEARCH_PATH, int level, char *out, size_t len) - * Get the search path for a given level of config data. "level" must - * be one of GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_GLOBAL, or - * GIT_CONFIG_LEVEL_XDG. The search path is written to the `out` - * buffer up to size `len`. Returns GIT_EBUFS if buffer is too small. + * * opts(GIT_OPT_GET_SEARCH_PATH, int level, char *out, size_t len) * - * opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path) - * Set the search path for a level of config data. The search path - * applied to shared attributes and ignore files, too. - * - `path` lists directories delimited by GIT_PATH_LIST_SEPARATOR. - * Pass NULL to reset to the default (generally based on environment - * variables). Use magic path `$PATH` to include the old value - * of the path (if you want to prepend or append, for instance). - * - `level` must be GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_GLOBAL, - * or GIT_CONFIG_LEVEL_XDG. + * > Get the search path for a given level of config data. "level" must + * > be one of `GIT_CONFIG_LEVEL_SYSTEM`, `GIT_CONFIG_LEVEL_GLOBAL`, or + * > `GIT_CONFIG_LEVEL_XDG`. The search path is written to the `out` + * > buffer up to size `len`. Returns GIT_EBUFS if buffer is too small. + * + * * opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path) + * + * > Set the search path for a level of config data. The search path + * > applied to shared attributes and ignore files, too. + * > + * > - `path` lists directories delimited by GIT_PATH_LIST_SEPARATOR. + * > Pass NULL to reset to the default (generally based on environment + * > variables). Use magic path `$PATH` to include the old value + * > of the path (if you want to prepend or append, for instance). + * > + * > - `level` must be GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_GLOBAL, + * > or GIT_CONFIG_LEVEL_XDG. * * @param option Option key * @param ... value to set the option diff --git a/include/git2/cred_helpers.h b/include/git2/cred_helpers.h index e3eb91d6c..5d93cf4dd 100644 --- a/include/git2/cred_helpers.h +++ b/include/git2/cred_helpers.h @@ -30,11 +30,11 @@ typedef struct git_cred_userpass_payload { /** * Stock callback usable as a git_cred_acquire_cb. This calls * git_cred_userpass_plaintext_new unless the protocol has not specified - * GIT_CREDTYPE_USERPASS_PLAINTEXT as an allowed type. + * `GIT_CREDTYPE_USERPASS_PLAINTEXT` as an allowed type. * * @param cred The newly created credential object. * @param url The resource for which we are demanding a credential. - * @param username_from_url The username that was embedded in a "user@host" + * @param user_from_url The username that was embedded in a "user@host" * remote url, or NULL if not included. * @param allowed_types A bitmask stating which cred types are OK to return. * @param payload The payload provided when specifying this callback. (This is From eb63fda2e24d007e31742587984a30e086249d43 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 25 Apr 2013 11:52:17 -0500 Subject: [PATCH 088/134] git_atomic_ssize for 64-bit atomics only on 64-bit platforms --- CMakeLists.txt | 9 +++++++++ src/cache.c | 13 +++++++------ src/cache.h | 6 +++--- src/thread-utils.h | 30 ++++++++++++++++++++++++++---- src/util.c | 6 +++--- 5 files changed, 48 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bd25aacc..1831c8717 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,6 +277,15 @@ ELSE() ENDIF() FILE(GLOB SRC_GIT2 src/*.c src/transports/*.c src/xdiff/*.c) +# Determine architecture of the machine +IF (CMAKE_SIZEOF_VOID_P EQUAL 8) + ADD_DEFINITIONS(-DGIT_ARCH_64) +ELSEIF (CMAKE_SIZEOF_VOID_P EQUAL 4) + ADD_DEFINITIONS(-DGIT_ARCH_32) +ELSE() + message(FATAL_ERROR "Unsupported architecture") +ENDIF() + # Compile and link libgit2 ADD_LIBRARY(git2 ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1} ${WIN_RC}) TARGET_LINK_LIBRARIES(git2 ${SSL_LIBRARIES}) diff --git a/src/cache.c b/src/cache.c index be4b037a3..1360cc976 100644 --- a/src/cache.c +++ b/src/cache.c @@ -18,8 +18,8 @@ GIT__USE_OIDMAP bool git_cache__enabled = true; -int64_t git_cache__max_storage = (256 * 1024 * 1024); -git_atomic64 git_cache__current_storage = {0}; +ssize_t git_cache__max_storage = (256 * 1024 * 1024); +git_atomic_ssize git_cache__current_storage = {0}; static size_t git_cache__max_object_size[8] = { 0, /* GIT_OBJ__EXT1 */ @@ -85,7 +85,7 @@ static void clear_cache(git_cache *cache) }); kh_clear(oid, cache->map); - git_atomic64_add(&git_cache__current_storage, -cache->used_memory); + git_atomic_ssize_add(&git_cache__current_storage, -cache->used_memory); cache->used_memory = 0; } @@ -111,7 +111,8 @@ void git_cache_free(git_cache *cache) static void cache_evict_entries(git_cache *cache) { uint32_t seed = rand(); - int64_t evicted_memory = 0, evict_count = 8; + size_t evict_count = 8; + ssize_t evicted_memory = 0; /* do not infinite loop if there's not enough entries to evict */ if (evict_count > kh_size(cache->map)) { @@ -134,7 +135,7 @@ static void cache_evict_entries(git_cache *cache) } cache->used_memory -= evicted_memory; - git_atomic64_add(&git_cache__current_storage, -evicted_memory); + git_atomic_ssize_add(&git_cache__current_storage, -evicted_memory); } static bool cache_should_store(git_otype object_type, size_t object_size) @@ -195,7 +196,7 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry) kh_val(cache->map, pos) = entry; git_cached_obj_incref(entry); cache->used_memory += entry->size; - git_atomic64_add(&git_cache__current_storage, (int64_t)entry->size); + git_atomic_ssize_add(&git_cache__current_storage, (ssize_t)entry->size); } } /* found */ diff --git a/src/cache.h b/src/cache.h index 16470e9c8..53fbcf4e9 100644 --- a/src/cache.h +++ b/src/cache.h @@ -31,12 +31,12 @@ typedef struct { typedef struct { git_oidmap *map; git_mutex lock; - int64_t used_memory; + ssize_t used_memory; } git_cache; extern bool git_cache__enabled; -extern int64_t git_cache__max_storage; -extern git_atomic64 git_cache__current_storage; +extern ssize_t git_cache__max_storage; +extern git_atomic_ssize git_cache__current_storage; int git_cache_set_max_object_size(git_otype type, size_t size); diff --git a/src/thread-utils.h b/src/thread-utils.h index 28ecd297e..49b5f3b5e 100644 --- a/src/thread-utils.h +++ b/src/thread-utils.h @@ -18,6 +18,8 @@ typedef struct { #endif } git_atomic; +#ifdef GIT_ARCH_64 + typedef struct { #if defined(GIT_WIN32) __int64 val; @@ -26,6 +28,18 @@ typedef struct { #endif } git_atomic64; +typedef git_atomic64 git_atomic_ssize; + +#define git_atomic_ssize_add git_atomic64_add + +#else + +typedef git_atomic git_atomic_ssize; + +#define git_atomic_ssize_add git_atomic_add + +#endif + GIT_INLINE(void) git_atomic_set(git_atomic *a, int val) { a->val = val; @@ -68,7 +82,7 @@ GIT_INLINE(int) git_atomic_inc(git_atomic *a) GIT_INLINE(int) git_atomic_add(git_atomic *a, int32_t addend) { #if defined(GIT_WIN32) - return _InterlockedExchangeAdd(&a->val, addend); + return InterlockedExchangeAdd(&a->val, addend); #elif defined(__GNUC__) return __sync_add_and_fetch(&a->val, addend); #else @@ -101,10 +115,12 @@ GIT_INLINE(void *) git___compare_and_swap( return (foundval == oldval) ? oldval : newval; } -GIT_INLINE(int) git_atomic64_add(git_atomic64 *a, int64_t addend) +#ifdef GIT_ARCH_64 + +GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) { #if defined(GIT_WIN32) - return _InterlockedExchangeAdd64(&a->val, addend); + return InterlockedExchangeAdd64(&a->val, addend); #elif defined(__GNUC__) return __sync_add_and_fetch(&a->val, addend); #else @@ -112,6 +128,8 @@ GIT_INLINE(int) git_atomic64_add(git_atomic64 *a, int64_t addend) #endif } +#endif + #else #define git_thread unsigned int @@ -161,7 +179,9 @@ GIT_INLINE(void *) git___compare_and_swap( return oldval; } -GIT_INLINE(int) git_atomic64_add(git_atomic64 *a, int64_t addend) +#ifdef GIT_ARCH_64 + +GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend) { a->val += addend; return a->val; @@ -169,6 +189,8 @@ GIT_INLINE(int) git_atomic64_add(git_atomic64 *a, int64_t addend) #endif +#endif + /* Atomically replace oldval with newval * @return oldval if it was replaced or newval if it was not */ diff --git a/src/util.c b/src/util.c index ce67c7e62..8c8bc1a6c 100644 --- a/src/util.c +++ b/src/util.c @@ -103,7 +103,7 @@ int git_libgit2_opts(int key, ...) } case GIT_OPT_SET_CACHE_MAX_SIZE: - git_cache__max_storage = va_arg(ap, int64_t); + git_cache__max_storage = va_arg(ap, ssize_t); break; case GIT_OPT_ENABLE_CACHING: @@ -111,8 +111,8 @@ int git_libgit2_opts(int key, ...) break; case GIT_OPT_GET_CACHED_MEMORY: - *(va_arg(ap, int64_t *)) = git_cache__current_storage.val; - *(va_arg(ap, int64_t *)) = git_cache__max_storage; + *(va_arg(ap, ssize_t *)) = git_cache__current_storage.val; + *(va_arg(ap, ssize_t *)) = git_cache__max_storage; break; } From 528a4e24c6671d621847cf8e3121e3c56fe20d3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 28 Apr 2013 14:16:45 +0200 Subject: [PATCH 089/134] Parse shorthand refspecs as valid Relax the ONELEVEL ref naming rules so the refspec parsing code can ask for 'master' to be considered valid. --- include/git2/refs.h | 7 +++++++ src/refs.c | 1 + src/refspec.c | 2 +- tests-clar/network/refspecs.c | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/git2/refs.h b/include/git2/refs.h index 1ff0d4544..e1d425352 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -422,6 +422,13 @@ typedef enum { * (e.g., foo//bar but not foo/bar). */ GIT_REF_FORMAT_REFSPEC_PATTERN = (1 << 1), + + /** + * Interpret the name as part of a refspec in shorthand form + * so the `ONELEVEL` naming rules aren't enforced and 'master' + * becomes a valid name. + */ + GIT_REF_FORMAT_REFSPEC_SHORTHAND = (1 << 2), } git_reference_normalize_t; /** diff --git a/src/refs.c b/src/refs.c index 9c6684a5a..2faa4cb83 100644 --- a/src/refs.c +++ b/src/refs.c @@ -752,6 +752,7 @@ int git_reference__normalize_name( goto cleanup; if ((segments_count == 1 ) && + !(flags & GIT_REF_FORMAT_REFSPEC_SHORTHAND) && !(is_all_caps_and_underscore(name, (size_t)segment_len) || ((flags & GIT_REF_FORMAT_REFSPEC_PATTERN) && !strcmp("*", name)))) goto cleanup; diff --git a/src/refspec.c b/src/refspec.c index fbdea9d93..256540819 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -60,7 +60,7 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch) refspec->pattern = is_glob; refspec->src = git__strndup(lhs, llen); - flags = GIT_REF_FORMAT_ALLOW_ONELEVEL + flags = GIT_REF_FORMAT_ALLOW_ONELEVEL | GIT_REF_FORMAT_REFSPEC_SHORTHAND | (is_glob ? GIT_REF_FORMAT_REFSPEC_PATTERN : 0); if (is_fetch) { diff --git a/tests-clar/network/refspecs.c b/tests-clar/network/refspecs.c index b3d80fb85..676a1fa99 100644 --- a/tests-clar/network/refspecs.c +++ b/tests-clar/network/refspecs.c @@ -81,4 +81,7 @@ void test_network_refspecs__parsing(void) assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*", true); assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*", true); + + assert_refspec(GIT_DIRECTION_FETCH, "master", true); + assert_refspec(GIT_DIRECTION_PUSH, "master", true); } From d84884571d04d609ed5f3508aecd9e24b84f47c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sun, 28 Apr 2013 16:26:55 +0200 Subject: [PATCH 090/134] remote: dwim the refspecs according to the remote's advertised refs As git allows you to store shorthand refspecs in the configuration, we need to do this ourselves. --- src/refspec.h | 1 + src/remote.c | 94 ++++++++++++++++++++++++++++--- tests-clar/network/remote/local.c | 41 ++++++++++++++ 3 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/refspec.h b/src/refspec.h index 29f4d5354..44d484c7b 100644 --- a/src/refspec.h +++ b/src/refspec.h @@ -17,6 +17,7 @@ struct git_refspec { unsigned int force :1, push : 1, pattern :1, + dwim :1, matching :1; }; diff --git a/src/remote.c b/src/remote.c index ffce2b6e2..1183137a6 100644 --- a/src/remote.c +++ b/src/remote.c @@ -632,28 +632,104 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur return 0; } +static int store_refs(git_remote_head *head, void *payload) +{ + git_vector *refs = (git_vector *)payload; + + return git_vector_insert(refs, head); +} + +static int dwim_refspecs(git_vector *refspecs, git_vector *refs) +{ + git_buf buf = GIT_BUF_INIT; + git_refspec *spec; + size_t i, j, pos; + git_remote_head key; + + const char* formatters[] = { + GIT_REFS_DIR "%s", + GIT_REFS_TAGS_DIR "%s", + GIT_REFS_HEADS_DIR "%s", + NULL + }; + + git_vector_foreach(refspecs, i, spec) { + if (spec->dwim) + continue; + + /* shorthand on the lhs */ + if (git__prefixcmp(spec->src, GIT_REFS_DIR)) { + for (j = 0; formatters[j]; j++) { + git_buf_clear(&buf); + if (git_buf_printf(&buf, formatters[j], spec->src) < 0) + return -1; + + key.name = (char *) git_buf_cstr(&buf); + if (!git_vector_search(&pos, refs, &key)) { + /* we found something to match the shorthand, set src to that */ + git__free(spec->src); + spec->src = git_buf_detach(&buf); + } + } + } + + if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) { + /* if it starts with "remotes" then we just prepend "refs/" */ + if (!git__prefixcmp(spec->dst, "remotes/")) { + git_buf_puts(&buf, GIT_REFS_DIR); + } else { + git_buf_puts(&buf, GIT_REFS_HEADS_DIR); + } + + if (git_buf_puts(&buf, spec->dst) < 0) + return -1; + + git__free(spec->dst); + spec->dst = git_buf_detach(&buf); + } + + spec->dwim = 1; + } + + return 0; +} + +static int remote_head_cmp(const void *_a, const void *_b) +{ + const git_remote_head *a = (git_remote_head *) _a; + const git_remote_head *b = (git_remote_head *) _b; + + return git__strcmp_cb(a->name, b->name); +} + int git_remote_download( git_remote *remote, git_transfer_progress_callback progress_cb, void *progress_payload) { int error; + git_vector refs; assert(remote); + if (git_vector_init(&refs, 16, remote_head_cmp) < 0) + return -1; + + if (git_remote_ls(remote, store_refs, &refs) < 0) { + return -1; + } + + error = dwim_refspecs(&remote->refspecs, &refs); + git_vector_free(&refs); + if (error < 0) + return -1; + if ((error = git_fetch_negotiate(remote)) < 0) return error; return git_fetch_download_pack(remote, progress_cb, progress_payload); } -static int update_tips_callback(git_remote_head *head, void *payload) -{ - git_vector *refs = (git_vector *)payload; - - return git_vector_insert(refs, head); -} - static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src) { unsigned int i; @@ -814,7 +890,7 @@ static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vecto if (!git_reference_is_valid_name(head->name)) continue; - if (git_refspec_src_matches(spec, head->name)) { + if (git_refspec_src_matches(spec, head->name) && spec->dst) { if (git_refspec_transform_r(&refname, spec, head->name) < 0) goto on_error; } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) { @@ -887,7 +963,7 @@ int git_remote_update_tips(git_remote *remote) if (git_vector_init(&refs, 16, NULL) < 0) return -1; - if (git_remote_ls(remote, update_tips_callback, &refs) < 0) + if (git_remote_ls(remote, store_refs, &refs) < 0) goto on_error; git_vector_foreach(&remote->refspecs, i, spec) { diff --git a/tests-clar/network/remote/local.c b/tests-clar/network/remote/local.c index 7e847e654..74ef63dc9 100644 --- a/tests-clar/network/remote/local.c +++ b/tests-clar/network/remote/local.c @@ -100,3 +100,44 @@ void test_network_remote_local__nested_tags_are_completely_peeled(void) cl_git_pass(git_remote_ls(remote, &ensure_peeled__cb, NULL)); } + +void test_network_remote_local__shorthand_fetch_refspec0(void) +{ + const char *refspec = "master:remotes/sloppy/master"; + const char *refspec2 = "master:boh/sloppy/master"; + + git_reference *ref; + + connect_to_local_repository(cl_fixture("testrepo.git")); + cl_git_pass(git_remote_add_fetch(remote, refspec)); + cl_git_pass(git_remote_add_fetch(remote, refspec2)); + + cl_git_pass(git_remote_download(remote, NULL, NULL)); + cl_git_pass(git_remote_update_tips(remote)); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/sloppy/master")); + git_reference_free(ref); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/heads/boh/sloppy/master")); + git_reference_free(ref); +} + +void test_network_remote_local__shorthand_fetch_refspec1(void) +{ + const char *refspec = "master"; + const char *refspec2 = "hard_tag"; + + git_reference *ref; + + connect_to_local_repository(cl_fixture("testrepo.git")); + git_remote_clear_refspecs(remote); + cl_git_pass(git_remote_add_fetch(remote, refspec)); + cl_git_pass(git_remote_add_fetch(remote, refspec2)); + + cl_git_pass(git_remote_download(remote, NULL, NULL)); + cl_git_pass(git_remote_update_tips(remote)); + + cl_git_fail(git_reference_lookup(&ref, repo, "refs/remotes/master")); + + cl_git_fail(git_reference_lookup(&ref, repo, "refs/tags/hard_tag")); +} From 51e4da6d8aa4a3a961d49197b004dbf7ccee8612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 29 Apr 2013 01:49:40 +0200 Subject: [PATCH 091/134] push: don't send a packfile when only issuing delete commands For update and create commands where all the objects are known to exist in the remote, we must send an empty packfile. However, if all we issue are delete commands, no packfile must be sent. Take this into consideration for push. --- src/transports/smart_protocol.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 90851980c..a5ad1e422 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -807,13 +807,13 @@ int git_smart__push(git_transport *transport, git_push *push) transport_smart *t = (transport_smart *)transport; git_smart_subtransport_stream *s; git_buf pktline = GIT_BUF_INIT; - int error = -1; + int error = -1, need_pack = 0; + push_spec *spec; + unsigned int i; #ifdef PUSH_DEBUG { git_remote_head *head; - push_spec *spec; - unsigned int i; char hex[41]; hex[40] = '\0'; git_vector_foreach(&push->remote->refs, i, head) { @@ -831,10 +831,23 @@ int git_smart__push(git_transport *transport, git_push *push) } #endif + /* + * Figure out if we need to send a packfile; which is in all + * cases except when we only send delete commands + */ + git_vector_foreach(&push->specs, i, spec) { + if (spec->lref) { + need_pack = 1; + break; + } + } + if (git_smart__get_push_stream(t, &s) < 0 || gen_pktline(&pktline, push) < 0 || - s->write(s, git_buf_cstr(&pktline), git_buf_len(&pktline)) < 0 || - git_packbuilder_foreach(push->pb, &stream_thunk, s) < 0) + s->write(s, git_buf_cstr(&pktline), git_buf_len(&pktline)) < 0) + goto on_error; + + if (need_pack && git_packbuilder_foreach(push->pb, &stream_thunk, s) < 0) goto on_error; /* If we sent nothing or the server doesn't support report-status, then From fb42a22e2fedeca8a5d0fa4a32653285374e689d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 29 Apr 2013 02:15:51 +0200 Subject: [PATCH 092/134] travis: test push Create a test repository in the VM and set up git-daemon so we can use it to test the push code. --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index ad1172dfa..0d5746f2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,10 @@ install: # Run the Build script script: + - mkdir _temp + - git init --bare _temp/test.git + - git daemon --listen=localhost --export-all --enable=receive-pack --base-path=_temp _temp 2>/dev/null & + - export GITTEST_REMOTE_URL="git://localhost/test.git" - mkdir _build - cd _build - cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS From 0c72248b9171acee7480a77edee89fa20fabdae8 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 29 Apr 2013 07:34:13 -0700 Subject: [PATCH 093/134] Introduce git_oid_compare, an exported oid cmp --- include/git2/oid.h | 9 +++++++++ src/oid.c | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/include/git2/oid.h b/include/git2/oid.h index 862f4b202..c35acdcdc 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -138,6 +138,15 @@ GIT_EXTERN(char *) git_oid_tostr(char *out, size_t n, const git_oid *id); */ GIT_EXTERN(void) git_oid_cpy(git_oid *out, const git_oid *src); +/** + * Compare two oid structures. + * + * @param a first oid structure. + * @param b second oid structure. + * @return <0, 0, >0 if a < b, a == b, a > b. + */ +GIT_EXTERN(int) git_oid_compare(const git_oid *oid_a, const git_oid *oid_b); + /** * Compare two oid structures. * diff --git a/src/oid.c b/src/oid.c index ab69eeb17..59c1546d7 100644 --- a/src/oid.c +++ b/src/oid.c @@ -166,6 +166,11 @@ void git_oid_cpy(git_oid *out, const git_oid *src) memcpy(out->id, src->id, sizeof(out->id)); } +int git_oid_compare(const git_oid *oid_a, const git_oid *oid_b) +{ + return git_oid_cmp(oid_a, oid_b); +} + int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len) { const unsigned char *a = oid_a->id; From 8564a0224abe09beaacb2d2e7a54b16f8fcea7d1 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 29 Apr 2013 08:51:24 -0700 Subject: [PATCH 094/134] Fix fragile git_oid_ncmp git_oid_ncmp was making some assumptions about the length of the data - this shifts the check to the top of the loop so it will work more robustly, limits the max, and adds some tests to verify the functionality. --- src/oid.c | 7 +++++-- tests-clar/core/oid.c | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/oid.c b/src/oid.c index 59c1546d7..4b6699009 100644 --- a/src/oid.c +++ b/src/oid.c @@ -176,13 +176,16 @@ int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len) const unsigned char *a = oid_a->id; const unsigned char *b = oid_b->id; - do { + if (len > GIT_OID_HEXSZ) + len = GIT_OID_HEXSZ; + + while (len > 1) { if (*a != *b) return 1; a++; b++; len -= 2; - } while (len > 1); + }; if (len) if ((*a ^ *b) & 0xf0) diff --git a/tests-clar/core/oid.c b/tests-clar/core/oid.c index 08791cce6..d863a3e85 100644 --- a/tests-clar/core/oid.c +++ b/tests-clar/core/oid.c @@ -27,4 +27,22 @@ void test_core_oid__streq(void) cl_assert(git_oid_streq(&idp, "deadbeef") == -1); cl_assert(git_oid_streq(&idp, "I'm not an oid.... :)") == -1); + +void test_core_oid__ncmp(void) +{ + cl_assert(!git_oid_ncmp(&id, &idp, 0)); + cl_assert(!git_oid_ncmp(&id, &idp, 1)); + cl_assert(!git_oid_ncmp(&id, &idp, 2)); + cl_assert(!git_oid_ncmp(&id, &idp, 17)); + cl_assert(!git_oid_ncmp(&id, &idp, 18)); + cl_assert(git_oid_ncmp(&id, &idp, 19)); + cl_assert(git_oid_ncmp(&id, &idp, 40)); + cl_assert(git_oid_ncmp(&id, &idp, 41)); + cl_assert(git_oid_ncmp(&id, &idp, 42)); + + cl_assert(!git_oid_ncmp(&id, &id, 0)); + cl_assert(!git_oid_ncmp(&id, &id, 1)); + cl_assert(!git_oid_ncmp(&id, &id, 39)); + cl_assert(!git_oid_ncmp(&id, &id, 40)); + cl_assert(!git_oid_ncmp(&id, &id, 41)); } From aa8f010120577e61715f3ae1286a03055815f9c3 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 29 Apr 2013 08:59:46 -0700 Subject: [PATCH 095/134] Add git_oid_strcmp and use it for git_oid_streq Add a new git_oid_strcmp that compares a string OID with a hex oid for sort order, and then reimplement git_oid_streq using it. This actually should speed up git_oid_streq because it only reads as far into the string as it needs to, whereas previously it would convert the whole string into an OID and then use git_oid_cmp. --- include/git2/oid.h | 10 ++++++++++ src/oid.c | 27 ++++++++++++++++++++++----- tests-clar/core/oid.c | 40 +++++++++++++++++++++++++++++++--------- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/include/git2/oid.h b/include/git2/oid.h index c35acdcdc..8d93e79cf 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -201,6 +201,16 @@ GIT_EXTERN(int) git_oid_ncmp(const git_oid *a, const git_oid *b, size_t len); */ GIT_EXTERN(int) git_oid_streq(const git_oid *id, const char *str); +/** + * Compare an oid to an hex formatted object id. + * + * @param id oid structure. + * @param str input hex string of an object id. + * @return -1 if str is not valid, <0 if id sorts before str, + * 0 if id matches str, >0 if id sorts after str. + */ +GIT_EXTERN(int) git_oid_strcmp(const git_oid *id, const char *str); + /** * Check is an oid is all zeros. * diff --git a/src/oid.c b/src/oid.c index 4b6699009..c7ce6ee50 100644 --- a/src/oid.c +++ b/src/oid.c @@ -194,14 +194,31 @@ int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len) return 0; } -int git_oid_streq(const git_oid *a, const char *str) +int git_oid_strcmp(const git_oid *oid_a, const char *str) { - git_oid id; + const unsigned char *a = oid_a->id; + unsigned char strval; + int hexval; - if (git_oid_fromstr(&id, str) < 0) - return -1; + for (a = oid_a->id; *str && (a - oid_a->id) < GIT_OID_RAWSZ; ++a) { + if ((hexval = git__fromhex(*str++)) < 0) + return -1; + strval = hexval << 4; + if (*str) { + if ((hexval = git__fromhex(*str++)) < 0) + return -1; + strval |= hexval; + } + if (*a != strval) + return (*a - strval); + } - return git_oid_cmp(a, &id) == 0 ? 0 : -1; + return 0; +} + +int git_oid_streq(const git_oid *oid_a, const char *str) +{ + return git_oid_strcmp(oid_a, str) == 0 ? 0 : -1; } int git_oid_iszero(const git_oid *oid_a) diff --git a/tests-clar/core/oid.c b/tests-clar/core/oid.c index d863a3e85..7ee6fb67d 100644 --- a/tests-clar/core/oid.c +++ b/tests-clar/core/oid.c @@ -16,17 +16,39 @@ void test_core_oid__initialize(void) void test_core_oid__streq(void) { - cl_assert(git_oid_streq(&id, str_oid) == 0); - cl_assert(git_oid_streq(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") == -1); + cl_assert_equal_i(0, git_oid_streq(&id, str_oid)); + cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); - cl_assert(git_oid_streq(&id, "deadbeef") == -1); - cl_assert(git_oid_streq(&id, "I'm not an oid.... :)") == -1); - - cl_assert(git_oid_streq(&idp, "ae90f12eea699729ed0000000000000000000000") == 0); - cl_assert(git_oid_streq(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") == -1); + cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeef")); + cl_assert_equal_i(-1, git_oid_streq(&id, "I'm not an oid.... :)")); - cl_assert(git_oid_streq(&idp, "deadbeef") == -1); - cl_assert(git_oid_streq(&idp, "I'm not an oid.... :)") == -1); + cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed0000000000000000000000")); + cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ed1")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ec")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef")); + + cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeef")); + cl_assert_equal_i(-1, git_oid_streq(&idp, "I'm not an oid.... :)")); +} + +void test_core_oid__strcmp(void) +{ + cl_assert_equal_i(0, git_oid_strcmp(&id, str_oid)); + cl_assert(git_oid_strcmp(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0); + + cl_assert(git_oid_strcmp(&id, "deadbeef") < 0); + cl_assert_equal_i(-1, git_oid_strcmp(&id, "I'm not an oid.... :)")); + + cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed0000000000000000000000")); + cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed")); + cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ed1") < 0); + cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ec") > 0); + cl_assert(git_oid_strcmp(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0); + + cl_assert(git_oid_strcmp(&idp, "deadbeef") < 0); + cl_assert_equal_i(-1, git_oid_strcmp(&idp, "I'm not an oid.... :)")); +} void test_core_oid__ncmp(void) { From ac1d85cf11ceb8bf9c9600ce9c29d5d037220cfb Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 29 Apr 2013 11:00:05 -0500 Subject: [PATCH 096/134] cmake 2.6 parser bug workaround --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1831c8717..9f6b06bf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,7 +293,7 @@ TARGET_OS_LIBRARIES(git2) # Workaround for Cmake bug #0011240 (see http://public.kitware.com/Bug/view.php?id=11240) # Win64+MSVC+static libs = linker error -IF(MSVC AND NOT BUILD_SHARED_LIBS AND (${CMAKE_SIZEOF_VOID_P} MATCHES "8") ) +IF(MSVC AND GIT_ARCH_64 AND NOT BUILD_SHARED_LIBS) SET_TARGET_PROPERTIES(git2 PROPERTIES STATIC_LIBRARY_FLAGS "/MACHINE:x64") ENDIF() From c8a4e8a5f6acc94c46c8a7ea2cf3f9d67b50e07a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 29 Apr 2013 11:14:56 -0500 Subject: [PATCH 097/134] don't use uninitialized struct stat in win32 --- src/odb.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/odb.c b/src/odb.c index 53630dddc..64e1232f5 100644 --- a/src/odb.c +++ b/src/odb.c @@ -445,31 +445,39 @@ static int add_default_backends( { size_t i; struct stat st; + ino_t inode; git_odb_backend *loose, *packed; /* TODO: inodes are not really relevant on Win32, so we need to find * a cross-platform workaround for this */ -#ifndef GIT_WIN32 +#ifdef GIT_WIN32 + GIT_UNUSED(i); + GIT_UNUSED(st); + + inode = 0; +#else if (p_stat(objects_dir, &st) < 0) { giterr_set(GITERR_ODB, "Failed to load object database in '%s'", objects_dir); return -1; } + inode = st.st_ino; + for (i = 0; i < db->backends.length; ++i) { backend_internal *backend = git_vector_get(&db->backends, i); - if (backend->disk_inode == st.st_ino) + if (backend->disk_inode == inode) return 0; } #endif /* add the loose object backend */ if (git_odb_backend_loose(&loose, objects_dir, -1, 0) < 0 || - add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, st.st_ino) < 0) + add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates, inode) < 0) return -1; /* add the packed file backend */ if (git_odb_backend_pack(&packed, objects_dir) < 0 || - add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, st.st_ino) < 0) + add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates, inode) < 0) return -1; return load_alternates(db, objects_dir, alternate_depth); From b7f167da29effa125663b143d3daf79a6ad88d2e Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 29 Apr 2013 13:52:12 -0700 Subject: [PATCH 098/134] Make git_oid_cmp public and add git_oid__cmp --- include/git2/oid.h | 14 +------------- src/attr.c | 2 +- src/checkout.c | 6 +++--- src/clone.c | 6 +++--- src/diff.c | 10 +++++----- src/diff_output.c | 4 ++-- src/diff_tform.c | 2 +- src/index.c | 2 +- src/indexer.c | 4 ++-- src/odb.c | 2 +- src/oid.c | 4 ++-- src/pack.c | 6 +++--- src/push.c | 2 +- src/refs.c | 2 +- src/refs.h | 1 + src/remote.c | 2 +- src/transports/local.c | 2 +- 17 files changed, 30 insertions(+), 41 deletions(-) diff --git a/include/git2/oid.h b/include/git2/oid.h index 8d93e79cf..288e90bc8 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -154,19 +154,7 @@ GIT_EXTERN(int) git_oid_compare(const git_oid *oid_a, const git_oid *oid_b); * @param b second oid structure. * @return <0, 0, >0 if a < b, a == b, a > b. */ -GIT_INLINE(int) git_oid_cmp(const git_oid *a, const git_oid *b) -{ - const unsigned char *sha1 = a->id; - const unsigned char *sha2 = b->id; - int i; - - for (i = 0; i < GIT_OID_RAWSZ; i++, sha1++, sha2++) { - if (*sha1 != *sha2) - return *sha1 - *sha2; - } - - return 0; -} +GIT_EXTERN(int) git_oid_cmp(const git_oid *a, const git_oid *b); /** * Compare two oid structures for equality diff --git a/src/attr.c b/src/attr.c index 979fecc14..6dd2c7e2f 100644 --- a/src/attr.c +++ b/src/attr.c @@ -312,7 +312,7 @@ static int load_attr_blob_from_index( entry = git_index_get_byindex(index, pos); - if (old_oid && git_oid_cmp(old_oid, &entry->oid) == 0) + if (old_oid && git_oid__cmp(old_oid, &entry->oid) == 0) return GIT_ENOTFOUND; if ((error = git_blob_lookup(blob, repo, &entry->oid)) < 0) diff --git a/src/checkout.c b/src/checkout.c index e29fccd05..96e15093c 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -138,7 +138,7 @@ static bool checkout_is_workdir_modified( if (!sm_oid) return false; - return (git_oid_cmp(&baseitem->oid, sm_oid) != 0); + return (git_oid__cmp(&baseitem->oid, sm_oid) != 0); } /* Look at the cache to decide if the workdir is modified. If not, @@ -149,7 +149,7 @@ static bool checkout_is_workdir_modified( if (wditem->mtime.seconds == ie->mtime.seconds && wditem->mtime.nanoseconds == ie->mtime.nanoseconds && wditem->file_size == ie->file_size) - return (git_oid_cmp(&baseitem->oid, &ie->oid) != 0); + return (git_oid__cmp(&baseitem->oid, &ie->oid) != 0); } /* depending on where base is coming from, we may or may not know @@ -163,7 +163,7 @@ static bool checkout_is_workdir_modified( wditem->file_size, &oid) < 0) return false; - return (git_oid_cmp(&baseitem->oid, &oid) != 0); + return (git_oid__cmp(&baseitem->oid, &oid) != 0); } #define CHECKOUT_ACTION_IF(FLAG,YES,NO) \ diff --git a/src/clone.c b/src/clone.c index 0665576e3..aeb7bbf5c 100644 --- a/src/clone.c +++ b/src/clone.c @@ -132,14 +132,14 @@ static int reference_matches_remote_head( return 0; } - if (git_oid_cmp(&head_info->remote_head_oid, &oid) == 0) { + if (git_oid__cmp(&head_info->remote_head_oid, &oid) == 0) { /* Determine the local reference name from the remote tracking one */ if (git_refspec_transform_l( - &head_info->branchname, + &head_info->branchname, head_info->refspec, reference_name) < 0) return -1; - + if (git_buf_len(&head_info->branchname) > 0) { if (git_buf_sets( &head_info->branchname, diff --git a/src/diff.c b/src/diff.c index 881173cde..6612abf06 100644 --- a/src/diff.c +++ b/src/diff.c @@ -196,21 +196,21 @@ static git_diff_delta *diff_delta__last_for_item( switch (delta->status) { case GIT_DELTA_UNMODIFIED: case GIT_DELTA_DELETED: - if (git_oid_cmp(&delta->old_file.oid, &item->oid) == 0) + if (git_oid__cmp(&delta->old_file.oid, &item->oid) == 0) return delta; break; case GIT_DELTA_ADDED: - if (git_oid_cmp(&delta->new_file.oid, &item->oid) == 0) + if (git_oid__cmp(&delta->new_file.oid, &item->oid) == 0) return delta; break; case GIT_DELTA_UNTRACKED: if (diff->strcomp(delta->new_file.path, item->path) == 0 && - git_oid_cmp(&delta->new_file.oid, &item->oid) == 0) + git_oid__cmp(&delta->new_file.oid, &item->oid) == 0) return delta; break; case GIT_DELTA_MODIFIED: - if (git_oid_cmp(&delta->old_file.oid, &item->oid) == 0 || - git_oid_cmp(&delta->new_file.oid, &item->oid) == 0) + if (git_oid__cmp(&delta->old_file.oid, &item->oid) == 0 || + git_oid__cmp(&delta->new_file.oid, &item->oid) == 0) return delta; break; default: diff --git a/src/diff_output.c b/src/diff_output.c index b8bb73bf7..4ce01bc62 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -660,7 +660,7 @@ static int diff_patch_load( */ if (check_if_unmodified && delta->old_file.mode == delta->new_file.mode && - !git_oid_cmp(&delta->old_file.oid, &delta->new_file.oid)) + !git_oid__cmp(&delta->old_file.oid, &delta->new_file.oid)) { delta->status = GIT_DELTA_UNMODIFIED; @@ -1388,7 +1388,7 @@ static int diff_single_apply(diff_single_data *data) (has_old ? GIT_DELTA_MODIFIED : GIT_DELTA_ADDED) : (has_old ? GIT_DELTA_DELETED : GIT_DELTA_UNTRACKED); - if (git_oid_cmp(&delta->new_file.oid, &delta->old_file.oid) == 0) + if (git_oid__cmp(&delta->new_file.oid, &delta->old_file.oid) == 0) delta->status = GIT_DELTA_UNMODIFIED; if ((error = diff_delta_is_binary_by_content( diff --git a/src/diff_tform.c b/src/diff_tform.c index efcb19d95..5c1a86cb9 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -429,7 +429,7 @@ static int similarity_measure( if (GIT_MODE_TYPE(a_file->mode) != GIT_MODE_TYPE(b_file->mode)) return 0; - if (git_oid_cmp(&a_file->oid, &b_file->oid) == 0) + if (git_oid__cmp(&a_file->oid, &b_file->oid) == 0) return 100; /* update signature cache if needed */ diff --git a/src/index.c b/src/index.c index d8ca78e52..2e2d373b5 100644 --- a/src/index.c +++ b/src/index.c @@ -1411,7 +1411,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) /* 160-bit SHA-1 over the content of the index file before this checksum. */ git_oid_fromraw(&checksum_expected, (const unsigned char *)buffer); - if (git_oid_cmp(&checksum_calculated, &checksum_expected) != 0) + if (git_oid__cmp(&checksum_calculated, &checksum_expected) != 0) return index_error_invalid("calculated checksum does not match expected"); #undef seek_forward diff --git a/src/indexer.c b/src/indexer.c index 606771927..91b7ba5d9 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -9,7 +9,6 @@ #include "git2/indexer.h" #include "git2/object.h" -#include "git2/oid.h" #include "common.h" #include "pack.h" @@ -17,6 +16,7 @@ #include "posix.h" #include "pack.h" #include "filebuf.h" +#include "oid.h" #include "oidmap.h" #define UINT31_MAX (0x7FFFFFFF) @@ -103,7 +103,7 @@ static int objects_cmp(const void *a, const void *b) const struct entry *entrya = a; const struct entry *entryb = b; - return git_oid_cmp(&entrya->oid, &entryb->oid); + return git_oid__cmp(&entrya->oid, &entryb->oid); } int git_indexer_stream_new( diff --git a/src/odb.c b/src/odb.c index 53630dddc..2574c6789 100644 --- a/src/odb.c +++ b/src/odb.c @@ -764,7 +764,7 @@ attempt_lookup: git__free(data); data = raw.data; - if (found && git_oid_cmp(&full_oid, &found_full_oid)) + if (found && git_oid__cmp(&full_oid, &found_full_oid)) return git_odb__error_ambiguous("multiple matches for prefix"); found_full_oid = full_oid; diff --git a/src/oid.c b/src/oid.c index c7ce6ee50..e74640c57 100644 --- a/src/oid.c +++ b/src/oid.c @@ -166,9 +166,9 @@ void git_oid_cpy(git_oid *out, const git_oid *src) memcpy(out->id, src->id, sizeof(out->id)); } -int git_oid_compare(const git_oid *oid_a, const git_oid *oid_b) +int git_oid_cmp(const git_oid *a, const git_oid *b) { - return git_oid_cmp(oid_a, oid_b); + return git_oid__cmp(a, b); } int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len) diff --git a/src/pack.c b/src/pack.c index 33cdf760a..f8b621ef8 100644 --- a/src/pack.c +++ b/src/pack.c @@ -12,8 +12,8 @@ #include "sha1_lookup.h" #include "mwindow.h" #include "fileops.h" +#include "oid.h" -#include "git2/oid.h" #include static int packfile_open(struct git_pack_file *p); @@ -875,7 +875,7 @@ static int packfile_open(struct git_pack_file *p) idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40; - if (git_oid_cmp(&sha1, (git_oid *)idx_sha1) == 0) + if (git_oid__cmp(&sha1, (git_oid *)idx_sha1) == 0) return 0; cleanup: @@ -1139,7 +1139,7 @@ int git_pack_entry_find( if (len == GIT_OID_HEXSZ && p->num_bad_objects) { unsigned i; for (i = 0; i < p->num_bad_objects; i++) - if (git_oid_cmp(short_oid, &p->bad_object_sha1[i]) == 0) + if (git_oid__cmp(short_oid, &p->bad_object_sha1[i]) == 0) return packfile_error("bad object found in packfile"); } diff --git a/src/push.c b/src/push.c index b6be1a4e1..9b1e78c8e 100644 --- a/src/push.c +++ b/src/push.c @@ -376,7 +376,7 @@ static int queue_differences( const git_tree_entry *d_entry = git_tree_entry_byindex(delta, j); int cmp = 0; - if (!git_oid_cmp(&b_entry->oid, &d_entry->oid)) + if (!git_oid__cmp(&b_entry->oid, &d_entry->oid)) goto loop; cmp = strcmp(b_entry->filename, d_entry->filename); diff --git a/src/refs.c b/src/refs.c index 9c6684a5a..f3a504147 100644 --- a/src/refs.c +++ b/src/refs.c @@ -831,7 +831,7 @@ int git_reference_cmp(git_reference *ref1, git_reference *ref2) if (type1 == GIT_REF_SYMBOLIC) return strcmp(ref1->target.symbolic, ref2->target.symbolic); - return git_oid_cmp(&ref1->target.oid, &ref2->target.oid); + return git_oid__cmp(&ref1->target.oid, &ref2->target.oid); } static int reference__update_terminal( diff --git a/src/refs.h b/src/refs.h index 97d4d2eb5..908e86f29 100644 --- a/src/refs.h +++ b/src/refs.h @@ -13,6 +13,7 @@ #include "git2/refdb.h" #include "strmap.h" #include "buffer.h" +#include "oid.h" #define GIT_REFS_DIR "refs/" #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/" diff --git a/src/remote.c b/src/remote.c index ffce2b6e2..306bc7356 100644 --- a/src/remote.c +++ b/src/remote.c @@ -845,7 +845,7 @@ static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vecto if (error == GIT_ENOTFOUND) memset(&old, 0, GIT_OID_RAWSZ); - if (!git_oid_cmp(&old, &head->oid)) + if (!git_oid__cmp(&old, &head->oid)) continue; /* In autotag mode, don't overwrite any locally-existing tags */ diff --git a/src/transports/local.c b/src/transports/local.c index 8af970eac..8b4d50c14 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -282,7 +282,7 @@ static int local_push_copy_object( odb_obj_size) < 0 || odb_stream->finalize_write(&remote_odb_obj_oid, odb_stream) < 0) { error = -1; - } else if (git_oid_cmp(&obj->id, &remote_odb_obj_oid) != 0) { + } else if (git_oid__cmp(&obj->id, &remote_odb_obj_oid) != 0) { giterr_set(GITERR_ODB, "Error when writing object to remote odb " "during local push operation. Remote odb object oid does not " "match local oid."); From d77611022c4a43d5e67cf52ce2bc2b11ee5bcdc0 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 29 Apr 2013 14:22:06 -0700 Subject: [PATCH 099/134] Standardize cast versions of git_object accessors This removes the GIT_INLINE versions of the simple git_object accessors and standardizes them with a helper macro in src/object.h to build the function bodies. --- include/git2/blob.h | 28 +++++++++++----------------- include/git2/tag.h | 31 +++++++++++++------------------ include/git2/tree.h | 20 +++++--------------- src/blob.c | 2 ++ src/object.h | 12 ++++++++++++ src/tag.c | 7 ++----- src/tree.c | 12 ++---------- 7 files changed, 47 insertions(+), 65 deletions(-) diff --git a/include/git2/blob.h b/include/git2/blob.h index 0a2aa9d36..8fca48966 100644 --- a/include/git2/blob.h +++ b/include/git2/blob.h @@ -29,10 +29,7 @@ GIT_BEGIN_DECL * @param id identity of the blob to locate. * @return 0 or an error code */ -GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git_oid *id) -{ - return git_object_lookup((git_object **)blob, repo, id, GIT_OBJ_BLOB); -} +GIT_EXTERN(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git_oid *id); /** * Lookup a blob object from a repository, @@ -46,10 +43,7 @@ GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git * @param len the length of the short identifier * @return 0 or an error code */ -GIT_INLINE(int) git_blob_lookup_prefix(git_blob **blob, git_repository *repo, const git_oid *id, size_t len) -{ - return git_object_lookup_prefix((git_object **)blob, repo, id, len, GIT_OBJ_BLOB); -} +GIT_EXTERN(int) git_blob_lookup_prefix(git_blob **blob, git_repository *repo, const git_oid *id, size_t len); /** * Close an open blob @@ -62,11 +56,7 @@ GIT_INLINE(int) git_blob_lookup_prefix(git_blob **blob, git_repository *repo, co * * @param blob the blob to close */ - -GIT_INLINE(void) git_blob_free(git_blob *blob) -{ - git_object_free((git_object *) blob); -} +GIT_EXTERN(void) git_blob_free(git_blob *blob); /** * Get the id of a blob. @@ -74,11 +64,15 @@ GIT_INLINE(void) git_blob_free(git_blob *blob) * @param blob a previously loaded blob. * @return SHA1 hash for this blob. */ -GIT_INLINE(const git_oid *) git_blob_id(const git_blob *blob) -{ - return git_object_id((const git_object *)blob); -} +GIT_EXTERN(const git_oid *) git_blob_id(const git_blob *blob); +/** + * Get the repository that contains the blob. + * + * @param blob A previously loaded blob. + * @return Repository that contains this blob. + */ +GIT_EXTERN(git_repository *) git_blob_owner(const git_blob *blob); /** * Get a read-only buffer with the raw content of a blob. diff --git a/include/git2/tag.h b/include/git2/tag.h index 84c954c27..469b1d72b 100644 --- a/include/git2/tag.h +++ b/include/git2/tag.h @@ -30,12 +30,8 @@ GIT_BEGIN_DECL * @param id identity of the tag to locate. * @return 0 or an error code */ -GIT_INLINE(int) git_tag_lookup( - git_tag **out, git_repository *repo, const git_oid *id) -{ - return git_object_lookup( - (git_object **)out, repo, id, (git_otype)GIT_OBJ_TAG); -} +GIT_EXTERN(int) git_tag_lookup( + git_tag **out, git_repository *repo, const git_oid *id); /** * Lookup a tag object from the repository, @@ -49,12 +45,8 @@ GIT_INLINE(int) git_tag_lookup( * @param len the length of the short identifier * @return 0 or an error code */ -GIT_INLINE(int) git_tag_lookup_prefix( - git_tag **out, git_repository *repo, const git_oid *id, size_t len) -{ - return git_object_lookup_prefix( - (git_object **)out, repo, id, len, (git_otype)GIT_OBJ_TAG); -} +GIT_EXTERN(int) git_tag_lookup_prefix( + git_tag **out, git_repository *repo, const git_oid *id, size_t len); /** * Close an open tag @@ -66,12 +58,7 @@ GIT_INLINE(int) git_tag_lookup_prefix( * * @param tag the tag to close */ - -GIT_INLINE(void) git_tag_free(git_tag *tag) -{ - git_object_free((git_object *)tag); -} - +GIT_EXTERN(void) git_tag_free(git_tag *tag); /** * Get the id of a tag. @@ -81,6 +68,14 @@ GIT_INLINE(void) git_tag_free(git_tag *tag) */ GIT_EXTERN(const git_oid *) git_tag_id(const git_tag *tag); +/** + * Get the repository that contains the tag. + * + * @param tag A previously loaded tag. + * @return Repository that contains this tag. + */ +GIT_EXTERN(git_repository *) git_tag_owner(const git_tag *tag); + /** * Get the tagged object of a tag * diff --git a/include/git2/tree.h b/include/git2/tree.h index 73bfc86f4..6ad722048 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -29,11 +29,8 @@ GIT_BEGIN_DECL * @param id Identity of the tree to locate. * @return 0 or an error code */ -GIT_INLINE(int) git_tree_lookup( - git_tree **out, git_repository *repo, const git_oid *id) -{ - return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_TREE); -} +GIT_EXTERN(int) git_tree_lookup( + git_tree **out, git_repository *repo, const git_oid *id); /** * Lookup a tree object from the repository, @@ -47,15 +44,11 @@ GIT_INLINE(int) git_tree_lookup( * @param len the length of the short identifier * @return 0 or an error code */ -GIT_INLINE(int) git_tree_lookup_prefix( +GIT_EXTERN(int) git_tree_lookup_prefix( git_tree **out, git_repository *repo, const git_oid *id, - size_t len) -{ - return git_object_lookup_prefix( - (git_object **)out, repo, id, len, GIT_OBJ_TREE); -} + size_t len); /** * Close an open tree @@ -67,10 +60,7 @@ GIT_INLINE(int) git_tree_lookup_prefix( * * @param tree The tree to close */ -GIT_INLINE(void) git_tree_free(git_tree *tree) -{ - git_object_free((git_object *)tree); -} +GIT_EXTERN(void) git_tree_free(git_tree *tree); /** * Get the id of a tree. diff --git a/src/blob.c b/src/blob.c index a68c4cc3e..d656576b8 100644 --- a/src/blob.c +++ b/src/blob.c @@ -15,6 +15,8 @@ #include "filter.h" #include "buf_text.h" +GIT_OBJ_WRAPPER(git_blob, GIT_OBJ_BLOB) + const void *git_blob_rawcontent(const git_blob *blob) { assert(blob); diff --git a/src/object.h b/src/object.h index d187c55b7..906d40736 100644 --- a/src/object.h +++ b/src/object.h @@ -28,4 +28,16 @@ int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid); +#define GIT_OBJ_WRAPPER(TYPE,OBJTYPE) \ + int TYPE##_lookup(TYPE **out, git_repository *repo, const git_oid *id) { \ + return git_object_lookup((git_object **)out, repo, id, OBJTYPE); } \ + int TYPE##_lookup_prefix(TYPE **out, git_repository *repo, const git_oid *id, size_t len) { \ + return git_object_lookup_prefix((git_object **)out, repo, id, len, OBJTYPE); } \ + void TYPE##_free(TYPE *obj) { \ + git_object_free((git_object *)obj); } \ + const git_oid *TYPE##_id(const TYPE *obj) { \ + return git_object_id((const git_object *)obj); } \ + git_repository *TYPE##_owner(const TYPE *obj) { \ + return git_object_owner((const git_object *)obj); } + #endif diff --git a/src/tag.c b/src/tag.c index b9a806cd1..ad3a8fd36 100644 --- a/src/tag.c +++ b/src/tag.c @@ -15,6 +15,8 @@ #include "git2/signature.h" #include "git2/odb_backend.h" +GIT_OBJ_WRAPPER(git_tag, GIT_OBJ_TAG) + void git_tag__free(void *_tag) { git_tag *tag = _tag; @@ -24,11 +26,6 @@ void git_tag__free(void *_tag) git__free(tag); } -const git_oid *git_tag_id(const git_tag *c) -{ - return git_object_id((const git_object *)c); -} - int git_tag_target(git_object **target, const git_tag *t) { assert(t); diff --git a/src/tree.c b/src/tree.c index 58eb92f35..67c9a068d 100644 --- a/src/tree.c +++ b/src/tree.c @@ -11,6 +11,8 @@ #include "git2/repository.h" #include "git2/object.h" +GIT_OBJ_WRAPPER(git_tree, GIT_OBJ_TREE) + #define DEFAULT_TREE_SIZE 16 #define MAX_FILEMODE_BYTES 6 @@ -232,16 +234,6 @@ void git_tree__free(void *_tree) git__free(tree); } -const git_oid *git_tree_id(const git_tree *t) -{ - return git_object_id((const git_object *)t); -} - -git_repository *git_tree_owner(const git_tree *t) -{ - return git_object_owner((const git_object *)t); -} - git_filemode_t git_tree_entry_filemode(const git_tree_entry *entry) { return (git_filemode_t)entry->attr; From e4af0f001600cfe7d72cfb140fc7dc2d25be2c37 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 29 Apr 2013 18:15:43 -0700 Subject: [PATCH 100/134] Add new src/oid.h --- src/oid.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/oid.h diff --git a/src/oid.h b/src/oid.h new file mode 100644 index 000000000..077d0a4c8 --- /dev/null +++ b/src/oid.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_oid_h__ +#define INCLUDE_oid_h__ + +#include "git2/oid.h" + +/* + * Compare two oid structures. + * + * @param a first oid structure. + * @param b second oid structure. + * @return <0, 0, >0 if a < b, a == b, a > b. + */ +GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b) +{ + const unsigned char *sha1 = a->id; + const unsigned char *sha2 = b->id; + int i; + + for (i = 0; i < GIT_OID_RAWSZ; i++, sha1++, sha2++) { + if (*sha1 != *sha2) + return *sha1 - *sha2; + } + + return 0; +} + +#endif From 203d5b0e6829242ea412bbef7751e3c522ac5dd8 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 29 Apr 2013 18:20:58 -0700 Subject: [PATCH 101/134] Some cleanups Removed useless prototype and renamed object typecast functions declaration macro. --- include/git2/oid.h | 9 --------- src/blob.c | 2 +- src/object.h | 2 +- src/tag.c | 2 +- src/tree.c | 2 +- 5 files changed, 4 insertions(+), 13 deletions(-) diff --git a/include/git2/oid.h b/include/git2/oid.h index 288e90bc8..b20bb221a 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -138,15 +138,6 @@ GIT_EXTERN(char *) git_oid_tostr(char *out, size_t n, const git_oid *id); */ GIT_EXTERN(void) git_oid_cpy(git_oid *out, const git_oid *src); -/** - * Compare two oid structures. - * - * @param a first oid structure. - * @param b second oid structure. - * @return <0, 0, >0 if a < b, a == b, a > b. - */ -GIT_EXTERN(int) git_oid_compare(const git_oid *oid_a, const git_oid *oid_b); - /** * Compare two oid structures. * diff --git a/src/blob.c b/src/blob.c index d656576b8..25ea0df30 100644 --- a/src/blob.c +++ b/src/blob.c @@ -15,7 +15,7 @@ #include "filter.h" #include "buf_text.h" -GIT_OBJ_WRAPPER(git_blob, GIT_OBJ_BLOB) +GIT_OBJECT__TYPED_FUNCTIONS(git_blob, GIT_OBJ_BLOB) const void *git_blob_rawcontent(const git_blob *blob) { diff --git a/src/object.h b/src/object.h index 906d40736..7b25fc342 100644 --- a/src/object.h +++ b/src/object.h @@ -28,7 +28,7 @@ int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid); -#define GIT_OBJ_WRAPPER(TYPE,OBJTYPE) \ +#define GIT_OBJECT__TYPED_FUNCTIONS(TYPE,OBJTYPE) \ int TYPE##_lookup(TYPE **out, git_repository *repo, const git_oid *id) { \ return git_object_lookup((git_object **)out, repo, id, OBJTYPE); } \ int TYPE##_lookup_prefix(TYPE **out, git_repository *repo, const git_oid *id, size_t len) { \ diff --git a/src/tag.c b/src/tag.c index ad3a8fd36..a0ecce176 100644 --- a/src/tag.c +++ b/src/tag.c @@ -15,7 +15,7 @@ #include "git2/signature.h" #include "git2/odb_backend.h" -GIT_OBJ_WRAPPER(git_tag, GIT_OBJ_TAG) +GIT_OBJECT__TYPED_FUNCTIONS(git_tag, GIT_OBJ_TAG) void git_tag__free(void *_tag) { diff --git a/src/tree.c b/src/tree.c index 67c9a068d..0a94aec10 100644 --- a/src/tree.c +++ b/src/tree.c @@ -11,7 +11,7 @@ #include "git2/repository.h" #include "git2/object.h" -GIT_OBJ_WRAPPER(git_tree, GIT_OBJ_TREE) +GIT_OBJECT__TYPED_FUNCTIONS(git_tree, GIT_OBJ_TREE) #define DEFAULT_TREE_SIZE 16 #define MAX_FILEMODE_BYTES 6 From 8d39f2a79067c9551286bb552457db71b88b64d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 30 Apr 2013 10:55:17 +0200 Subject: [PATCH 102/134] refspec: add direction accessor --- include/git2/refspec.h | 8 ++++++++ src/refspec.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/include/git2/refspec.h b/include/git2/refspec.h index 3e1b502ef..89ab81b02 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -51,6 +51,14 @@ GIT_EXTERN(const char *) git_refspec_string(const git_refspec *refspec); */ GIT_EXTERN(int) git_refspec_force(const git_refspec *refspec); +/** + * Get the refspec's direction. + * + * @param the refspec + * @return GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH + */ +GIT_EXTERN(git_direction) git_refspec_direction(const git_refspec *spec); + /** * Check if a refspec's source descriptor matches a reference * diff --git a/src/refspec.c b/src/refspec.c index 256540819..a907df84c 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -274,3 +274,10 @@ int git_refspec_is_wildcard(const git_refspec *spec) return (spec->src[strlen(spec->src) - 1] == '*'); } + +git_direction git_refspec_direction(const git_refspec *spec) +{ + assert(spec); + + return spec->push; +} From 1ffd0806f406a9dc300dbdefaf1e1d036a4294b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 30 Apr 2013 11:18:16 +0200 Subject: [PATCH 103/134] remote: add resfpec list accessors Bring back a way of acessing the git_refspec* from a remote. Closes #1514 --- include/git2/refspec.h | 1 + include/git2/remote.h | 26 ++++++++++++++++++++++++++ src/remote.c | 26 ++++++++++++++++++++++++++ tests-clar/clone/nonetwork.c | 4 ++-- tests-clar/network/remote/remotes.c | 15 +++++++-------- 5 files changed, 62 insertions(+), 10 deletions(-) diff --git a/include/git2/refspec.h b/include/git2/refspec.h index 89ab81b02..c0b410cbf 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -9,6 +9,7 @@ #include "common.h" #include "types.h" +#include "net.h" /** * @file git2/refspec.h diff --git a/include/git2/remote.h b/include/git2/remote.h index f02b95678..2aa384a54 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -190,6 +190,32 @@ GIT_EXTERN(int) git_remote_get_push_refspecs(git_strarray *array, git_remote *re */ GIT_EXTERN(void) git_remote_clear_refspecs(git_remote *remote); +/** + * Get the number of refspecs for a remote + * + * @param remote the remote + * @return the amount of refspecs configured in this remote + */ +GIT_EXTERN(size_t) git_remote_refspec_count(git_remote *remote); + +/** + * Get a refspec from the remote + * + * @param remote the remote to query + * @param n the refspec to get + * @return the nth refspec + */ +GIT_EXTERN(const git_refspec *)git_remote_get_refspec(git_remote *remote, size_t n); + +/** + * Remove a refspec from the remote + * + * @param remote the remote to query + * @param n the refspec to remove + * @return 0 or GIT_ENOTFOUND + */ +GIT_EXTERN(int) git_remote_remove_refspec(git_remote *remote, size_t n); + /** * Open a connection to a remote * diff --git a/src/remote.c b/src/remote.c index 1183137a6..153c93470 100644 --- a/src/remote.c +++ b/src/remote.c @@ -8,6 +8,7 @@ #include "git2/config.h" #include "git2/types.h" #include "git2/oid.h" +#include "git2/net.h" #include "config.h" #include "repository.h" @@ -1574,3 +1575,28 @@ int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote) { return copy_refspecs(array, remote, true); } + +size_t git_remote_refspec_count(git_remote *remote) +{ + return remote->refspecs.length; +} + +const git_refspec *git_remote_get_refspec(git_remote *remote, size_t n) +{ + return git_vector_get(&remote->refspecs, n); +} + +int git_remote_remove_refspec(git_remote *remote, size_t n) +{ + git_refspec *spec; + + assert(remote); + + spec = git_vector_get(&remote->refspecs, n); + if (spec) { + git_refspec__free(spec); + git__free(spec); + } + + return git_vector_remove(&remote->refspecs, n); +} diff --git a/tests-clar/clone/nonetwork.c b/tests-clar/clone/nonetwork.c index 02066e07d..545fe3a06 100644 --- a/tests-clar/clone/nonetwork.c +++ b/tests-clar/clone/nonetwork.c @@ -149,7 +149,7 @@ void test_clone_nonetwork__custom_fetch_spec(void) cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); - actual_fs = git_vector_get(&g_remote->refspecs, 0); + actual_fs = git_remote_get_refspec(g_remote, 0); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); @@ -165,7 +165,7 @@ void test_clone_nonetwork__custom_push_spec(void) cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); cl_git_pass(git_remote_load(&g_remote, g_repo, "origin")); - actual_fs = git_vector_get(&g_remote->refspecs, g_remote->refspecs.length - 1); + actual_fs = git_remote_get_refspec(g_remote, git_remote_refspec_count(g_remote) - 1); cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs)); cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs)); } diff --git a/tests-clar/network/remote/remotes.c b/tests-clar/network/remote/remotes.c index 908e17d96..4c24db8eb 100644 --- a/tests-clar/network/remote/remotes.c +++ b/tests-clar/network/remote/remotes.c @@ -13,7 +13,7 @@ void test_network_remote_remotes__initialize(void) cl_git_pass(git_remote_load(&_remote, _repo, "test")); - _refspec = git_vector_get(&_remote->refspecs, 0); + _refspec = git_remote_get_refspec(_remote, 0); cl_assert(_refspec != NULL); } @@ -113,15 +113,14 @@ void test_network_remote_remotes__add_fetchspec(void) { size_t size; - size = _remote->refspecs.length; - cl_assert_equal_i(size, _remote->refspecs.length); + size = git_remote_refspec_count(_remote); cl_git_pass(git_remote_add_fetch(_remote, "refs/*:refs/*")); size++; - cl_assert_equal_i(size, _remote->refspecs.length); + cl_assert_equal_i(size, git_remote_refspec_count(_remote)); - _refspec = git_vector_get(&_remote->refspecs, size-1); + _refspec = git_remote_get_refspec(_remote, size - 1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); @@ -132,13 +131,13 @@ void test_network_remote_remotes__add_pushspec(void) { size_t size; - size = _remote->refspecs.length; + size = git_remote_refspec_count(_remote); cl_git_pass(git_remote_add_push(_remote, "refs/*:refs/*")); size++; - cl_assert_equal_i(size, _remote->refspecs.length); + cl_assert_equal_i(size, git_remote_refspec_count(_remote)); - _refspec = git_vector_get(&_remote->refspecs, size-1); + _refspec = git_remote_get_refspec(_remote, size - 1); cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); From 9c5d4b2e807cdbb83cf55868700b0387cd4e8c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 30 Apr 2013 12:05:16 +0200 Subject: [PATCH 104/134] remote: fix a leak when dwim'ing refspecs --- src/remote.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/remote.c b/src/remote.c index 153c93470..08f56cd51 100644 --- a/src/remote.c +++ b/src/remote.c @@ -692,6 +692,7 @@ static int dwim_refspecs(git_vector *refspecs, git_vector *refs) spec->dwim = 1; } + git_buf_free(&buf); return 0; } From 0a1755c045b930de474883eb6e7fedcc3403b494 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 30 Apr 2013 03:15:45 -0700 Subject: [PATCH 105/134] Catch issue in config set with no config file This prevents a segfault when setting a value in the config of a repository that doesn't have a config file. --- src/config.c | 6 ++++++ tests-clar/repo/open.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/config.c b/src/config.c index 3c0bbe9a7..2e1268ef3 100644 --- a/src/config.c +++ b/src/config.c @@ -373,6 +373,12 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) } internal = git_vector_get(&cfg->files, 0); + if (!internal) { + /* Should we auto-vivify .git/config? Tricky from this location */ + giterr_set(GITERR_CONFIG, "Cannot set value when no config files exist"); + return GIT_ENOTFOUND; + } + file = internal->file; error = file->set(file, name, value); diff --git a/tests-clar/repo/open.c b/tests-clar/repo/open.c index 7f93ae91a..6b5253797 100644 --- a/tests-clar/repo/open.c +++ b/tests-clar/repo/open.c @@ -280,3 +280,38 @@ void test_repo_open__opening_a_non_existing_repository_returns_ENOTFOUND(void) git_repository *repo; cl_assert_equal_i(GIT_ENOTFOUND, git_repository_open(&repo, "i-do-not/exist")); } + +void test_repo_open__no_config(void) +{ + git_buf path = GIT_BUF_INIT; + git_repository *repo; + git_config *config; + + cl_fixture_sandbox("empty_standard_repo"); + cl_git_pass(cl_rename("empty_standard_repo/.gitted", "empty_standard_repo/.git")); + + /* remove local config */ + cl_git_pass(git_futils_rmdir_r( + "empty_standard_repo/.git/config", NULL, GIT_RMDIR_REMOVE_FILES)); + + /* isolate from system level configs */ + cl_must_pass(p_mkdir("alternate", 0777)); + cl_git_pass(git_path_prettify(&path, "alternate", NULL)); + cl_git_pass(git_libgit2_opts( + GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); + cl_git_pass(git_libgit2_opts( + GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); + cl_git_pass(git_libgit2_opts( + GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); + + git_buf_free(&path); + + cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); + cl_git_pass(git_repository_config(&config, repo)); + + cl_git_fail(git_config_set_string(config, "test.set", "42")); + + git_config_free(config); + git_repository_free(repo); + cl_fixture_cleanup("empty_standard_repo"); +} From 0b726701f3d3c5a3a596b53d8db0b7a4b4032dfb Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 30 Apr 2013 13:13:38 +0200 Subject: [PATCH 106/134] object: Explicitly define helper API methods for all obj types --- include/git2/commit.h | 20 ++----- src/blob.c | 2 - src/object.h | 12 ---- src/object_api.c | 129 ++++++++++++++++++++++++++++++++++++++++++ src/tag.c | 2 - src/tree.c | 2 - 6 files changed, 133 insertions(+), 34 deletions(-) create mode 100644 src/object_api.c diff --git a/include/git2/commit.h b/include/git2/commit.h index 0f7601252..f536ac7c8 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -30,10 +30,7 @@ GIT_BEGIN_DECL * an annotated tag it will be peeled back to the commit. * @return 0 or an error code */ -GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, const git_oid *id) -{ - return git_object_lookup((git_object **)commit, repo, id, GIT_OBJ_COMMIT); -} +GIT_EXTERN(int) git_commit_lookup(git_commit **commit, git_repository *repo, const git_oid *id); /** * Lookup a commit object from a repository, @@ -48,10 +45,7 @@ GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, con * @param len the length of the short identifier * @return 0 or an error code */ -GIT_INLINE(int) git_commit_lookup_prefix(git_commit **commit, git_repository *repo, const git_oid *id, size_t len) -{ - return git_object_lookup_prefix((git_object **)commit, repo, id, len, GIT_OBJ_COMMIT); -} +GIT_EXTERN(int) git_commit_lookup_prefix(git_commit **commit, git_repository *repo, const git_oid *id, size_t len); /** * Close an open commit @@ -65,10 +59,7 @@ GIT_INLINE(int) git_commit_lookup_prefix(git_commit **commit, git_repository *re * @param commit the commit to close */ -GIT_INLINE(void) git_commit_free(git_commit *commit) -{ - git_object_free((git_object *) commit); -} +GIT_EXTERN(void) git_commit_free(git_commit *commit); /** * Get the id of a commit. @@ -76,10 +67,7 @@ GIT_INLINE(void) git_commit_free(git_commit *commit) * @param commit a previously loaded commit. * @return object identity for the commit. */ -GIT_INLINE(const git_oid *) git_commit_id(const git_commit *commit) -{ - return git_object_id((const git_object *)commit); -} +GIT_EXTERN(const git_oid *) git_commit_id(const git_commit *commit); /** * Get the encoding for the message of a commit, diff --git a/src/blob.c b/src/blob.c index 25ea0df30..a68c4cc3e 100644 --- a/src/blob.c +++ b/src/blob.c @@ -15,8 +15,6 @@ #include "filter.h" #include "buf_text.h" -GIT_OBJECT__TYPED_FUNCTIONS(git_blob, GIT_OBJ_BLOB) - const void *git_blob_rawcontent(const git_blob *blob) { assert(blob); diff --git a/src/object.h b/src/object.h index 7b25fc342..d187c55b7 100644 --- a/src/object.h +++ b/src/object.h @@ -28,16 +28,4 @@ int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid); -#define GIT_OBJECT__TYPED_FUNCTIONS(TYPE,OBJTYPE) \ - int TYPE##_lookup(TYPE **out, git_repository *repo, const git_oid *id) { \ - return git_object_lookup((git_object **)out, repo, id, OBJTYPE); } \ - int TYPE##_lookup_prefix(TYPE **out, git_repository *repo, const git_oid *id, size_t len) { \ - return git_object_lookup_prefix((git_object **)out, repo, id, len, OBJTYPE); } \ - void TYPE##_free(TYPE *obj) { \ - git_object_free((git_object *)obj); } \ - const git_oid *TYPE##_id(const TYPE *obj) { \ - return git_object_id((const git_object *)obj); } \ - git_repository *TYPE##_owner(const TYPE *obj) { \ - return git_object_owner((const git_object *)obj); } - #endif diff --git a/src/object_api.c b/src/object_api.c new file mode 100644 index 000000000..620617dfd --- /dev/null +++ b/src/object_api.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#include "git2/object.h" + +#include "common.h" +#include "repository.h" + +#include "commit.h" +#include "tree.h" +#include "blob.h" +#include "tag.h" + +/** + * Blob + */ +int git_commit_lookup(git_commit **out, git_repository *repo, const git_oid *id) +{ + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_COMMIT); +} + +int git_commit_lookup_prefix(git_commit **out, git_repository *repo, const git_oid *id, size_t len) +{ + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_COMMIT); +} + +void git_commit_free(git_commit *obj) +{ + git_object_free((git_object *)obj); +} + +const git_oid *git_commit_id(const git_commit *obj) +{ + return git_object_id((const git_object *)obj); +} + +git_repository *git_commit_owner(const git_commit *obj) +{ + return git_object_owner((const git_object *)obj); +} + + +/** + * Tree + */ +int git_tree_lookup(git_tree **out, git_repository *repo, const git_oid *id) +{ + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_COMMIT); +} + +int git_tree_lookup_prefix(git_tree **out, git_repository *repo, const git_oid *id, size_t len) +{ + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_COMMIT); +} + +void git_tree_free(git_tree *obj) +{ + git_object_free((git_object *)obj); +} + +const git_oid *git_tree_id(const git_tree *obj) +{ + return git_object_id((const git_object *)obj); +} + +git_repository *git_tree_owner(const git_tree *obj) +{ + return git_object_owner((const git_object *)obj); +} + + +/** + * Tag + */ +int git_tag_lookup(git_tag **out, git_repository *repo, const git_oid *id) +{ + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_COMMIT); +} + +int git_tag_lookup_prefix(git_tag **out, git_repository *repo, const git_oid *id, size_t len) +{ + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_COMMIT); +} + +void git_tag_free(git_tag *obj) +{ + git_object_free((git_object *)obj); +} + +const git_oid *git_tag_id(const git_tag *obj) +{ + return git_object_id((const git_object *)obj); +} + +git_repository *git_tag_owner(const git_tag *obj) +{ + return git_object_owner((const git_object *)obj); +} + +/** + * Blob + */ +int git_blob_lookup(git_blob **out, git_repository *repo, const git_oid *id) +{ + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_COMMIT); +} + +int git_blob_lookup_prefix(git_blob **out, git_repository *repo, const git_oid *id, size_t len) +{ + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_COMMIT); +} + +void git_blob_free(git_blob *obj) +{ + git_object_free((git_object *)obj); +} + +const git_oid *git_blob_id(const git_blob *obj) +{ + return git_object_id((const git_object *)obj); +} + +git_repository *git_blob_owner(const git_blob *obj) +{ + return git_object_owner((const git_object *)obj); +} diff --git a/src/tag.c b/src/tag.c index a0ecce176..a4f2e2581 100644 --- a/src/tag.c +++ b/src/tag.c @@ -15,8 +15,6 @@ #include "git2/signature.h" #include "git2/odb_backend.h" -GIT_OBJECT__TYPED_FUNCTIONS(git_tag, GIT_OBJ_TAG) - void git_tag__free(void *_tag) { git_tag *tag = _tag; diff --git a/src/tree.c b/src/tree.c index 0a94aec10..79cbcffcb 100644 --- a/src/tree.c +++ b/src/tree.c @@ -11,8 +11,6 @@ #include "git2/repository.h" #include "git2/object.h" -GIT_OBJECT__TYPED_FUNCTIONS(git_tree, GIT_OBJ_TREE) - #define DEFAULT_TREE_SIZE 16 #define MAX_FILEMODE_BYTES 6 From 7dcda3aa3780292e33bb9229ff998ffe4edc07bf Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 30 Apr 2013 13:19:02 +0200 Subject: [PATCH 107/134] object: haha --- src/object_api.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/object_api.c b/src/object_api.c index 620617dfd..838bba323 100644 --- a/src/object_api.c +++ b/src/object_api.c @@ -48,12 +48,12 @@ git_repository *git_commit_owner(const git_commit *obj) */ int git_tree_lookup(git_tree **out, git_repository *repo, const git_oid *id) { - return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_COMMIT); + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_TREE); } int git_tree_lookup_prefix(git_tree **out, git_repository *repo, const git_oid *id, size_t len) { - return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_COMMIT); + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_TREE); } void git_tree_free(git_tree *obj) @@ -77,12 +77,12 @@ git_repository *git_tree_owner(const git_tree *obj) */ int git_tag_lookup(git_tag **out, git_repository *repo, const git_oid *id) { - return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_COMMIT); + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_TAG); } int git_tag_lookup_prefix(git_tag **out, git_repository *repo, const git_oid *id, size_t len) { - return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_COMMIT); + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_TAG); } void git_tag_free(git_tag *obj) @@ -105,12 +105,12 @@ git_repository *git_tag_owner(const git_tag *obj) */ int git_blob_lookup(git_blob **out, git_repository *repo, const git_oid *id) { - return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_COMMIT); + return git_object_lookup((git_object **)out, repo, id, GIT_OBJ_BLOB); } int git_blob_lookup_prefix(git_blob **out, git_repository *repo, const git_oid *id, size_t len) { - return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_COMMIT); + return git_object_lookup_prefix((git_object **)out, repo, id, len, GIT_OBJ_BLOB); } void git_blob_free(git_blob *obj) From fdb3034e725ccf2c7be11871fcc374ced436983e Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 25 Apr 2013 14:57:13 -0700 Subject: [PATCH 108/134] Reorganize diff code into functions In preparation for more changes to the internal diff logic, it seemed wise to split the very large git_diff__from_iterators into separate functions that handle the four main cases (unmatched old item, unmatched new item, unmatched new directory, and matched old and new items). Hopefully this will keep the logic easier to follow even as more cases have to be added to this code. --- src/diff.c | 377 ++++++++++++++++++++++++++++------------------------- 1 file changed, 202 insertions(+), 175 deletions(-) diff --git a/src/diff.c b/src/diff.c index 6612abf06..58c7eacc6 100644 --- a/src/diff.c +++ b/src/diff.c @@ -530,24 +530,30 @@ cleanup: return result; } +typedef struct { + git_repository *repo; + git_iterator *old_iter; + git_iterator *new_iter; + const git_index_entry *oitem; + const git_index_entry *nitem; + git_buf ignore_prefix; +} diff_in_progress; + #define MODE_BITS_MASK 0000777 static int maybe_modified( - git_iterator *old_iter, - const git_index_entry *oitem, - git_iterator *new_iter, - const git_index_entry *nitem, - git_diff_list *diff) + git_diff_list *diff, + diff_in_progress *info) { git_oid noid, *use_noid = NULL; git_delta_t status = GIT_DELTA_MODIFIED; + const git_index_entry *oitem = info->oitem; + const git_index_entry *nitem = info->nitem; unsigned int omode = oitem->mode; unsigned int nmode = nitem->mode; - bool new_is_workdir = (new_iter->type == GIT_ITERATOR_TYPE_WORKDIR); + bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_TYPE_WORKDIR); const char *matched_pathspec; - GIT_UNUSED(old_iter); - if (!git_pathspec_match_path( &diff->pathspec, oitem->path, DIFF_FLAG_IS_SET(diff, GIT_DIFF_DISABLE_PATHSPEC_MATCH), @@ -692,6 +698,168 @@ static bool entry_is_prefixed( item->path[pathlen] == '/'); } +static int handle_unmatched_new_directory( + git_diff_list *diff, diff_in_progress *info, git_delta_t *delta) +{ + int error = 0; + const git_index_entry *nitem = info->nitem; + bool contains_oitem = entry_is_prefixed(diff, info->oitem, nitem); + bool recurse_into_dir = + (*delta == GIT_DELTA_UNTRACKED && + DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) || + (*delta == GIT_DELTA_IGNORED && + DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)); + + /* do not advance into directories that contain a .git file */ + if (!contains_oitem && recurse_into_dir) { + git_buf *full = NULL; + if (git_iterator_current_workdir_path(&full, info->new_iter) < 0) + return -1; + if (git_path_contains_dir(full, DOT_GIT)) + recurse_into_dir = false; + } + + /* if directory is ignored, remember ignore_prefix */ + if ((contains_oitem || recurse_into_dir) && + *delta == GIT_DELTA_UNTRACKED && + git_iterator_current_is_ignored(info->new_iter)) + { + git_buf_sets(&info->ignore_prefix, info->nitem->path); + *delta = GIT_DELTA_IGNORED; + + /* skip recursion if we've just learned this is ignored */ + if (DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) + recurse_into_dir = false; + } + + if (contains_oitem || recurse_into_dir) { + /* advance into directory */ + error = git_iterator_advance_into(&info->nitem, info->new_iter); + + /* if directory is empty, can't advance into it, so skip */ + if (error == GIT_ENOTFOUND) { + giterr_clear(); + error = git_iterator_advance(&info->nitem, info->new_iter); + + git_buf_clear(&info->ignore_prefix); + } + + /* return UNMODIFIED to tell caller not to create a new record */ + *delta = GIT_DELTA_UNMODIFIED; + } + + return error; +} + +static int handle_unmatched_new_item( + git_diff_list *diff, diff_in_progress *info) +{ + int error = 0; + const git_index_entry *nitem = info->nitem; + git_delta_t delta_type = GIT_DELTA_UNTRACKED; + + /* check if contained in ignored parent directory */ + if (git_buf_len(&info->ignore_prefix) && + diff->pfxcomp(nitem->path, git_buf_cstr(&info->ignore_prefix)) == 0) + delta_type = GIT_DELTA_IGNORED; + + if (S_ISDIR(nitem->mode)) { + error = handle_unmatched_new_directory(diff, info, &delta_type); + + if (error || delta_type == GIT_DELTA_UNMODIFIED) + return error; + } + + /* In core git, the next two "else if" clauses are effectively + * reversed -- i.e. when an untracked file contained in an + * ignored directory is individually ignored, it shows up as an + * ignored file in the diff list, even though other untracked + * files in the same directory are skipped completely. + * + * To me, this is odd. If the directory is ignored and the file + * is untracked, we should skip it consistently, regardless of + * whether it happens to match a pattern in the ignore file. + * + * To match the core git behavior, just reverse the following + * two "else if" cases so that individual file ignores are + * checked before container directory exclusions are used to + * skip the file. + */ + else if (delta_type == GIT_DELTA_IGNORED && + DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) + return git_iterator_advance(&info->nitem, info->new_iter); + + else if (git_iterator_current_is_ignored(info->new_iter)) + delta_type = GIT_DELTA_IGNORED; + + else if (info->new_iter->type != GIT_ITERATOR_TYPE_WORKDIR) + delta_type = GIT_DELTA_ADDED; + + if ((error = diff_delta__from_one(diff, delta_type, nitem)) < 0) + return error; + + /* if we are generating TYPECHANGE records then check for that + * instead of just generating an ADDED/UNTRACKED record + */ + if (delta_type != GIT_DELTA_IGNORED && + DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && + entry_is_prefixed(diff, info->oitem, nitem)) + { + /* this entry was prefixed with a tree - make TYPECHANGE */ + git_diff_delta *last = diff_delta__last_for_item(diff, nitem); + if (last) { + last->status = GIT_DELTA_TYPECHANGE; + last->old_file.mode = GIT_FILEMODE_TREE; + } + } + + return git_iterator_advance(&info->nitem, info->new_iter); +} + +static int handle_unmatched_old_item( + git_diff_list *diff, diff_in_progress *info) +{ + int error = diff_delta__from_one(diff, GIT_DELTA_DELETED, info->oitem); + if (error < 0) + return error; + + /* if we are generating TYPECHANGE records then check for that + * instead of just generating a DELETE record + */ + if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && + entry_is_prefixed(diff, info->nitem, info->oitem)) + { + /* this entry has become a tree! convert to TYPECHANGE */ + git_diff_delta *last = diff_delta__last_for_item(diff, info->oitem); + if (last) { + last->status = GIT_DELTA_TYPECHANGE; + last->new_file.mode = GIT_FILEMODE_TREE; + } + + /* If new_iter is a workdir iterator, then this situation + * will certainly be followed by a series of untracked items. + * Unless RECURSE_UNTRACKED_DIRS is set, skip over them... + */ + if (S_ISDIR(info->nitem->mode) && + DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) + return git_iterator_advance(&info->nitem, info->new_iter); + } + + return git_iterator_advance(&info->oitem, info->old_iter); +} + +static int handle_matched_item( + git_diff_list *diff, diff_in_progress *info) +{ + int error = 0; + + if (!(error = maybe_modified(diff, info)) && + !(error = git_iterator_advance(&info->oitem, info->old_iter))) + error = git_iterator_advance(&info->nitem, info->new_iter); + + return error; +} + int git_diff__from_iterators( git_diff_list **diff_ptr, git_repository *repo, @@ -700,8 +868,7 @@ int git_diff__from_iterators( const git_diff_options *opts) { int error = 0; - const git_index_entry *oitem, *nitem; - git_buf ignore_prefix = GIT_BUF_INIT; + diff_in_progress info; git_diff_list *diff; *diff_ptr = NULL; @@ -709,191 +876,51 @@ int git_diff__from_iterators( diff = diff_list_alloc(repo, old_iter, new_iter); GITERR_CHECK_ALLOC(diff); + info.repo = repo; + info.old_iter = old_iter; + info.new_iter = new_iter; + git_buf_init(&info.ignore_prefix, 0); + /* make iterators have matching icase behavior */ if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) { - if (git_iterator_set_ignore_case(old_iter, true) < 0 || - git_iterator_set_ignore_case(new_iter, true) < 0) - goto fail; + if (!(error = git_iterator_set_ignore_case(old_iter, true))) + error = git_iterator_set_ignore_case(new_iter, true); } - if (diff_list_apply_options(diff, opts) < 0 || - git_iterator_current(&oitem, old_iter) < 0 || - git_iterator_current(&nitem, new_iter) < 0) - goto fail; + /* finish initialization */ + if (!error && + !(error = diff_list_apply_options(diff, opts)) && + !(error = git_iterator_current(&info.oitem, old_iter))) + error = git_iterator_current(&info.nitem, new_iter); /* run iterators building diffs */ - while (oitem || nitem) { - int cmp = oitem ? (nitem ? diff->entrycomp(oitem, nitem) : -1) : 1; + while (!error && (info.oitem || info.nitem)) { + int cmp = info.oitem ? + (info.nitem ? diff->entrycomp(info.oitem, info.nitem) : -1) : 1; /* create DELETED records for old items not matched in new */ - if (cmp < 0) { - if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0) - goto fail; - - /* if we are generating TYPECHANGE records then check for that - * instead of just generating a DELETE record - */ - if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && - entry_is_prefixed(diff, nitem, oitem)) - { - /* this entry has become a tree! convert to TYPECHANGE */ - git_diff_delta *last = diff_delta__last_for_item(diff, oitem); - if (last) { - last->status = GIT_DELTA_TYPECHANGE; - last->new_file.mode = GIT_FILEMODE_TREE; - } - - /* If new_iter is a workdir iterator, then this situation - * will certainly be followed by a series of untracked items. - * Unless RECURSE_UNTRACKED_DIRS is set, skip over them... - */ - if (S_ISDIR(nitem->mode) && - DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) - { - if (git_iterator_advance(&nitem, new_iter) < 0) - goto fail; - } - } - - if (git_iterator_advance(&oitem, old_iter) < 0) - goto fail; - } + if (cmp < 0) + error = handle_unmatched_old_item(diff, &info); /* create ADDED, TRACKED, or IGNORED records for new items not * matched in old (and/or descend into directories as needed) */ - else if (cmp > 0) { - git_delta_t delta_type = GIT_DELTA_UNTRACKED; - bool contains_oitem = entry_is_prefixed(diff, oitem, nitem); - - /* check if contained in ignored parent directory */ - if (git_buf_len(&ignore_prefix) && - diff->pfxcomp(nitem->path, git_buf_cstr(&ignore_prefix)) == 0) - delta_type = GIT_DELTA_IGNORED; - - if (S_ISDIR(nitem->mode)) { - /* recurse into directory only if there are tracked items in - * it or if the user requested the contents of untracked - * directories and it is not under an ignored directory. - */ - bool recurse_into_dir = - (delta_type == GIT_DELTA_UNTRACKED && - DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) || - (delta_type == GIT_DELTA_IGNORED && - DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)); - - /* do not advance into directories that contain a .git file */ - if (!contains_oitem && recurse_into_dir) { - git_buf *full = NULL; - if (git_iterator_current_workdir_path(&full, new_iter) < 0) - goto fail; - if (git_path_contains_dir(full, DOT_GIT)) - recurse_into_dir = false; - } - - /* if directory is ignored, remember ignore_prefix */ - if ((contains_oitem || recurse_into_dir) && - delta_type == GIT_DELTA_UNTRACKED && - git_iterator_current_is_ignored(new_iter)) - { - git_buf_sets(&ignore_prefix, nitem->path); - delta_type = GIT_DELTA_IGNORED; - - /* skip recursion if we've just learned this is ignored */ - if (DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) - recurse_into_dir = false; - } - - if (contains_oitem || recurse_into_dir) { - /* advance into directory */ - error = git_iterator_advance_into(&nitem, new_iter); - - /* if directory is empty, can't advance into it, so skip */ - if (error == GIT_ENOTFOUND) { - giterr_clear(); - error = git_iterator_advance(&nitem, new_iter); - - git_buf_clear(&ignore_prefix); - } - - if (error < 0) - goto fail; - continue; - } - } - - /* In core git, the next two "else if" clauses are effectively - * reversed -- i.e. when an untracked file contained in an - * ignored directory is individually ignored, it shows up as an - * ignored file in the diff list, even though other untracked - * files in the same directory are skipped completely. - * - * To me, this is odd. If the directory is ignored and the file - * is untracked, we should skip it consistently, regardless of - * whether it happens to match a pattern in the ignore file. - * - * To match the core git behavior, just reverse the following - * two "else if" cases so that individual file ignores are - * checked before container directory exclusions are used to - * skip the file. - */ - else if (delta_type == GIT_DELTA_IGNORED && - DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) { - if (git_iterator_advance(&nitem, new_iter) < 0) - goto fail; - continue; /* ignored parent directory, so skip completely */ - } - - else if (git_iterator_current_is_ignored(new_iter)) - delta_type = GIT_DELTA_IGNORED; - - else if (new_iter->type != GIT_ITERATOR_TYPE_WORKDIR) - delta_type = GIT_DELTA_ADDED; - - if (diff_delta__from_one(diff, delta_type, nitem) < 0) - goto fail; - - /* if we are generating TYPECHANGE records then check for that - * instead of just generating an ADDED/UNTRACKED record - */ - if (delta_type != GIT_DELTA_IGNORED && - DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && - contains_oitem) - { - /* this entry was prefixed with a tree - make TYPECHANGE */ - git_diff_delta *last = diff_delta__last_for_item(diff, nitem); - if (last) { - last->status = GIT_DELTA_TYPECHANGE; - last->old_file.mode = GIT_FILEMODE_TREE; - } - } - - if (git_iterator_advance(&nitem, new_iter) < 0) - goto fail; - } + else if (cmp > 0) + error = handle_unmatched_new_item(diff, &info); /* otherwise item paths match, so create MODIFIED record * (or ADDED and DELETED pair if type changed) */ - else { - assert(oitem && nitem && cmp == 0); - - if (maybe_modified(old_iter, oitem, new_iter, nitem, diff) < 0 || - git_iterator_advance(&oitem, old_iter) < 0 || - git_iterator_advance(&nitem, new_iter) < 0) - goto fail; - } + else + error = handle_matched_item(diff, &info); } - *diff_ptr = diff; - -fail: - if (!*diff_ptr) { + if (!error) + *diff_ptr = diff; + else git_diff_list_free(diff); - error = -1; - } - git_buf_free(&ignore_prefix); + git_buf_free(&info.ignore_prefix); return error; } From e26b14c0345ef82771f222aa50be926f5969531d Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Fri, 26 Apr 2013 15:35:47 -0700 Subject: [PATCH 109/134] Update diff handling of untracked directories When diff encounters an untracked directory, there was a shortcut that it took which is not compatible with core git. This makes the default behavior no longer take that shortcut and instead look inside the untracked directory to see if there are any untracked files within it. If there are not, then the directory is treated as an ignore directory instead of an untracked directory. This has implications for the git_status APIs. --- include/git2/diff.h | 7 + include/git2/submodule.h | 28 ++-- src/diff.c | 209 ++++++++++++++++++++--------- src/vector.c | 8 +- tests-clar/status/status_helpers.c | 3 +- tests-clar/status/status_helpers.h | 1 + tests-clar/status/worktree.c | 5 +- tests-clar/submodule/status.c | 27 ++++ 8 files changed, 202 insertions(+), 86 deletions(-) diff --git a/include/git2/diff.h b/include/git2/diff.h index d9ceadf20..cc16d01b6 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -124,6 +124,13 @@ typedef enum { * adds all files under the directory as IGNORED entries, too. */ GIT_DIFF_RECURSE_IGNORED_DIRS = (1 << 18), + /** For an untracked directory, diff can immediately label it UNTRACKED, + * but this differs from core Git which scans underneath for untracked + * or ignored files and marks the directory ignored unless it contains + * untracked files under it. That search can be slow. This flag makes + * diff skip ahead and immediately report the directory as untracked. + */ + GIT_DIFF_FAST_UNTRACKED_DIRS = (1 << 19), } git_diff_option_t; /** diff --git a/include/git2/submodule.h b/include/git2/submodule.h index 40934b3ed..004665050 100644 --- a/include/git2/submodule.h +++ b/include/git2/submodule.h @@ -103,20 +103,20 @@ typedef enum { * * WD_UNTRACKED - wd contains untracked files */ typedef enum { - GIT_SUBMODULE_STATUS_IN_HEAD = (1u << 0), - GIT_SUBMODULE_STATUS_IN_INDEX = (1u << 1), - GIT_SUBMODULE_STATUS_IN_CONFIG = (1u << 2), - GIT_SUBMODULE_STATUS_IN_WD = (1u << 3), - GIT_SUBMODULE_STATUS_INDEX_ADDED = (1u << 4), - GIT_SUBMODULE_STATUS_INDEX_DELETED = (1u << 5), - GIT_SUBMODULE_STATUS_INDEX_MODIFIED = (1u << 6), - GIT_SUBMODULE_STATUS_WD_UNINITIALIZED = (1u << 7), - GIT_SUBMODULE_STATUS_WD_ADDED = (1u << 8), - GIT_SUBMODULE_STATUS_WD_DELETED = (1u << 9), - GIT_SUBMODULE_STATUS_WD_MODIFIED = (1u << 10), - GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = (1u << 11), - GIT_SUBMODULE_STATUS_WD_WD_MODIFIED = (1u << 12), - GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13), + GIT_SUBMODULE_STATUS_IN_HEAD = (1u << 0), + GIT_SUBMODULE_STATUS_IN_INDEX = (1u << 1), + GIT_SUBMODULE_STATUS_IN_CONFIG = (1u << 2), + GIT_SUBMODULE_STATUS_IN_WD = (1u << 3), + GIT_SUBMODULE_STATUS_INDEX_ADDED = (1u << 4), + GIT_SUBMODULE_STATUS_INDEX_DELETED = (1u << 5), + GIT_SUBMODULE_STATUS_INDEX_MODIFIED = (1u << 6), + GIT_SUBMODULE_STATUS_WD_UNINITIALIZED = (1u << 7), + GIT_SUBMODULE_STATUS_WD_ADDED = (1u << 8), + GIT_SUBMODULE_STATUS_WD_DELETED = (1u << 9), + GIT_SUBMODULE_STATUS_WD_MODIFIED = (1u << 10), + GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED = (1u << 11), + GIT_SUBMODULE_STATUS_WD_WD_MODIFIED = (1u << 12), + GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13), } git_submodule_status_t; #define GIT_SUBMODULE_STATUS__IN_FLAGS \ diff --git a/src/diff.c b/src/diff.c index 58c7eacc6..cea3fdb22 100644 --- a/src/diff.c +++ b/src/diff.c @@ -698,56 +698,58 @@ static bool entry_is_prefixed( item->path[pathlen] == '/'); } -static int handle_unmatched_new_directory( - git_diff_list *diff, diff_in_progress *info, git_delta_t *delta) +static int diff_scan_inside_untracked_dir( + git_diff_list *diff, diff_in_progress *info, git_delta_t *delta_type) { int error = 0; - const git_index_entry *nitem = info->nitem; - bool contains_oitem = entry_is_prefixed(diff, info->oitem, nitem); - bool recurse_into_dir = - (*delta == GIT_DELTA_UNTRACKED && - DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) || - (*delta == GIT_DELTA_IGNORED && - DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)); + git_buf base = GIT_BUF_INIT; + bool is_ignored; - /* do not advance into directories that contain a .git file */ - if (!contains_oitem && recurse_into_dir) { - git_buf *full = NULL; - if (git_iterator_current_workdir_path(&full, info->new_iter) < 0) - return -1; - if (git_path_contains_dir(full, DOT_GIT)) - recurse_into_dir = false; - } + *delta_type = GIT_DELTA_IGNORED; + git_buf_sets(&base, info->nitem->path); - /* if directory is ignored, remember ignore_prefix */ - if ((contains_oitem || recurse_into_dir) && - *delta == GIT_DELTA_UNTRACKED && - git_iterator_current_is_ignored(info->new_iter)) - { - git_buf_sets(&info->ignore_prefix, info->nitem->path); - *delta = GIT_DELTA_IGNORED; + /* advance into untracked directory */ + if ((error = git_iterator_advance_into(&info->nitem, info->new_iter)) < 0) { - /* skip recursion if we've just learned this is ignored */ - if (DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) - recurse_into_dir = false; - } - - if (contains_oitem || recurse_into_dir) { - /* advance into directory */ - error = git_iterator_advance_into(&info->nitem, info->new_iter); - - /* if directory is empty, can't advance into it, so skip */ + /* skip ahead if empty */ if (error == GIT_ENOTFOUND) { giterr_clear(); error = git_iterator_advance(&info->nitem, info->new_iter); - - git_buf_clear(&info->ignore_prefix); } - /* return UNMODIFIED to tell caller not to create a new record */ - *delta = GIT_DELTA_UNMODIFIED; + return error; } + /* look for actual untracked file */ + while (!diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) { + is_ignored = git_iterator_current_is_ignored(info->new_iter); + + /* need to recurse into non-ignored directories */ + if (!is_ignored && S_ISDIR(info->nitem->mode)) { + if ((error = git_iterator_advance_into( + &info->nitem, info->new_iter)) < 0) + break; + continue; + } + + /* found a non-ignored item - treat parent dir as untracked */ + if (!is_ignored) { + *delta_type = GIT_DELTA_UNTRACKED; + break; + } + + if ((error = git_iterator_advance(&info->nitem, info->new_iter)) < 0) + break; + } + + /* finish off scan */ + while (!diff->pfxcomp(info->nitem->path, git_buf_cstr(&base))) { + if ((error = git_iterator_advance(&info->nitem, info->new_iter)) < 0) + break; + } + + git_buf_free(&base); + return error; } @@ -757,36 +759,116 @@ static int handle_unmatched_new_item( int error = 0; const git_index_entry *nitem = info->nitem; git_delta_t delta_type = GIT_DELTA_UNTRACKED; + bool contains_oitem; - /* check if contained in ignored parent directory */ - if (git_buf_len(&info->ignore_prefix) && - diff->pfxcomp(nitem->path, git_buf_cstr(&info->ignore_prefix)) == 0) - delta_type = GIT_DELTA_IGNORED; + /* check if this is a prefix of the other side */ + contains_oitem = entry_is_prefixed(diff, info->oitem, nitem); - if (S_ISDIR(nitem->mode)) { - error = handle_unmatched_new_directory(diff, info, &delta_type); - - if (error || delta_type == GIT_DELTA_UNMODIFIED) - return error; + /* check if this is contained in an ignored parent directory */ + if (git_buf_len(&info->ignore_prefix)) { + if (diff->pfxcomp(nitem->path, git_buf_cstr(&info->ignore_prefix)) == 0) + delta_type = GIT_DELTA_IGNORED; + else + git_buf_clear(&info->ignore_prefix); } - /* In core git, the next two "else if" clauses are effectively - * reversed -- i.e. when an untracked file contained in an - * ignored directory is individually ignored, it shows up as an - * ignored file in the diff list, even though other untracked - * files in the same directory are skipped completely. + if (S_ISDIR(nitem->mode)) { + bool recurse_into_dir = contains_oitem; + + /* if not already inside an ignored dir, check if this is ignored */ + if (delta_type != GIT_DELTA_IGNORED && + git_iterator_current_is_ignored(info->new_iter)) + { + delta_type = GIT_DELTA_IGNORED; + git_buf_sets(&info->ignore_prefix, nitem->path); + } + + /* check if user requests recursion into this type of dir */ + recurse_into_dir = contains_oitem || + (delta_type == GIT_DELTA_UNTRACKED && + DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_UNTRACKED_DIRS)) || + (delta_type == GIT_DELTA_IGNORED && + DIFF_FLAG_IS_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)); + + /* do not advance into directories that contain a .git file */ + if (recurse_into_dir) { + git_buf *full = NULL; + if (git_iterator_current_workdir_path(&full, info->new_iter) < 0) + return -1; + if (full && git_path_contains_dir(full, DOT_GIT)) + recurse_into_dir = false; + } + + /* still have to look into untracked directories to match core git - + * with no untracked files, directory is treated as ignored + */ + if (!recurse_into_dir && + delta_type == GIT_DELTA_UNTRACKED && + DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_FAST_UNTRACKED_DIRS)) + { + git_diff_delta *last; + + /* attempt to insert record for this directory */ + if ((error = diff_delta__from_one(diff, delta_type, nitem)) < 0) + return error; + + /* if delta wasn't created (because of rules), just skip ahead */ + last = diff_delta__last_for_item(diff, nitem); + if (!last) + return git_iterator_advance(&info->nitem, info->new_iter); + + /* iterate into dir looking for an actual untracked file */ + if (diff_scan_inside_untracked_dir(diff, info, &delta_type) < 0) + return -1; + + /* it iteration changed delta type, the update the record */ + if (delta_type == GIT_DELTA_IGNORED) { + last->status = GIT_DELTA_IGNORED; + + /* remove the record if we don't want ignored records */ + if (DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_INCLUDE_IGNORED)) { + git_vector_pop(&diff->deltas); + git__free(last); + } + } + + return 0; + } + + /* try to advance into directory if necessary */ + if (recurse_into_dir) { + error = git_iterator_advance_into(&info->nitem, info->new_iter); + + /* if real error or no error, proceed with iteration */ + if (error != GIT_ENOTFOUND) + return error; + giterr_clear(); + + /* if directory is empty, can't advance into it, so either skip + * it or ignore it + */ + if (contains_oitem) + return git_iterator_advance(&info->nitem, info->new_iter); + delta_type = GIT_DELTA_IGNORED; + } + } + + /* In core git, the next two checks are effectively reversed -- + * i.e. when an file contained in an ignored directory is explicitly + * ignored, it shows up as an ignored file in the diff list, even though + * other untracked files in the same directory are skipped completely. * - * To me, this is odd. If the directory is ignored and the file - * is untracked, we should skip it consistently, regardless of - * whether it happens to match a pattern in the ignore file. + * To me, this seems odd. If the directory is ignored and the file is + * untracked, we should skip it consistently, regardless of whether it + * happens to match a pattern in the ignore file. * - * To match the core git behavior, just reverse the following - * two "else if" cases so that individual file ignores are - * checked before container directory exclusions are used to - * skip the file. + * To match the core git behavior, reverse the following two if checks + * so that individual file ignores are checked before container + * directory exclusions are used to skip the file. */ else if (delta_type == GIT_DELTA_IGNORED && - DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) + DIFF_FLAG_ISNT_SET(diff, GIT_DIFF_RECURSE_IGNORED_DIRS)) + /* item contained in ignored directory, so skip over it */ return git_iterator_advance(&info->nitem, info->new_iter); else if (git_iterator_current_is_ignored(info->new_iter)) @@ -795,15 +877,16 @@ static int handle_unmatched_new_item( else if (info->new_iter->type != GIT_ITERATOR_TYPE_WORKDIR) delta_type = GIT_DELTA_ADDED; + /* Actually create the record for this item if necessary */ if ((error = diff_delta__from_one(diff, delta_type, nitem)) < 0) return error; - /* if we are generating TYPECHANGE records then check for that - * instead of just generating an ADDED/UNTRACKED record + /* If user requested TYPECHANGE records, then check for that instead of + * just generating an ADDED/UNTRACKED record */ if (delta_type != GIT_DELTA_IGNORED && DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES) && - entry_is_prefixed(diff, info->oitem, nitem)) + contains_oitem) { /* this entry was prefixed with a tree - make TYPECHANGE */ git_diff_delta *last = diff_delta__last_for_item(diff, nitem); diff --git a/src/vector.c b/src/vector.c index f4a818ed2..5ba2fab18 100644 --- a/src/vector.c +++ b/src/vector.c @@ -277,15 +277,13 @@ void git_vector_swap(git_vector *a, git_vector *b) int git_vector_resize_to(git_vector *v, size_t new_length) { - if (new_length <= v->length) - return 0; - if (new_length > v->_alloc_size && resize_vector(v, new_length) < 0) return -1; - memset(&v->contents[v->length], 0, - sizeof(void *) * (new_length - v->length)); + if (new_length > v->length) + memset(&v->contents[v->length], 0, + sizeof(void *) * (new_length - v->length)); v->length = new_length; diff --git a/tests-clar/status/status_helpers.c b/tests-clar/status/status_helpers.c index 24546d45c..f073c2491 100644 --- a/tests-clar/status/status_helpers.c +++ b/tests-clar/status/status_helpers.c @@ -40,7 +40,8 @@ int cb_status__single(const char *p, unsigned int s, void *payload) { status_entry_single *data = (status_entry_single *)payload; - GIT_UNUSED(p); + if (data->debug) + fprintf(stderr, "%02d: %s (%04x)\n", data->count, p, s); data->count++; data->status = s; diff --git a/tests-clar/status/status_helpers.h b/tests-clar/status/status_helpers.h index 1aa0263ee..ae1469e79 100644 --- a/tests-clar/status/status_helpers.h +++ b/tests-clar/status/status_helpers.h @@ -24,6 +24,7 @@ extern int cb_status__count(const char *p, unsigned int s, void *payload); typedef struct { int count; unsigned int status; + bool debug; } status_entry_single; /* cb_status__single takes payload of "status_entry_single *" */ diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c index a9b8a12ed..0138b1712 100644 --- a/tests-clar/status/worktree.c +++ b/tests-clar/status/worktree.c @@ -258,9 +258,8 @@ void test_status_worktree__ignores(void) static int cb_status__check_592(const char *p, unsigned int s, void *payload) { - GIT_UNUSED(payload); - - if (s != GIT_STATUS_WT_DELETED || (payload != NULL && strcmp(p, (const char *)payload) != 0)) + if (s != GIT_STATUS_WT_DELETED || + (payload != NULL && strcmp(p, (const char *)payload) != 0)) return -1; return 0; diff --git a/tests-clar/submodule/status.c b/tests-clar/submodule/status.c index 282e82758..fca84af63 100644 --- a/tests-clar/submodule/status.c +++ b/tests-clar/submodule/status.c @@ -383,3 +383,30 @@ void test_submodule_status__iterator(void) cl_git_pass(git_status_foreach_ext(g_repo, &opts, confirm_submodule_status, &exp)); } + +void test_submodule_status__untracked_dirs_containing_ignored_files(void) +{ + git_buf path = GIT_BUF_INIT; + unsigned int status, expected; + git_submodule *sm; + + cl_git_pass(git_buf_joinpath(&path, git_repository_path(g_repo), "modules/sm_unchanged/info/exclude")); + cl_git_append2file(git_buf_cstr(&path), "\n*.ignored\n"); + + cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "sm_unchanged/directory")); + cl_git_pass(git_futils_mkdir(git_buf_cstr(&path), NULL, 0755, 0)); + cl_git_pass(git_buf_joinpath(&path, git_buf_cstr(&path), "i_am.ignored")); + cl_git_mkfile(git_buf_cstr(&path), "ignored this file, please\n"); + + cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged")); + cl_git_pass(git_submodule_status(&status, sm)); + + cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status)); + + expected = GIT_SUBMODULE_STATUS_IN_HEAD | + GIT_SUBMODULE_STATUS_IN_INDEX | + GIT_SUBMODULE_STATUS_IN_CONFIG | + GIT_SUBMODULE_STATUS_IN_WD; + + cl_assert(status == expected); +} From a66c4bc846cb59512c1aa164211f3f912d9bc425 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 29 Apr 2013 02:57:01 -0700 Subject: [PATCH 110/134] More tests for diff untracked directories This includes more tests for various scenarios when diff includes an untracked directory in the workdir with contents either ignored or not. --- tests-clar/diff/diff_helpers.c | 10 +- tests-clar/diff/diff_helpers.h | 7 ++ tests-clar/diff/workdir.c | 187 +++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 1 deletion(-) diff --git a/tests-clar/diff/diff_helpers.c b/tests-clar/diff/diff_helpers.c index 19c005e2e..e7f97c034 100644 --- a/tests-clar/diff/diff_helpers.c +++ b/tests-clar/diff/diff_helpers.c @@ -28,7 +28,15 @@ int diff_file_cb( { diff_expects *e = payload; - GIT_UNUSED(progress); + if (e->debug) + fprintf(stderr, "%c %s (%.3f)\n", + git_diff_status_char(delta->status), + delta->old_file.path, progress); + + if (e->names) + cl_assert_equal_s(e->names[e->files], delta->old_file.path); + if (e->statuses) + cl_assert_equal_i(e->statuses[e->files], (int)delta->status); e->files++; diff --git a/tests-clar/diff/diff_helpers.h b/tests-clar/diff/diff_helpers.h index 674fd8e19..b39a69d1d 100644 --- a/tests-clar/diff/diff_helpers.h +++ b/tests-clar/diff/diff_helpers.h @@ -18,6 +18,13 @@ typedef struct { int line_ctxt; int line_adds; int line_dels; + + /* optional arrays of expected specific values */ + const char **names; + int *statuses; + + int debug; + } diff_expects; typedef struct { diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c index 435bd4f2c..94fd7165d 100644 --- a/tests-clar/diff/workdir.c +++ b/tests-clar/diff/workdir.c @@ -1033,3 +1033,190 @@ void test_diff_workdir__to_tree_issue_1397(void) git_diff_list_free(diff); git_tree_free(a); } + +void test_diff_workdir__untracked_directory_scenarios(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + diff_expects exp; + char *pathspec = NULL; + static const char *files0[] = { + "subdir/deleted_file", + "subdir/modified_file", + "subdir/new_file", + NULL + }; + static const char *files1[] = { + "subdir/deleted_file", + "subdir/directory/", + "subdir/modified_file", + "subdir/new_file", + NULL + }; + static const char *files2[] = { + "subdir/deleted_file", + "subdir/directory/more/notignored", + "subdir/modified_file", + "subdir/new_file", + NULL + }; + + g_repo = cl_git_sandbox_init("status"); + cl_git_mkfile("status/.gitignore", "ignored\n"); + + opts.context_lines = 3; + opts.interhunk_lines = 1; + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + pathspec = "subdir"; + + /* baseline for "subdir" pathspec */ + + memset(&exp, 0, sizeof(exp)); + exp.names = files0; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(3, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* empty directory */ + + cl_git_pass(p_mkdir("status/subdir/directory", 0777)); + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* directory with only ignored files */ + + cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777)); + cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n"); + + cl_git_pass(p_mkdir("status/subdir/directory/another", 0777)); + cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n"); + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* directory with ignored directory (contents irrelevant) */ + + cl_git_pass(p_mkdir("status/subdir/directory/more", 0777)); + cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777)); + cl_git_mkfile("status/subdir/directory/more/ignored/notignored", + "inside ignored dir\n"); + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* quick version avoids directory scan */ + + opts.flags = opts.flags | GIT_DIFF_FAST_UNTRACKED_DIRS; + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* directory with nested non-ignored content */ + + opts.flags = opts.flags & ~GIT_DIFF_FAST_UNTRACKED_DIRS; + + cl_git_mkfile("status/subdir/directory/more/notignored", + "not ignored deep under untracked\n"); + + memset(&exp, 0, sizeof(exp)); + exp.names = files1; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); + + /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */ + + opts.flags = opts.flags & ~GIT_DIFF_INCLUDE_IGNORED; + opts.flags = opts.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS; + + memset(&exp, 0, sizeof(exp)); + exp.names = files2; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); + + cl_assert_equal_i(4, exp.files); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); + cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); + cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); + cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); + + git_diff_list_free(diff); +} From 61c00541ac3c92eb3a82c4a1f67e47510ca1318b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 29 Apr 2013 06:21:56 -0700 Subject: [PATCH 111/134] Update comment for clarity --- include/git2/diff.h | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/include/git2/diff.h b/include/git2/diff.h index cc16d01b6..0ef47c018 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -88,47 +88,59 @@ typedef enum { GIT_DIFF_INCLUDE_UNTRACKED = (1 << 8), /** Include unmodified files in the diff list */ GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 9), + /** Even with GIT_DIFF_INCLUDE_UNTRACKED, an entire untracked directory * will be marked with only a single entry in the diff list; this flag * adds all files under the directory as UNTRACKED entries, too. */ GIT_DIFF_RECURSE_UNTRACKED_DIRS = (1 << 10), + /** If the pathspec is set in the diff options, this flags means to * apply it as an exact match instead of as an fnmatch pattern. */ GIT_DIFF_DISABLE_PATHSPEC_MATCH = (1 << 11), + /** Use case insensitive filename comparisons */ GIT_DIFF_DELTAS_ARE_ICASE = (1 << 12), + /** When generating patch text, include the content of untracked files */ GIT_DIFF_INCLUDE_UNTRACKED_CONTENT = (1 << 13), + /** Disable updating of the `binary` flag in delta records. This is * useful when iterating over a diff if you don't need hunk and data * callbacks and want to avoid having to load file completely. */ GIT_DIFF_SKIP_BINARY_CHECK = (1 << 14), + /** Normally, a type change between files will be converted into a * DELETED record for the old and an ADDED record for the new; this * options enabled the generation of TYPECHANGE delta records. */ GIT_DIFF_INCLUDE_TYPECHANGE = (1 << 15), + /** Even with GIT_DIFF_INCLUDE_TYPECHANGE, blob->tree changes still * generally show as a DELETED blob. This flag tries to correctly * label blob->tree transitions as TYPECHANGE records with new_file's * mode set to tree. Note: the tree SHA will not be available. */ GIT_DIFF_INCLUDE_TYPECHANGE_TREES = (1 << 16), + /** Ignore file mode changes */ GIT_DIFF_IGNORE_FILEMODE = (1 << 17), + /** Even with GIT_DIFF_INCLUDE_IGNORED, an entire ignored directory * will be marked with only a single entry in the diff list; this flag * adds all files under the directory as IGNORED entries, too. */ GIT_DIFF_RECURSE_IGNORED_DIRS = (1 << 18), - /** For an untracked directory, diff can immediately label it UNTRACKED, - * but this differs from core Git which scans underneath for untracked - * or ignored files and marks the directory ignored unless it contains - * untracked files under it. That search can be slow. This flag makes - * diff skip ahead and immediately report the directory as untracked. + + /** Core Git scans inside untracked directories, labeling them IGNORED + * if they are empty or only contain ignored files; a directory is + * consider UNTRACKED only if it has an actual untracked file in it. + * This scan is extra work for a case you often don't care about. This + * flag makes libgit2 immediately label an untracked directory as + * UNTRACKED without looking insde it (which differs from core Git). + * Of course, ignore rules are still checked for the directory itself. */ GIT_DIFF_FAST_UNTRACKED_DIRS = (1 << 19), } git_diff_option_t; From 5fa7e469848bef4eab19cc069df9aa3b0134c9f7 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 30 Apr 2013 04:13:39 -0700 Subject: [PATCH 112/134] Fix some formatting inconsistency --- src/diff.c | 6 ++---- src/diff_output.c | 50 +++++++++++++++++++---------------------------- 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/diff.c b/src/diff.c index cea3fdb22..a154e67e8 100644 --- a/src/diff.c +++ b/src/diff.c @@ -327,8 +327,7 @@ static git_diff_list *diff_list_alloc( /* Use case-insensitive compare if either iterator has * the ignore_case bit set */ if (!git_iterator_ignore_case(old_iter) && - !git_iterator_ignore_case(new_iter)) - { + !git_iterator_ignore_case(new_iter)) { diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE; diff->strcomp = git__strcmp; @@ -777,8 +776,7 @@ static int handle_unmatched_new_item( /* if not already inside an ignored dir, check if this is ignored */ if (delta_type != GIT_DELTA_IGNORED && - git_iterator_current_is_ignored(info->new_iter)) - { + git_iterator_current_is_ignored(info->new_iter)) { delta_type = GIT_DELTA_IGNORED; git_buf_sets(&info->ignore_prefix, nitem->path); } diff --git a/src/diff_output.c b/src/diff_output.c index 4ce01bc62..64ff6b5be 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -101,8 +101,8 @@ static bool diff_delta_is_binary_forced( /* make sure files are conceivably mmap-able */ if ((git_off_t)((size_t)delta->old_file.size) != delta->old_file.size || - (git_off_t)((size_t)delta->new_file.size) != delta->new_file.size) - { + (git_off_t)((size_t)delta->new_file.size) != delta->new_file.size) { + delta->old_file.flags |= GIT_DIFF_FLAG_BINARY; delta->new_file.flags |= GIT_DIFF_FLAG_BINARY; delta->flags |= GIT_DIFF_FLAG_BINARY; @@ -232,8 +232,7 @@ static int get_blob_content( if (git_oid_iszero(&file->oid)) return 0; - if (file->mode == GIT_FILEMODE_COMMIT) - { + if (file->mode == GIT_FILEMODE_COMMIT) { char oidstr[GIT_OID_HEXSZ+1]; git_buf content = GIT_BUF_INIT; @@ -299,8 +298,8 @@ static int get_workdir_sm_content( char oidstr[GIT_OID_HEXSZ+1]; if ((error = git_submodule_lookup(&sm, ctxt->repo, file->path)) < 0 || - (error = git_submodule_status(&sm_status, sm)) < 0) - { + (error = git_submodule_status(&sm_status, sm)) < 0) { + /* GIT_EEXISTS means a "submodule" that has not been git added */ if (error == GIT_EEXISTS) error = 0; @@ -312,8 +311,8 @@ static int get_workdir_sm_content( const git_oid* sm_head; if ((sm_head = git_submodule_wd_id(sm)) != NULL || - (sm_head = git_submodule_head_id(sm)) != NULL) - { + (sm_head = git_submodule_head_id(sm)) != NULL) { + git_oid_cpy(&file->oid, sm_head); file->flags |= GIT_DIFF_FLAG_VALID_OID; } @@ -660,8 +659,8 @@ static int diff_patch_load( */ if (check_if_unmodified && delta->old_file.mode == delta->new_file.mode && - !git_oid__cmp(&delta->old_file.oid, &delta->new_file.oid)) - { + !git_oid__cmp(&delta->old_file.oid, &delta->new_file.oid)) { + delta->status = GIT_DELTA_UNMODIFIED; if ((ctxt->opts->flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0) @@ -1049,6 +1048,12 @@ char git_diff_status_char(git_delta_t status) return code; } +static int callback_error(void) +{ + giterr_clear(); + return GIT_EUSER; +} + static int print_compact( const git_diff_delta *delta, float progress, void *data) { @@ -1083,10 +1088,7 @@ static int print_compact( if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); return 0; } @@ -1200,10 +1202,7 @@ static int print_patch_file( if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) return 0; @@ -1217,10 +1216,7 @@ static int print_patch_file( if (pi->print_cb(delta, NULL, GIT_DIFF_LINE_BINARY, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); return 0; } @@ -1243,10 +1239,7 @@ static int print_patch_hunk( if (pi->print_cb(d, r, GIT_DIFF_LINE_HUNK_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); return 0; } @@ -1278,10 +1271,7 @@ static int print_patch_line( if (pi->print_cb(delta, range, line_origin, git_buf_cstr(pi->buf), git_buf_len(pi->buf), pi->payload)) - { - giterr_clear(); - return GIT_EUSER; - } + return callback_error(); return 0; } From bade51948c08c36ac0bea63cf62ee1a9dd952501 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 30 Apr 2013 21:02:13 +0200 Subject: [PATCH 113/134] lol namespaces --- include/git2/repository.h | 22 ++++++++++++++++++++++ src/refdb_fs.c | 11 +++++++++-- src/repository.c | 18 ++++++++++++++++++ src/repository.h | 1 + 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index 08024cd89..cd238e17c 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -626,6 +626,28 @@ typedef enum { */ GIT_EXTERN(int) git_repository_state(git_repository *repo); +/** + * Sets the active namespace for this Git Repository + * + * This namespace affects all reference operations for the repo. + * See `man gitnamespaces` + * + * @param repo The repo + * @param nmspace The namespace. This should not include the refs + * folder, e.g. to namespace all references under `refs/namespaces/foo/`, + * use `foo` as the namespace. + * @return 0 on success, -1 on error + */ +GIT_EXTERN(int) git_repository_set_namespace(git_repository *repo, const char *nmspace); + +/** + * Get the currently active namespace for this repository + * + * @param repo The repo + * @return the active namespace, or NULL if there isn't one + */ +GIT_EXTERN(const char *) git_repository_get_namespace(git_repository *repo); + /** @} */ GIT_END_DECL #endif diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 2f2e67104..5228cb811 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -41,7 +41,7 @@ typedef struct refdb_fs_backend { git_refdb_backend parent; git_repository *repo; - const char *path; + char *path; git_refcache refcache; } refdb_fs_backend; @@ -993,6 +993,7 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend) backend = (refdb_fs_backend *)_backend; refcache_free(&backend->refcache); + git__free(backend->path); git__free(backend); } @@ -1000,13 +1001,19 @@ int git_refdb_backend_fs( git_refdb_backend **backend_out, git_repository *repository) { + git_buf path = GIT_BUF_INIT; refdb_fs_backend *backend; backend = git__calloc(1, sizeof(refdb_fs_backend)); GITERR_CHECK_ALLOC(backend); backend->repo = repository; - backend->path = repository->path_repository; + + git_buf_puts(&path, repository->path_repository); + if (repository->namespace != NULL) + git_buf_printf(&path, "refs/%s/", repository->namespace); + + backend->path = git_buf_detach(&path); backend->parent.exists = &refdb_fs_backend__exists; backend->parent.lookup = &refdb_fs_backend__lookup; diff --git a/src/repository.c b/src/repository.c index 2161aa697..e6eaf753c 100644 --- a/src/repository.c +++ b/src/repository.c @@ -111,6 +111,7 @@ void git_repository_free(git_repository *repo) git__free(repo->path_repository); git__free(repo->workdir); + git__free(repo->namespace); git__free(repo); } @@ -764,6 +765,23 @@ void git_repository_set_index(git_repository *repo, git_index *index) set_index(repo, index); } +int git_repository_set_namespace(git_repository *repo, const char *namespace) +{ + git__free(repo->namespace); + + if (namespace == NULL) { + repo->namespace = NULL; + return 0; + } + + return (repo->namespace = git__strdup(namespace)) ? 0 : -1; +} + +const char *git_repository_get_namespace(git_repository *repo) +{ + return repo->namespace; +} + static int check_repositoryformatversion(git_config *config) { int version; diff --git a/src/repository.h b/src/repository.h index f7f9ecb1f..bd5f63dac 100644 --- a/src/repository.h +++ b/src/repository.h @@ -111,6 +111,7 @@ struct git_repository { char *path_repository; char *workdir; + char *namespace; unsigned is_bare:1; unsigned int lru_counter; From bec65a5e994bc4701216c9ca2c7dae83770b3edc Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 1 Apr 2013 22:16:21 -0500 Subject: [PATCH 114/134] merge! --- docs/merge-df_conflicts.txt | 41 + include/git2/index.h | 6 +- include/git2/merge.h | 64 +- src/index.c | 19 +- src/merge.c | 854 +++++++++++++++++- src/merge.h | 115 ++- src/merge_file.c | 175 ++++ src/merge_file.h | 71 ++ tests-clar/merge/merge_helpers.c | 224 +++++ tests-clar/merge/merge_helpers.h | 62 ++ tests-clar/merge/trees/automerge.c | 217 +++++ tests-clar/merge/trees/modeconflict.c | 59 ++ tests-clar/merge/trees/treediff.c | 279 ++++++ tests-clar/merge/trees/trivial.c | 396 ++++++++ tests-clar/merge/{ => workdir}/setup.c | 21 +- .../merge-resolve/.gitted/COMMIT_EDITMSG | 1 + .../resources/merge-resolve/.gitted/HEAD | 1 + .../resources/merge-resolve/.gitted/ORIG_HEAD | 1 + .../resources/merge-resolve/.gitted/config | 6 + .../merge-resolve/.gitted/description | 1 + .../resources/merge-resolve/.gitted/index | Bin 0 -> 624 bytes .../resources/merge-resolve/.gitted/logs/HEAD | 236 +++++ .../.gitted/logs/refs/heads/branch | 2 + .../.gitted/logs/refs/heads/df_ancestor | 5 + .../.gitted/logs/refs/heads/df_side1 | 14 + .../.gitted/logs/refs/heads/df_side2 | 9 + .../.gitted/logs/refs/heads/ff_branch | 5 + .../.gitted/logs/refs/heads/master | 5 + .../.gitted/logs/refs/heads/octo1 | 2 + .../.gitted/logs/refs/heads/octo2 | 2 + .../.gitted/logs/refs/heads/octo3 | 2 + .../.gitted/logs/refs/heads/octo4 | 2 + .../.gitted/logs/refs/heads/octo5 | 2 + .../.gitted/logs/refs/heads/octo6 | 3 + .../.gitted/logs/refs/heads/renames1 | 2 + .../.gitted/logs/refs/heads/renames2 | 3 + .../.gitted/logs/refs/heads/trivial-10 | 3 + .../.gitted/logs/refs/heads/trivial-10-branch | 2 + .../.gitted/logs/refs/heads/trivial-11 | 3 + .../.gitted/logs/refs/heads/trivial-11-branch | 2 + .../.gitted/logs/refs/heads/trivial-13 | 3 + .../.gitted/logs/refs/heads/trivial-13-branch | 2 + .../.gitted/logs/refs/heads/trivial-14 | 3 + .../.gitted/logs/refs/heads/trivial-14-branch | 2 + .../.gitted/logs/refs/heads/trivial-2alt | 2 + .../logs/refs/heads/trivial-2alt-branch | 2 + .../.gitted/logs/refs/heads/trivial-3alt | 3 + .../logs/refs/heads/trivial-3alt-branch | 1 + .../.gitted/logs/refs/heads/trivial-4 | 2 + .../.gitted/logs/refs/heads/trivial-4-branch | 2 + .../.gitted/logs/refs/heads/trivial-5alt-1 | 2 + .../logs/refs/heads/trivial-5alt-1-branch | 2 + .../.gitted/logs/refs/heads/trivial-5alt-2 | 3 + .../logs/refs/heads/trivial-5alt-2-branch | 2 + .../.gitted/logs/refs/heads/trivial-6 | 3 + .../.gitted/logs/refs/heads/trivial-6-branch | 2 + .../.gitted/logs/refs/heads/trivial-7 | 3 + .../.gitted/logs/refs/heads/trivial-7-branch | 5 + .../.gitted/logs/refs/heads/trivial-8 | 3 + .../.gitted/logs/refs/heads/trivial-8-branch | 2 + .../.gitted/logs/refs/heads/trivial-9 | 3 + .../.gitted/logs/refs/heads/trivial-9-branch | 2 + .../.gitted/logs/refs/heads/unrelated | 1 + .../00/5b6fcc8fec71d2550bef8462d169b3c26aa14b | Bin 0 -> 168 bytes .../00/9b9cab6fdac02915a88ecd078b7a792ed802d8 | Bin 0 -> 164 bytes .../00/c7d33f1ffa79d19c2272b370fcaeaadba49c08 | Bin 0 -> 147 bytes .../01/f149e1b8f84bd8896aaff6d6b22af88459ded0 | Bin 0 -> 166 bytes .../02/04a84f822acbf6386b36d33f1f6bc68bbbf858 | Bin 0 -> 168 bytes .../02/251f990ca8e92e7ae61d3426163fa821c64001 | Bin 0 -> 264 bytes .../03/21415405cb906c46869919af56d51dbbe5e85c | Bin 0 -> 271 bytes .../03/2ebc5ab85d9553bb187d3cd40875ff23a63ed0 | Bin 0 -> 29 bytes .../03/b87706555accbf874ccd410dbda01e8e70a67f | Bin 0 -> 353 bytes .../03/dad1005e5d06d418f50b12e0bcd48ff2306a03 | Bin 0 -> 264 bytes .../05/1ffd7901a442faf56b226161649074f15c7c47 | 1 + .../05/8541fc37114bfc1dddf6bd6bffc7fae5c2e6fe | Bin 0 -> 63 bytes .../05/f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c | Bin 0 -> 170 bytes .../07/a759da919f737221791d542f176ab49c88837f | Bin 0 -> 165 bytes .../07/c514b04698e068892b31c8d352b85813b99c6e | Bin 0 -> 32 bytes .../09/055301463b7f2f8ee5d368f8ed5c0a40ad8515 | Bin 0 -> 41 bytes .../09/17bb159596aea4d295f4857da77e8f96b3c7dc | Bin 0 -> 36 bytes .../09/2ce8682d7f3a2a3a769a6daca58950168ba5c4 | Bin 0 -> 163 bytes .../09/3bebf072dd4bbba88833667d6ffe454df199e1 | Bin 0 -> 266 bytes .../09/768bed22680cdb0859683fa9677ccc8d5a25c1 | Bin 0 -> 275 bytes .../0a/75d9aac1dc84fb5aa51f7325c0ab53242ddef7 | Bin 0 -> 275 bytes .../0c/fd6c54ef6532d862408f562309dc9c74a401e8 | Bin 0 -> 28 bytes .../0d/52e3a556e189ba0948ae56780918011c1b167d | Bin 0 -> 235 bytes .../0d/872f8e871a30208305978ecbf9e66d864f1638 | Bin 0 -> 89 bytes .../0e/c5f433959cd46177f745903353efb5be08d151 | Bin 0 -> 165 bytes .../11/deab00b2d3a6f5a3073988ac050c2d7b6655e2 | Bin 0 -> 34 bytes .../11/f4f3c08b737f5fd896cbefa1425ee63b21b2fa | 1 + .../13/d1be4ea52a6ced1d7a1d832f0ee3c399348e5e | Bin 0 -> 168 bytes .../14/39088f509b79b1535b64193137d3ce4b240734 | Bin 0 -> 58 bytes .../15/8dc7bedb202f5b26502bf3574faa7f4238d56c | 2 + .../16/f825815cfd20a07a75c71554e82d8eede0b061 | 1 + .../17/8940b450f238a56c0d75b7955cb57b38191982 | Bin 0 -> 65 bytes .../18/3310e30fb1499af8c619108ffea4d300b5e778 | Bin 0 -> 170 bytes .../18/cb316b1cefa0f8a6946f0e201a8e1a6f845ab9 | Bin 0 -> 68 bytes .../19/b7ac485269b672a101060894de3ba9c2a24dd1 | Bin 0 -> 53 bytes .../1c/ff9ec6a47a537380dedfdd17c9e76d74259a2b | Bin 0 -> 33 bytes .../1e/4ff029aee68d0d69ef9eb6efa6cbf1ec732f99 | Bin 0 -> 29 bytes .../1f/81433e3161efbf250576c58fede7f6b836f3d3 | Bin 0 -> 262 bytes .../20/91d94c8bd3eb0835dc5220de5e8bb310fa1513 | Bin 0 -> 271 bytes .../21/671e290278286fb2ce4c63d01699b67adce331 | Bin 0 -> 79 bytes .../22/7792b52aaa0b238bea00ec7e509b02623f168c | Bin 0 -> 102 bytes .../23/3c0919c998ed110a4b6ff36f353aec8b713487 | Bin 0 -> 43 bytes .../23/92a2dacc9efb562b8635d6579fb458751c7c5b | Bin 0 -> 142 bytes .../24/1a1005cd9b980732741b74385b891142bcba28 | Bin 0 -> 67 bytes .../24/2591eb280ee9eeb2ce63524b9a8b9bc4cb515d | Bin 0 -> 30 bytes .../24/90b9f1a079420870027deefb49f51d6656cf74 | Bin 0 -> 268 bytes .../25/9d08ca43af9200e9ea9a098e44a5a350ebd9b3 | Bin 0 -> 381 bytes .../25/c40b7660c08c8fb581f770312f41b9b03119d1 | Bin 0 -> 31 bytes .../26/153a3ff3649b6c2bb652d3f06878c6e0a172f9 | Bin 0 -> 48 bytes .../27/133da702ba3c60af2a01e96c2555ff4045d692 | Bin 0 -> 32 bytes .../2b/0de5dc27505dcdd83a75c8bf1fcd9462cd7add | Bin 0 -> 147 bytes .../2b/5f1f181ee3b58ea751f5dd5d8f9b445520a136 | Bin 0 -> 53 bytes .../2b/d0a343aeef7a2cf0d158478966a6e587ff3863 | Bin 0 -> 56 bytes .../2d/a538570bc1e5b2c3e855bf702f35248ad0735f | 2 + .../2f/2e37b7ebbae467978610896ca3aafcdad2ee67 | Bin 0 -> 52 bytes .../2f/4024ce528d36d8670c289cce5a7963e625bb0c | Bin 0 -> 179 bytes .../2f/56120107d680129a5d9791b521cb1e73a2ed31 | 3 + .../2f/598248eeccfc27e5ca44d9d96383f6dfea7b16 | 1 + .../31/68dca1a561889b045a6441909f4c56145e666d | 2 + .../31/d5472536041a83d986829240bbbdc897c6f8a6 | Bin 0 -> 41 bytes .../32/21dd512b7e2dc4b5bd03046df6c81b2ab2070b | Bin 0 -> 47 bytes .../33/46d64325b39e5323733492cd55f808994a2475 | Bin 0 -> 33 bytes .../33/d500f588fbbe65901d82b4e6b008e549064be0 | 2 + .../34/bfafff88eaf118402b44e6f3e2dbbf1a582b05 | 1 + .../35/0c6eb3010efc403a6bed682332635314e9ed58 | Bin 0 -> 92 bytes .../35/411bfb77cd2cc431f3a03a2b4976ed94b5d241 | Bin 0 -> 31 bytes .../35/4704d3613ad4228e4786fc76656b11e98236c4 | Bin 0 -> 41 bytes .../35/632e43612c06a3ea924bfbacd48333da874c29 | 1 + .../35/75826c96a975031d2c14368529cc5c4353a8fd | Bin 0 -> 163 bytes .../36/219b49367146cb2e6a1555b5a9ebd4d0328495 | Bin 0 -> 68 bytes .../36/4bbe4ce80c7bd31e6307dce77d46e3e1759fb3 | Bin 0 -> 35 bytes .../37/48859b001c6e627e712a07951aee40afd19b41 | Bin 0 -> 41 bytes .../38/5c8a0f26ddf79e9041e15e17dc352ed2c4cced | 2 + .../3b/47b031b3e55ae11e14a05260b1c3ffd6838d55 | Bin 0 -> 161 bytes .../3b/bf0bf59b20df5d5fc58b9fc1dc07be637c301f | Bin 0 -> 269 bytes .../3e/f4d30382ca33fdeba9fda895a99e0891ba37aa | Bin 0 -> 36 bytes .../3e/f9bfe82f9635518ae89152322f3b46fd4ba25b | Bin 0 -> 172 bytes .../40/2784a46a4a3982294231594cbeb431f506d22c | Bin 0 -> 83 bytes .../41/2b32fb66137366147f1801ecc962452757d48a | 2 + .../43/aafd43bea779ec74317dc361f45ae3f532a505 | Bin 0 -> 37 bytes .../43/c338656342227a3a3cd3aa85cbf784061f5425 | Bin 0 -> 266 bytes .../45/299c1ca5e07bba1fd90843056fb559f96b1f5a | Bin 0 -> 58 bytes .../46/6daf8552b891e5c22bc58c9d7fc1a2eb8f0289 | Bin 0 -> 382 bytes .../47/6dbb3e207313d1d8aaa120c6ad204bf1295e53 | Bin 0 -> 522 bytes .../47/8172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 | Bin 0 -> 165 bytes .../49/130a28ef567af9a6a6104c38773fedfa5f9742 | Bin 0 -> 37 bytes .../49/9df817155e4bdd3c6ee192a72c52f481818230 | Bin 0 -> 35 bytes .../4a/9550ebcc97ce22b22f45af7b829bb030d003f5 | Bin 0 -> 53 bytes .../4b/253da36a0ae8bfce63aeabd8c5b58429925594 | 2 + .../4b/48deed3a433909bfd6b6ab3d4b91348b6af464 | Bin 0 -> 24 bytes .../4b/825dc642cb6eb9a060e54bf8d69288fbee4904 | Bin 0 -> 15 bytes .../4c/9fac0707f8d4195037ae5a681aa48626491541 | Bin 0 -> 167 bytes .../4c/a408a8c88655f7586a1b580be6fad138121e98 | Bin 0 -> 159 bytes .../4e/0d9401aee78eb345a8685a859d37c8c3c0bbed | Bin 0 -> 262 bytes .../4e/886e602529caa9ab11d71f86634bd1b6e0de10 | Bin 0 -> 56 bytes .../4e/b04c9e79e88f6640d01ff5b25ca2a60764f216 | Bin 0 -> 34 bytes .../4f/e93c0ec83eb6305cbace3dace88ecee1b63cb6 | Bin 0 -> 161 bytes .../50/12fd565b1393bdfda1805d4ec38ce6619e1fd1 | Bin 0 -> 29 bytes .../50/4f75ac95a71ef98051817618576a68505b92f9 | Bin 0 -> 93 bytes .../50/84fc2a88b6bdba8db93bd3953a8f4fdb470238 | Bin 0 -> 53 bytes .../50/ce7d7d01217679e26c55939eef119e0c93e272 | Bin 0 -> 159 bytes .../51/95a1b480f66691b667f10a9e41e70115a78351 | Bin 0 -> 170 bytes .../52/d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 | 3 + .../53/825f41ac8d640612f9423a2f03a69f3d96809a | Bin 0 -> 164 bytes .../54/269b3f6ec3d7d4ede24dd350dd5d605495c3ae | 2 + .../54/59c89aa0026d543ce8343bd89871bce543f9c2 | 3 + .../54/7607c690372fe81fab8e3bb44c530e129118fd | Bin 0 -> 58 bytes .../55/b4e4687e7a0d9ca367016ed930f385d4022e6f | 1 + .../56/6ab53c220a2eafc1212af1a024513230280ab9 | 3 + .../56/a638b76b75e068590ac999c2f8621e7f3e264c | 1 + .../57/079a46233ae2b6df62e9ade71c4948512abefb | Bin 0 -> 168 bytes .../58/43febcb23480df0b5edb22a21c59c772bb8e29 | Bin 0 -> 71 bytes .../58/e853f66699fd02629fd50bde08082bc005933a | Bin 0 -> 160 bytes .../59/6803b523203a4851c824c07366906f8353f4ad | Bin 0 -> 163 bytes .../5c/2411f8075f48a6b2fdb85ebc0d371747c4df15 | Bin 0 -> 37 bytes .../5c/341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d | Bin 0 -> 37 bytes .../5c/3b68a71fc4fa5d362fd3875e53137c6a5ab7a5 | Bin 0 -> 40 bytes .../5d/c1018e90b19654bee986b7a0c268804d39659d | Bin 0 -> 168 bytes .../5d/dd0fe66f990dc0e5cf9fec6d9b465240e9537f | Bin 0 -> 43 bytes .../5e/b7bb6a146eb3c7fd3990b240a2308eceb1cf8d | Bin 0 -> 268 bytes .../5f/bfbdc04b4eca46f54f4853a3c5a1dce28f5165 | Bin 0 -> 283 bytes .../60/91fc2c036a382a69489e3f518ee5aae9a4e567 | Bin 0 -> 258 bytes .../61/340eeed7340fa6a8792def9a5938bb5d4434bb | Bin 0 -> 92 bytes .../61/78885b38fe96e825ac0f492c0a941f288b37f6 | Bin 0 -> 289 bytes .../62/12c31dab5e482247d7977e4f0dd3601decf13b | Bin 0 -> 45 bytes .../62/269111c3b02a9355badcb9da8678b1bf41787b | Bin 0 -> 269 bytes .../62/c4f6533c9a3894191fdcb96a3be935ade63f1a | Bin 0 -> 53 bytes .../63/247125386de9ec90a27ad36169307bf8a11a38 | 1 + .../67/18a45909532d1fcf5600d0877f7fe7e78f0b86 | 1 + .../68/c6c84b091926c7d90aa6a79b2bc3bb6adccd8e | Bin 0 -> 55 bytes .../69/f570c57b24ea7c086e94c5e574964798321435 | Bin 0 -> 266 bytes .../6a/e1a3967031a42cf955d9d5c2395211ac82f6cf | Bin 0 -> 272 bytes .../6b/7e37be8ce0b897093f2878a9dcd8f396beda2c | Bin 0 -> 53 bytes .../6c/06dcd163587c2cc18be44857e0b71116382aeb | Bin 0 -> 30 bytes .../6f/32739c3724d1d5f855299309f388606f407468 | Bin 0 -> 630 bytes .../6f/a33014764bf1120a454eb8437ae098238e409b | Bin 0 -> 168 bytes .../6f/be9fb85c86d7d1435f728da418bdff52c640a9 | Bin 0 -> 83 bytes .../71/17467b18605a660ebe5586df69e2311ed5609f | Bin 0 -> 265 bytes .../71/2ebba6669ea847d9829e4f1059d6c830c8b531 | Bin 0 -> 152 bytes .../71/add2d7b93d55bf3600f8a1582beceebbd050c8 | Bin 0 -> 264 bytes .../74/df13f0793afdaa972150bba976f7de8284914e | Bin 0 -> 26 bytes .../75/a811bf6bc57694adb3fe604786f3a4efd1cd1b | 2 + .../76/63fce0130db092936b137cabd693ec234eb060 | Bin 0 -> 49 bytes .../76/ab0e2868197ec158ddd6c78d8a0d2fd73d38f9 | Bin 0 -> 37 bytes .../7a/a3edf2bcfee22398e6b55295aa56366b7aaf76 | Bin 0 -> 271 bytes .../7c/2c5228c9e90170d4a35e6558e47163daf092e5 | Bin 0 -> 172 bytes .../7c/b63eed597130ba4abb87b3e544b85021905520 | 3 + .../7e/2d058d5fedf8329db44db4fac610d6b1a89159 | Bin 0 -> 165 bytes .../7f/7a2da58126226986d71c6ddfab4afba693280d | Bin 0 -> 199 bytes .../80/a8fbb3abb1ba423d554e9630b8fc2e5698f86b | Bin 0 -> 168 bytes .../81/87117062b750eed4f93fd7e899f17b52ce554d | Bin 0 -> 170 bytes .../83/07d93a155903a5c49576583f0ce1f6ff897c0e | Bin 0 -> 30 bytes .../83/824a8c6658768e2013905219cc8c64cc3d9a2e | Bin 0 -> 382 bytes .../84/9619b03ae540acee4d1edec96b86993da6b497 | 3 + .../84/de84f8f3a6d63e636ee9ad81f4b80512fa9bbe | Bin 0 -> 41 bytes .../86/088dae8bade454995b21a1c88107b0e1accdab | Bin 0 -> 47 bytes .../87/b4926260d77a3b851e71ecce06839bd650b231 | Bin 0 -> 43 bytes .../88/e185910a15cd13bdf44854ad037f4842b03b29 | Bin 0 -> 177 bytes .../8a/ad9d0ea334951da47b621a475b39cc6ed759bf | Bin 0 -> 51 bytes .../8a/ae714f7d939309d7f132b30646d96743134a9f | 1 + .../8b/095d8fd01594f4d14454d073e3ac57b9ce485f | Bin 0 -> 201 bytes .../8b/5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a | 1 + .../8c/749d9968d4b10dcfb06c9f97d0e5d92d337071 | 2 + .../8f/4433f8593ddd65b7dd43dd4564d841f4d9c8aa | Bin 0 -> 164 bytes .../90/a336c7dacbe295159413559b0043b8bdc60d57 | Bin 0 -> 271 bytes .../91/2b2d7819cf9c1029e414883857ed61d597a1a5 | Bin 0 -> 295 bytes .../91/8bb3e09090a9995d48af9a2a6296d7e6088d1c | Bin 0 -> 38 bytes .../92/7d4943cdbdc9a667db8e62cfd0a41870235c51 | Bin 0 -> 535 bytes .../93/77fccdb210540b8c0520cc6e80eb632c20bd25 | Bin 0 -> 53 bytes .../94/4f5dd1a867cab4c2bbcb896493435cae1dcc1a | 2 + .../94/8ba6e701c1edab0c2d394fb7c5538334129793 | Bin 0 -> 71 bytes .../95/646149ab6b6ba6edc83cff678582538b457b2b | 3 + .../95/9de65e568274120fdf9e3af9f77b1550122149 | Bin 0 -> 40 bytes .../96/8ca794a4597f7f6abbb2b8d940b4078a0f3fd4 | Bin 0 -> 53 bytes .../97/7c696519c5a3004c5f1d15d60c89dbeb8f235f | Bin 0 -> 160 bytes .../98/ba4205fcf31f5dd93c916d35fe3f3b3d0e6714 | 1 + .../98/d52d07c0b0bbf2b46548f6aa521295c2cb55db | 3 + .../99/b4f7e4f24470fa06b980bc21f1095c2a9425c0 | Bin 0 -> 164 bytes .../9a/301fbe6fada7dcb74fcd7c20269b5c743459a7 | Bin 0 -> 163 bytes .../9a/f731fa116d1eb9a6c0109562472cfee6f5a979 | Bin 0 -> 48 bytes .../9c/0b6c34ef379a42d858f03fef38630f476b9102 | Bin 0 -> 38 bytes .../9e/7f4359c469f309b6057febf4c6e80742cbed5b | Bin 0 -> 539 bytes .../9e/fe7723802d4305142eee177e018fee1572c4f4 | Bin 0 -> 36 bytes .../9f/74397a3397b3585faf09e9926b110d7f654254 | Bin 0 -> 621 bytes .../a0/31a28ae70e33a641ce4b8a8f6317f1ab79dee4 | Bin 0 -> 37 bytes .../a3/9a620dae5bc8b4e771cd4d251b7d080401a21e | Bin 0 -> 29 bytes .../a3/fabece9eb8748da810e1e08266fef9b7136ad4 | Bin 0 -> 164 bytes .../a4/1b1bb6d0be3c22fb654234c33b428e15c8cc27 | Bin 0 -> 92 bytes .../a4/3150a738849c59376cf30bb2a68348a83c8f48 | Bin 0 -> 162 bytes .../a5/563304ddf6caba25cb50323a2ea6f7dbfcadca | Bin 0 -> 48 bytes .../a7/08b253bd507417ec42d1467a7fd2d7519c4956 | Bin 0 -> 40 bytes .../a7/65fb87eb2f7a1920b73b2d5a057f8f8476a42b | Bin 0 -> 170 bytes .../a7/7a56a49f8f3ae242e02717f18ebbc60c5cc543 | Bin 0 -> 65 bytes .../a7/dbfcbfc1a60709cb80b5ca24539008456531d0 | 1 + .../a8/02e06f1782a9645b9851bc7202cee74a8a4972 | Bin 0 -> 172 bytes .../a8/87dd39ad3edd610fc9083dcb61e40ab50673d1 | 1 + .../a9/0bc3fb6f15181972a2959a921429efbd81a473 | 2 + .../ab/40af3cb8a3ed2e2843e96d9aa7871336b94573 | Bin 0 -> 161 bytes .../ab/6c44a2e84492ad4b41bb6bac87353e9d02ac8b | Bin 0 -> 33 bytes .../ab/929391ac42572f92110f3deeb4f0844a951e22 | Bin 0 -> 40 bytes .../ac/4045f965119e6998f4340ed0f411decfb3ec05 | Bin 0 -> 29 bytes .../ad/a14492498136771f69dd451866cabcb0e9ef9a | Bin 0 -> 39 bytes .../ad/a55a45d14527dc3dfc714ea1c65d2e1e6fbe87 | 1 + .../b2/d399ae15224e1d58066e3c8df70ce37de7a656 | 2 + .../b4/2712cfe99a1a500b2a51fe984e0b8a7702ba11 | 5 + .../b6/9fe837e4cecfd4c9a40cdca7c138468687df07 | 2 + .../b6/f610aef53bd343e6c96227de874c66f00ee8e8 | Bin 0 -> 162 bytes .../b7/a2576f9fc20024ac9ef17cb134acbd1ac73127 | Bin 0 -> 320 bytes .../b8/a3a806d3950e8c0a03a34f234a92eff0e2c68d | Bin 0 -> 286 bytes .../ba/cac9b3493509aa15e1730e1545fc0919d1dae0 | Bin 0 -> 29 bytes .../bc/744705e1d8a019993cf88f62bc4020f1b80919 | 2 + .../bc/95c75d59386147d1e79a87c33068d8dbfd71f2 | Bin 0 -> 348 bytes .../bd/593285fc7fe4ca18ccdbabf027f5d689101452 | Bin 0 -> 159 bytes .../bd/867fbae2faa80b920b002b80b1c91bcade7784 | Bin 0 -> 48 bytes .../bd/9cb4cd0a770cb9adcb5fce212142ef40ea1c35 | Bin 0 -> 51 bytes .../be/f6e37b3ee632ba74159168836f382fed21d77d | 2 + .../c0/6a9be584ac49aa02c5551312d9e2982c91df10 | Bin 0 -> 348 bytes .../c1/b17981db0840109a820dae8674ee29684134ff | Bin 0 -> 348 bytes .../c1/b6a51bbb87c2f82b161412c3d20b59fc69b090 | Bin 0 -> 47 bytes .../c3/5dee9bcc0e989f3b0c40f68372a9a51b6c4e6a | Bin 0 -> 162 bytes .../c3/d02eeef75183df7584d8d13ac03053910c1301 | Bin 0 -> 67 bytes .../c4/efe31e9decccc8b2b4d3df9aac2cdfe2995618 | Bin 0 -> 538 bytes .../c5/0d0f1cb60b8b0fe1615ad20ace557e9d68d7bd | 1 + .../c5/bbe550b9f09444bdddd3ecf3d97c0b42aa786c | Bin 0 -> 269 bytes .../c6/07fc30883e335def28cd686b51f6cfa02b06ec | 2 + .../c6/92ecf62007c0ac9fb26e2aa884de2933de15ed | Bin 0 -> 40 bytes .../c8/f06f2e3bb2964174677e91f0abead0e43c9e5d | Bin 0 -> 45 bytes .../c9/174cef549ec94ecbc43ef03cdc775b4950becb | 2 + .../c9/4b27e41064c521120627e07e2035cca1d24ffa | Bin 0 -> 162 bytes .../ca/b2cf23998b40f1af2d9d9a756dc9e285a8df4b | Bin 0 -> 40 bytes .../cb/491780d82e46dc88a065b965ab307a038f2bc2 | Bin 0 -> 163 bytes .../cb/6693a788715b82440a54e0eacd19ba9f6ec559 | Bin 0 -> 41 bytes .../cc/3e3009134cb88014129fc8858d1101359e5e2f | 2 + .../ce/8860d49e3bea6fd745874a01b7c3e46da8cbc3 | Bin 0 -> 48 bytes .../ce/e656c392ad0557b3aae0fb411475c206e2926f | Bin 0 -> 32 bytes .../cf/8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d | Bin 0 -> 29 bytes .../d0/7ec190c306ec690bac349e87d01c4358e49bb2 | 2 + .../d0/d4594e16f2e19107e3fa7ea63e7aaaff305ffb | Bin 0 -> 51 bytes .../d2/f8637f2eab2507a1e13cbc9df4729ec386627e | Bin 0 -> 268 bytes .../d3/719a5ae8e4d92276b5313ce976f6ee5af2b436 | 2 + .../d3/7aa3bbfe1c0c49b909781251b956dbabe85f96 | Bin 0 -> 80 bytes .../d3/7ad72a2052685fc6201c2af90103ad42d2079b | Bin 0 -> 233 bytes .../d4/207f77243500bec335ab477f9227fcdb1e271a | 2 + .../d4/27e0b2e138501a3d15cc376077a3631e15bd46 | Bin 0 -> 38 bytes .../d5/093787ef302b941b6aab081b99fb4880038bd8 | Bin 0 -> 30 bytes .../d5/a61b0b4992a4f0caa887fa08b52431e727bb6f | Bin 0 -> 81 bytes .../d5/b6fc965c926a1bfc9ee456042b94088b5c5d21 | Bin 0 -> 319 bytes .../d5/ec1152fe25e9fec00189eb00b3db71db24c218 | Bin 0 -> 24 bytes .../d6/42b9770c66bba94a08df09b5efb095001f76d7 | Bin 0 -> 539 bytes .../d6/462fa3f5292857db599c54aea2bf91616230c5 | Bin 0 -> 48 bytes .../d6/cf6c7741b3316826af1314042550c97ded1d50 | 2 + .../d8/74671ef5b20184836cb983bb273e5280384d0b | Bin 0 -> 162 bytes .../d8/fa77b6833082c1ea36b7828a582d4c43882450 | 1 + .../d9/63979c237d08b6ba39062ee7bf64c7d34a27f8 | Bin 0 -> 48 bytes .../da/178208145ef585a1bd5ca5f4c9785d738df2cf | Bin 0 -> 41 bytes .../db/6261a7c65c7fd678520c9bb6f2c47582ab9ed5 | Bin 0 -> 624 bytes .../dd/9a570c3400e6e07bc4d7651d6e20b08926b3d9 | Bin 0 -> 36 bytes .../de/872ee3618b894992e9d1e18ba2ebe256a112f9 | 1 + .../df/e3f22baa1f6fce5447901c3086bae368de6bdd | Bin 0 -> 40 bytes .../e0/67f9361140f19391472df8a82d6610813c73b7 | Bin 0 -> 53 bytes .../e1/129b3cfb5898e0fbd606e0cb80b2755e50d161 | Bin 0 -> 92 bytes .../e1/7ace1492648c9dc5701bad5c47af9d1b60c4e9 | Bin 0 -> 264 bytes .../e2/c6abbd55fed5ac71a5f2751e29b4a34726a595 | 1 + .../e3/1e7ad3ed298f24e383c4950f4671993ec078e4 | Bin 0 -> 210 bytes .../e3/76fbdd06ebf021c92724da9f26f44212734e3e | 3 + .../e4/9f917b448d1340b31d76e54ba388268fd4c922 | Bin 0 -> 36 bytes .../e4/f618a2c3ed0669308735727df5ebf2447f022f | 2 + .../e6/5a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 | Bin 0 -> 160 bytes .../e8/107f24196736b870a318a0e28f048e29f6feff | 3 + .../e9/2cdb7017dc6c5aed25cb4202c5b0104b872246 | Bin 0 -> 48 bytes .../e9/ad6ec3e38364a3d07feda7c4197d4d845c53b5 | Bin 0 -> 36 bytes .../e9/f48beccc62d535739bfbdebe0a55ed716d8366 | Bin 0 -> 382 bytes .../eb/c09d0137cfb0c26697aed0109fb943ad906f3f | Bin 0 -> 166 bytes .../ec/67e5a86adff465359f1c8f995e12dbdfa08d8a | Bin 0 -> 166 bytes .../ed/9523e62e453e50dd9be1606af19399b96e397a | Bin 0 -> 87 bytes .../ee/1d6f164893c1866a323f072eeed36b855656be | Bin 0 -> 291 bytes .../ee/3fa1b8c00aff7fe02065fdb50864bb0d932ccf | Bin 0 -> 64 bytes .../ee/a9286df54245fea72c5b557291470eb825f38f | Bin 0 -> 235 bytes .../ef/58fdd8086c243bdc81f99e379acacfd21d32d6 | 2 + .../ef/c499524cf105d5264ac7fc54e07e95764e8075 | Bin 0 -> 32 bytes .../ef/c9121fdedaf08ba180b53ebfbcf71bd488ed09 | Bin 0 -> 160 bytes .../f0/053b8060bb3f0be5cbcc3147a07ece26bf097e | Bin 0 -> 163 bytes .../f0/ce2b8e4986084d9b308fb72709e414c23eb5e6 | Bin 0 -> 125 bytes .../f2/0c9063fa0bda9a397c96947a7b687305c49753 | Bin 0 -> 29 bytes .../f2/9e7fb590551095230c6149cbe72f2e9104a796 | Bin 0 -> 41 bytes .../f3/293571dcd708b6a3faf03818cd2844d000e198 | 1 + .../f3/f1164b68b57b1995b658a828320e6df3081fae | Bin 0 -> 310 bytes .../f4/15caf3fcad16304cb424b67f0ee6b12dc03aae | Bin 0 -> 320 bytes .../f4/8097eb340dc5a7cae55aabcf1faf4548aa821f | Bin 0 -> 165 bytes .../f5/504f36e6f4eb797a56fc5bac6c6c7f32969bf2 | Bin 0 -> 42 bytes .../f5/b50c85a87cac64d7eb3254cdd1aec9564c0293 | Bin 0 -> 35 bytes .../f5/f9dd5886a6ee20272be0aafc790cba43b31931 | Bin 0 -> 244 bytes .../f6/be049e284c0f9dcbbc745543885be3502ea521 | Bin 0 -> 265 bytes .../f7/c332bd4d4d4b777366cae4d24d1687477576bf | Bin 0 -> 156 bytes .../f8/958bdf4d365a84a9a178b1f5f35ff1dacbd884 | 2 + .../fa/c03f2c5139618d87d53614c153823bf1f31396 | Bin 0 -> 76 bytes .../fa/da9356aa3f74622327a3038ae9c6f92e1c5c1d | Bin 0 -> 168 bytes .../fb/738a106cfd097a4acb96ce132ecb1ad6c46b03 | Bin 0 -> 264 bytes .../fc/4c636d6515e9e261f9260dbcf3cc6eca97ea08 | Bin 0 -> 29 bytes .../fc/7d7b805f7a9428574f4f802b2e34cd20ab9d99 | Bin 0 -> 575 bytes .../fc/90237dc4891fa6c69827fc465632225e391618 | Bin 0 -> 163 bytes .../fd/57d2d6770fad8e9959124793a17f441b571e66 | Bin 0 -> 279 bytes .../fd/89f8cffb663ac89095a0f9764902e93ceaca6a | 2 + .../fe/5407fc50a53aecb41d1a6e9ea7b612e581af87 | Bin 0 -> 48 bytes .../ff/49d07869831ad761bbdaea026086f8789bcb00 | Bin 0 -> 24 bytes .../ff/b312248d607284c290023f9502eea010d34efd | Bin 0 -> 68 bytes .../merge-resolve/.gitted/refs/heads/branch | 1 + .../.gitted/refs/heads/df_ancestor | 1 + .../merge-resolve/.gitted/refs/heads/df_side1 | 1 + .../merge-resolve/.gitted/refs/heads/df_side2 | 1 + .../.gitted/refs/heads/ff_branch | 1 + .../merge-resolve/.gitted/refs/heads/master | 1 + .../merge-resolve/.gitted/refs/heads/octo1 | 1 + .../merge-resolve/.gitted/refs/heads/octo2 | 1 + .../merge-resolve/.gitted/refs/heads/octo3 | 1 + .../merge-resolve/.gitted/refs/heads/octo4 | 1 + .../merge-resolve/.gitted/refs/heads/octo5 | 1 + .../merge-resolve/.gitted/refs/heads/octo6 | 1 + .../refs/heads/rename_conflict_ancestor | 1 + .../.gitted/refs/heads/rename_conflict_ours | 1 + .../.gitted/refs/heads/rename_conflict_theirs | 1 + .../merge-resolve/.gitted/refs/heads/renames1 | 1 + .../merge-resolve/.gitted/refs/heads/renames2 | 1 + .../.gitted/refs/heads/trivial-10 | 1 + .../.gitted/refs/heads/trivial-10-branch | 1 + .../.gitted/refs/heads/trivial-11 | 1 + .../.gitted/refs/heads/trivial-11-branch | 1 + .../.gitted/refs/heads/trivial-13 | 1 + .../.gitted/refs/heads/trivial-13-branch | 1 + .../.gitted/refs/heads/trivial-14 | 1 + .../.gitted/refs/heads/trivial-14-branch | 1 + .../.gitted/refs/heads/trivial-2alt | 1 + .../.gitted/refs/heads/trivial-2alt-branch | 1 + .../.gitted/refs/heads/trivial-3alt | 1 + .../.gitted/refs/heads/trivial-3alt-branch | 1 + .../.gitted/refs/heads/trivial-4 | 1 + .../.gitted/refs/heads/trivial-4-branch | 1 + .../.gitted/refs/heads/trivial-5alt-1 | 1 + .../.gitted/refs/heads/trivial-5alt-1-branch | 1 + .../.gitted/refs/heads/trivial-5alt-2 | 1 + .../.gitted/refs/heads/trivial-5alt-2-branch | 1 + .../.gitted/refs/heads/trivial-6 | 1 + .../.gitted/refs/heads/trivial-6-branch | 1 + .../.gitted/refs/heads/trivial-7 | 1 + .../.gitted/refs/heads/trivial-7-branch | 1 + .../.gitted/refs/heads/trivial-8 | 1 + .../.gitted/refs/heads/trivial-8-branch | 1 + .../.gitted/refs/heads/trivial-9 | 1 + .../.gitted/refs/heads/trivial-9-branch | 1 + .../.gitted/refs/heads/unrelated | 1 + .../merge-resolve/added-in-master.txt | 1 + .../resources/merge-resolve/automergeable.txt | 9 + .../merge-resolve/changed-in-branch.txt | 1 + .../merge-resolve/changed-in-master.txt | 1 + .../resources/merge-resolve/conflicting.txt | 1 + .../merge-resolve/removed-in-branch.txt | 1 + .../resources/merge-resolve/unchanged.txt | 1 + 420 files changed, 3103 insertions(+), 38 deletions(-) create mode 100644 docs/merge-df_conflicts.txt create mode 100644 src/merge_file.c create mode 100644 src/merge_file.h create mode 100644 tests-clar/merge/merge_helpers.c create mode 100644 tests-clar/merge/merge_helpers.h create mode 100644 tests-clar/merge/trees/automerge.c create mode 100644 tests-clar/merge/trees/modeconflict.c create mode 100644 tests-clar/merge/trees/treediff.c create mode 100644 tests-clar/merge/trees/trivial.c rename tests-clar/merge/{ => workdir}/setup.c (85%) create mode 100644 tests-clar/resources/merge-resolve/.gitted/COMMIT_EDITMSG create mode 100644 tests-clar/resources/merge-resolve/.gitted/HEAD create mode 100644 tests-clar/resources/merge-resolve/.gitted/ORIG_HEAD create mode 100644 tests-clar/resources/merge-resolve/.gitted/config create mode 100644 tests-clar/resources/merge-resolve/.gitted/description create mode 100644 tests-clar/resources/merge-resolve/.gitted/index create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/HEAD create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_ancestor create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/ff_branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/master create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo3 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo5 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo6 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/unrelated create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/00/5b6fcc8fec71d2550bef8462d169b3c26aa14b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/00/9b9cab6fdac02915a88ecd078b7a792ed802d8 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/00/c7d33f1ffa79d19c2272b370fcaeaadba49c08 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/01/f149e1b8f84bd8896aaff6d6b22af88459ded0 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/02/04a84f822acbf6386b36d33f1f6bc68bbbf858 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/02/251f990ca8e92e7ae61d3426163fa821c64001 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/03/21415405cb906c46869919af56d51dbbe5e85c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/03/2ebc5ab85d9553bb187d3cd40875ff23a63ed0 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/03/b87706555accbf874ccd410dbda01e8e70a67f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/03/dad1005e5d06d418f50b12e0bcd48ff2306a03 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/05/1ffd7901a442faf56b226161649074f15c7c47 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/05/8541fc37114bfc1dddf6bd6bffc7fae5c2e6fe create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/05/f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/07/a759da919f737221791d542f176ab49c88837f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/07/c514b04698e068892b31c8d352b85813b99c6e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/09/055301463b7f2f8ee5d368f8ed5c0a40ad8515 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/09/17bb159596aea4d295f4857da77e8f96b3c7dc create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/09/2ce8682d7f3a2a3a769a6daca58950168ba5c4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/09/3bebf072dd4bbba88833667d6ffe454df199e1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/09/768bed22680cdb0859683fa9677ccc8d5a25c1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/0a/75d9aac1dc84fb5aa51f7325c0ab53242ddef7 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/0c/fd6c54ef6532d862408f562309dc9c74a401e8 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/0d/52e3a556e189ba0948ae56780918011c1b167d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/0d/872f8e871a30208305978ecbf9e66d864f1638 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/0e/c5f433959cd46177f745903353efb5be08d151 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/11/deab00b2d3a6f5a3073988ac050c2d7b6655e2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/11/f4f3c08b737f5fd896cbefa1425ee63b21b2fa create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/13/d1be4ea52a6ced1d7a1d832f0ee3c399348e5e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/14/39088f509b79b1535b64193137d3ce4b240734 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/15/8dc7bedb202f5b26502bf3574faa7f4238d56c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/16/f825815cfd20a07a75c71554e82d8eede0b061 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/17/8940b450f238a56c0d75b7955cb57b38191982 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/18/3310e30fb1499af8c619108ffea4d300b5e778 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/18/cb316b1cefa0f8a6946f0e201a8e1a6f845ab9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/19/b7ac485269b672a101060894de3ba9c2a24dd1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/1c/ff9ec6a47a537380dedfdd17c9e76d74259a2b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/1e/4ff029aee68d0d69ef9eb6efa6cbf1ec732f99 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/1f/81433e3161efbf250576c58fede7f6b836f3d3 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/20/91d94c8bd3eb0835dc5220de5e8bb310fa1513 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/21/671e290278286fb2ce4c63d01699b67adce331 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/22/7792b52aaa0b238bea00ec7e509b02623f168c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/23/3c0919c998ed110a4b6ff36f353aec8b713487 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/23/92a2dacc9efb562b8635d6579fb458751c7c5b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/24/1a1005cd9b980732741b74385b891142bcba28 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/24/2591eb280ee9eeb2ce63524b9a8b9bc4cb515d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/24/90b9f1a079420870027deefb49f51d6656cf74 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/25/9d08ca43af9200e9ea9a098e44a5a350ebd9b3 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/25/c40b7660c08c8fb581f770312f41b9b03119d1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/26/153a3ff3649b6c2bb652d3f06878c6e0a172f9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/27/133da702ba3c60af2a01e96c2555ff4045d692 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/2b/0de5dc27505dcdd83a75c8bf1fcd9462cd7add create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/2b/5f1f181ee3b58ea751f5dd5d8f9b445520a136 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/2b/d0a343aeef7a2cf0d158478966a6e587ff3863 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/2d/a538570bc1e5b2c3e855bf702f35248ad0735f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/2f/2e37b7ebbae467978610896ca3aafcdad2ee67 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/2f/4024ce528d36d8670c289cce5a7963e625bb0c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/2f/56120107d680129a5d9791b521cb1e73a2ed31 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/2f/598248eeccfc27e5ca44d9d96383f6dfea7b16 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/31/68dca1a561889b045a6441909f4c56145e666d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/31/d5472536041a83d986829240bbbdc897c6f8a6 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/32/21dd512b7e2dc4b5bd03046df6c81b2ab2070b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/33/46d64325b39e5323733492cd55f808994a2475 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/33/d500f588fbbe65901d82b4e6b008e549064be0 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/34/bfafff88eaf118402b44e6f3e2dbbf1a582b05 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/35/0c6eb3010efc403a6bed682332635314e9ed58 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/35/411bfb77cd2cc431f3a03a2b4976ed94b5d241 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/35/4704d3613ad4228e4786fc76656b11e98236c4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/35/632e43612c06a3ea924bfbacd48333da874c29 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/35/75826c96a975031d2c14368529cc5c4353a8fd create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/36/219b49367146cb2e6a1555b5a9ebd4d0328495 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/36/4bbe4ce80c7bd31e6307dce77d46e3e1759fb3 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/37/48859b001c6e627e712a07951aee40afd19b41 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/38/5c8a0f26ddf79e9041e15e17dc352ed2c4cced create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/3b/47b031b3e55ae11e14a05260b1c3ffd6838d55 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/3b/bf0bf59b20df5d5fc58b9fc1dc07be637c301f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/3e/f4d30382ca33fdeba9fda895a99e0891ba37aa create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/3e/f9bfe82f9635518ae89152322f3b46fd4ba25b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/40/2784a46a4a3982294231594cbeb431f506d22c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/41/2b32fb66137366147f1801ecc962452757d48a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/43/aafd43bea779ec74317dc361f45ae3f532a505 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/43/c338656342227a3a3cd3aa85cbf784061f5425 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/45/299c1ca5e07bba1fd90843056fb559f96b1f5a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/46/6daf8552b891e5c22bc58c9d7fc1a2eb8f0289 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/47/6dbb3e207313d1d8aaa120c6ad204bf1295e53 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/47/8172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/49/130a28ef567af9a6a6104c38773fedfa5f9742 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/49/9df817155e4bdd3c6ee192a72c52f481818230 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4a/9550ebcc97ce22b22f45af7b829bb030d003f5 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4b/253da36a0ae8bfce63aeabd8c5b58429925594 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4b/48deed3a433909bfd6b6ab3d4b91348b6af464 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4c/9fac0707f8d4195037ae5a681aa48626491541 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4c/a408a8c88655f7586a1b580be6fad138121e98 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4e/0d9401aee78eb345a8685a859d37c8c3c0bbed create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4e/886e602529caa9ab11d71f86634bd1b6e0de10 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4e/b04c9e79e88f6640d01ff5b25ca2a60764f216 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/4f/e93c0ec83eb6305cbace3dace88ecee1b63cb6 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/50/12fd565b1393bdfda1805d4ec38ce6619e1fd1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/50/4f75ac95a71ef98051817618576a68505b92f9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/50/84fc2a88b6bdba8db93bd3953a8f4fdb470238 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/50/ce7d7d01217679e26c55939eef119e0c93e272 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/51/95a1b480f66691b667f10a9e41e70115a78351 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/52/d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/53/825f41ac8d640612f9423a2f03a69f3d96809a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/54/269b3f6ec3d7d4ede24dd350dd5d605495c3ae create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/54/59c89aa0026d543ce8343bd89871bce543f9c2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/54/7607c690372fe81fab8e3bb44c530e129118fd create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/55/b4e4687e7a0d9ca367016ed930f385d4022e6f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/56/6ab53c220a2eafc1212af1a024513230280ab9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/56/a638b76b75e068590ac999c2f8621e7f3e264c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/57/079a46233ae2b6df62e9ade71c4948512abefb create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/58/43febcb23480df0b5edb22a21c59c772bb8e29 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/58/e853f66699fd02629fd50bde08082bc005933a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/59/6803b523203a4851c824c07366906f8353f4ad create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/5c/2411f8075f48a6b2fdb85ebc0d371747c4df15 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/5c/341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/5c/3b68a71fc4fa5d362fd3875e53137c6a5ab7a5 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/5d/c1018e90b19654bee986b7a0c268804d39659d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/5d/dd0fe66f990dc0e5cf9fec6d9b465240e9537f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/5e/b7bb6a146eb3c7fd3990b240a2308eceb1cf8d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/5f/bfbdc04b4eca46f54f4853a3c5a1dce28f5165 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/60/91fc2c036a382a69489e3f518ee5aae9a4e567 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/61/340eeed7340fa6a8792def9a5938bb5d4434bb create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/61/78885b38fe96e825ac0f492c0a941f288b37f6 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/62/12c31dab5e482247d7977e4f0dd3601decf13b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/62/269111c3b02a9355badcb9da8678b1bf41787b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/62/c4f6533c9a3894191fdcb96a3be935ade63f1a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/63/247125386de9ec90a27ad36169307bf8a11a38 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/67/18a45909532d1fcf5600d0877f7fe7e78f0b86 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/68/c6c84b091926c7d90aa6a79b2bc3bb6adccd8e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/69/f570c57b24ea7c086e94c5e574964798321435 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/6a/e1a3967031a42cf955d9d5c2395211ac82f6cf create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/6b/7e37be8ce0b897093f2878a9dcd8f396beda2c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/6c/06dcd163587c2cc18be44857e0b71116382aeb create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/6f/32739c3724d1d5f855299309f388606f407468 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/6f/a33014764bf1120a454eb8437ae098238e409b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/6f/be9fb85c86d7d1435f728da418bdff52c640a9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/71/17467b18605a660ebe5586df69e2311ed5609f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/71/2ebba6669ea847d9829e4f1059d6c830c8b531 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/71/add2d7b93d55bf3600f8a1582beceebbd050c8 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/74/df13f0793afdaa972150bba976f7de8284914e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/75/a811bf6bc57694adb3fe604786f3a4efd1cd1b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/76/63fce0130db092936b137cabd693ec234eb060 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/76/ab0e2868197ec158ddd6c78d8a0d2fd73d38f9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/7a/a3edf2bcfee22398e6b55295aa56366b7aaf76 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/7c/2c5228c9e90170d4a35e6558e47163daf092e5 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/7c/b63eed597130ba4abb87b3e544b85021905520 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/7e/2d058d5fedf8329db44db4fac610d6b1a89159 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/7f/7a2da58126226986d71c6ddfab4afba693280d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/80/a8fbb3abb1ba423d554e9630b8fc2e5698f86b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/81/87117062b750eed4f93fd7e899f17b52ce554d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/83/07d93a155903a5c49576583f0ce1f6ff897c0e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/83/824a8c6658768e2013905219cc8c64cc3d9a2e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/84/9619b03ae540acee4d1edec96b86993da6b497 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/84/de84f8f3a6d63e636ee9ad81f4b80512fa9bbe create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/86/088dae8bade454995b21a1c88107b0e1accdab create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/87/b4926260d77a3b851e71ecce06839bd650b231 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/88/e185910a15cd13bdf44854ad037f4842b03b29 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/8a/ad9d0ea334951da47b621a475b39cc6ed759bf create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/8a/ae714f7d939309d7f132b30646d96743134a9f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/8b/095d8fd01594f4d14454d073e3ac57b9ce485f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/8b/5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/8c/749d9968d4b10dcfb06c9f97d0e5d92d337071 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/8f/4433f8593ddd65b7dd43dd4564d841f4d9c8aa create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/90/a336c7dacbe295159413559b0043b8bdc60d57 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/91/2b2d7819cf9c1029e414883857ed61d597a1a5 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/91/8bb3e09090a9995d48af9a2a6296d7e6088d1c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/92/7d4943cdbdc9a667db8e62cfd0a41870235c51 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/93/77fccdb210540b8c0520cc6e80eb632c20bd25 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/94/4f5dd1a867cab4c2bbcb896493435cae1dcc1a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/94/8ba6e701c1edab0c2d394fb7c5538334129793 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/95/646149ab6b6ba6edc83cff678582538b457b2b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/95/9de65e568274120fdf9e3af9f77b1550122149 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/96/8ca794a4597f7f6abbb2b8d940b4078a0f3fd4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/97/7c696519c5a3004c5f1d15d60c89dbeb8f235f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/98/ba4205fcf31f5dd93c916d35fe3f3b3d0e6714 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/98/d52d07c0b0bbf2b46548f6aa521295c2cb55db create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/99/b4f7e4f24470fa06b980bc21f1095c2a9425c0 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/9a/301fbe6fada7dcb74fcd7c20269b5c743459a7 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/9a/f731fa116d1eb9a6c0109562472cfee6f5a979 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/9c/0b6c34ef379a42d858f03fef38630f476b9102 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/9e/7f4359c469f309b6057febf4c6e80742cbed5b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/9e/fe7723802d4305142eee177e018fee1572c4f4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/9f/74397a3397b3585faf09e9926b110d7f654254 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a0/31a28ae70e33a641ce4b8a8f6317f1ab79dee4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a3/9a620dae5bc8b4e771cd4d251b7d080401a21e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a3/fabece9eb8748da810e1e08266fef9b7136ad4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a4/1b1bb6d0be3c22fb654234c33b428e15c8cc27 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a4/3150a738849c59376cf30bb2a68348a83c8f48 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a5/563304ddf6caba25cb50323a2ea6f7dbfcadca create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a7/08b253bd507417ec42d1467a7fd2d7519c4956 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a7/65fb87eb2f7a1920b73b2d5a057f8f8476a42b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a7/7a56a49f8f3ae242e02717f18ebbc60c5cc543 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a7/dbfcbfc1a60709cb80b5ca24539008456531d0 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a8/02e06f1782a9645b9851bc7202cee74a8a4972 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a8/87dd39ad3edd610fc9083dcb61e40ab50673d1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/a9/0bc3fb6f15181972a2959a921429efbd81a473 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ab/40af3cb8a3ed2e2843e96d9aa7871336b94573 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ab/6c44a2e84492ad4b41bb6bac87353e9d02ac8b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ab/929391ac42572f92110f3deeb4f0844a951e22 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ac/4045f965119e6998f4340ed0f411decfb3ec05 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ad/a14492498136771f69dd451866cabcb0e9ef9a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ad/a55a45d14527dc3dfc714ea1c65d2e1e6fbe87 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/b2/d399ae15224e1d58066e3c8df70ce37de7a656 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/b4/2712cfe99a1a500b2a51fe984e0b8a7702ba11 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/b6/9fe837e4cecfd4c9a40cdca7c138468687df07 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/b6/f610aef53bd343e6c96227de874c66f00ee8e8 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/b7/a2576f9fc20024ac9ef17cb134acbd1ac73127 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/b8/a3a806d3950e8c0a03a34f234a92eff0e2c68d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ba/cac9b3493509aa15e1730e1545fc0919d1dae0 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/bc/744705e1d8a019993cf88f62bc4020f1b80919 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/bc/95c75d59386147d1e79a87c33068d8dbfd71f2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/bd/593285fc7fe4ca18ccdbabf027f5d689101452 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/bd/867fbae2faa80b920b002b80b1c91bcade7784 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/bd/9cb4cd0a770cb9adcb5fce212142ef40ea1c35 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/be/f6e37b3ee632ba74159168836f382fed21d77d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c0/6a9be584ac49aa02c5551312d9e2982c91df10 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c1/b17981db0840109a820dae8674ee29684134ff create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c1/b6a51bbb87c2f82b161412c3d20b59fc69b090 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c3/5dee9bcc0e989f3b0c40f68372a9a51b6c4e6a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c3/d02eeef75183df7584d8d13ac03053910c1301 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c4/efe31e9decccc8b2b4d3df9aac2cdfe2995618 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c5/0d0f1cb60b8b0fe1615ad20ace557e9d68d7bd create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c5/bbe550b9f09444bdddd3ecf3d97c0b42aa786c create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c6/07fc30883e335def28cd686b51f6cfa02b06ec create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c6/92ecf62007c0ac9fb26e2aa884de2933de15ed create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c8/f06f2e3bb2964174677e91f0abead0e43c9e5d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c9/174cef549ec94ecbc43ef03cdc775b4950becb create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/c9/4b27e41064c521120627e07e2035cca1d24ffa create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ca/b2cf23998b40f1af2d9d9a756dc9e285a8df4b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/cb/491780d82e46dc88a065b965ab307a038f2bc2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/cb/6693a788715b82440a54e0eacd19ba9f6ec559 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/cc/3e3009134cb88014129fc8858d1101359e5e2f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ce/8860d49e3bea6fd745874a01b7c3e46da8cbc3 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ce/e656c392ad0557b3aae0fb411475c206e2926f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/cf/8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d0/7ec190c306ec690bac349e87d01c4358e49bb2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d0/d4594e16f2e19107e3fa7ea63e7aaaff305ffb create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d2/f8637f2eab2507a1e13cbc9df4729ec386627e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d3/719a5ae8e4d92276b5313ce976f6ee5af2b436 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d3/7aa3bbfe1c0c49b909781251b956dbabe85f96 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d3/7ad72a2052685fc6201c2af90103ad42d2079b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d4/207f77243500bec335ab477f9227fcdb1e271a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d4/27e0b2e138501a3d15cc376077a3631e15bd46 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d5/093787ef302b941b6aab081b99fb4880038bd8 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d5/a61b0b4992a4f0caa887fa08b52431e727bb6f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d5/b6fc965c926a1bfc9ee456042b94088b5c5d21 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d5/ec1152fe25e9fec00189eb00b3db71db24c218 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d6/42b9770c66bba94a08df09b5efb095001f76d7 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d6/462fa3f5292857db599c54aea2bf91616230c5 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d6/cf6c7741b3316826af1314042550c97ded1d50 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d8/74671ef5b20184836cb983bb273e5280384d0b create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d8/fa77b6833082c1ea36b7828a582d4c43882450 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/d9/63979c237d08b6ba39062ee7bf64c7d34a27f8 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/da/178208145ef585a1bd5ca5f4c9785d738df2cf create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/db/6261a7c65c7fd678520c9bb6f2c47582ab9ed5 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/dd/9a570c3400e6e07bc4d7651d6e20b08926b3d9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/de/872ee3618b894992e9d1e18ba2ebe256a112f9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/df/e3f22baa1f6fce5447901c3086bae368de6bdd create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e0/67f9361140f19391472df8a82d6610813c73b7 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e1/129b3cfb5898e0fbd606e0cb80b2755e50d161 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e1/7ace1492648c9dc5701bad5c47af9d1b60c4e9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e2/c6abbd55fed5ac71a5f2751e29b4a34726a595 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e3/1e7ad3ed298f24e383c4950f4671993ec078e4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e3/76fbdd06ebf021c92724da9f26f44212734e3e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e4/9f917b448d1340b31d76e54ba388268fd4c922 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e4/f618a2c3ed0669308735727df5ebf2447f022f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e6/5a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e8/107f24196736b870a318a0e28f048e29f6feff create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e9/2cdb7017dc6c5aed25cb4202c5b0104b872246 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e9/ad6ec3e38364a3d07feda7c4197d4d845c53b5 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/e9/f48beccc62d535739bfbdebe0a55ed716d8366 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/eb/c09d0137cfb0c26697aed0109fb943ad906f3f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ec/67e5a86adff465359f1c8f995e12dbdfa08d8a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ed/9523e62e453e50dd9be1606af19399b96e397a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ee/1d6f164893c1866a323f072eeed36b855656be create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ee/3fa1b8c00aff7fe02065fdb50864bb0d932ccf create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ee/a9286df54245fea72c5b557291470eb825f38f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ef/58fdd8086c243bdc81f99e379acacfd21d32d6 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ef/c499524cf105d5264ac7fc54e07e95764e8075 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ef/c9121fdedaf08ba180b53ebfbcf71bd488ed09 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f0/053b8060bb3f0be5cbcc3147a07ece26bf097e create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f0/ce2b8e4986084d9b308fb72709e414c23eb5e6 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f2/0c9063fa0bda9a397c96947a7b687305c49753 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f2/9e7fb590551095230c6149cbe72f2e9104a796 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f3/293571dcd708b6a3faf03818cd2844d000e198 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f3/f1164b68b57b1995b658a828320e6df3081fae create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f4/15caf3fcad16304cb424b67f0ee6b12dc03aae create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f4/8097eb340dc5a7cae55aabcf1faf4548aa821f create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f5/504f36e6f4eb797a56fc5bac6c6c7f32969bf2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f5/b50c85a87cac64d7eb3254cdd1aec9564c0293 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f5/f9dd5886a6ee20272be0aafc790cba43b31931 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f6/be049e284c0f9dcbbc745543885be3502ea521 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f7/c332bd4d4d4b777366cae4d24d1687477576bf create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/f8/958bdf4d365a84a9a178b1f5f35ff1dacbd884 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/fa/c03f2c5139618d87d53614c153823bf1f31396 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/fa/da9356aa3f74622327a3038ae9c6f92e1c5c1d create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/fb/738a106cfd097a4acb96ce132ecb1ad6c46b03 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/fc/4c636d6515e9e261f9260dbcf3cc6eca97ea08 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/fc/7d7b805f7a9428574f4f802b2e34cd20ab9d99 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/fc/90237dc4891fa6c69827fc465632225e391618 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/fd/57d2d6770fad8e9959124793a17f441b571e66 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/fd/89f8cffb663ac89095a0f9764902e93ceaca6a create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/fe/5407fc50a53aecb41d1a6e9ea7b612e581af87 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ff/49d07869831ad761bbdaea026086f8789bcb00 create mode 100644 tests-clar/resources/merge-resolve/.gitted/objects/ff/b312248d607284c290023f9502eea010d34efd create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/df_ancestor create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/df_side2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/ff_branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/master create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/octo1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/octo2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/octo3 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/octo4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/octo5 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/octo6 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ancestor create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_ours create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/rename_conflict_theirs create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/renames1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/renames2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-10-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-11-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-13-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-14-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-2alt-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-3alt-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-4-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-1-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-5alt-2-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-6-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-7-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-8-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9 create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/trivial-9-branch create mode 100644 tests-clar/resources/merge-resolve/.gitted/refs/heads/unrelated create mode 100644 tests-clar/resources/merge-resolve/added-in-master.txt create mode 100644 tests-clar/resources/merge-resolve/automergeable.txt create mode 100644 tests-clar/resources/merge-resolve/changed-in-branch.txt create mode 100644 tests-clar/resources/merge-resolve/changed-in-master.txt create mode 100644 tests-clar/resources/merge-resolve/conflicting.txt create mode 100644 tests-clar/resources/merge-resolve/removed-in-branch.txt create mode 100644 tests-clar/resources/merge-resolve/unchanged.txt diff --git a/docs/merge-df_conflicts.txt b/docs/merge-df_conflicts.txt new file mode 100644 index 000000000..09780ee2d --- /dev/null +++ b/docs/merge-df_conflicts.txt @@ -0,0 +1,41 @@ +Anc / Our / Thr represent the ancestor / ours / theirs side of a merge +from branch "branch" into HEAD. Workdir represents the expected files in +the working directory. Index represents the expected files in the index, +with stage markers. + + Anc Our Thr Workdir Index +1 D D + D/F D/F D/F [0] + +2 D D+ D~HEAD (mod/del) D/F [0] + D/F D/F D [1] + D [2] + +3 D D D/F D/F [0] + D/F + +4 D D+ D~branch (mod/del) D/F [0] + D/F D/F D [1] + D [3] + +5 D D/F (add/add) D/F [2] + D/F D/F [3] + D/F + +6 D/F D/F D D [0] + D + +7 D/F D/F+ D/F (mod/del) D/F [1] + D D~branch (fil/dir) D/F [2] + D [3] + +8 D/F D/F D D [0] + D + +9 D/F D/F+ D/F (mod/del) D/F [1] + D D~HEAD (fil/dir) D [2] + D/F [3] + +10 D/F D/F (fil/dir) D/F [0] + D D~HEAD D [2] + D diff --git a/include/git2/index.h b/include/git2/index.h index 3d4bd15a8..fcfe4be3d 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -551,9 +551,9 @@ GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_byindex(git_index *i * @return 0 or an error code */ GIT_EXTERN(int) git_index_reuc_add(git_index *index, const char *path, - int ancestor_mode, git_oid *ancestor_id, - int our_mode, git_oid *our_id, - int their_mode, git_oid *their_id); + int ancestor_mode, const git_oid *ancestor_id, + int our_mode, const git_oid *our_id, + int their_mode, const git_oid *their_id); /** * Remove an resolve undo entry from the index diff --git a/include/git2/merge.h b/include/git2/merge.h index f4c5d9881..43a61f0e4 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -7,19 +7,51 @@ #ifndef INCLUDE_git_merge_h__ #define INCLUDE_git_merge_h__ -#include "common.h" -#include "types.h" -#include "oid.h" +#include "git2/common.h" +#include "git2/types.h" +#include "git2/oid.h" +#include "git2/checkout.h" +#include "git2/index.h" /** * @file git2/merge.h - * @brief Git merge-base routines - * @defgroup git_revwalk Git merge-base routines + * @brief Git merge routines + * @defgroup git_merge Git merge routines * @ingroup Git * @{ */ GIT_BEGIN_DECL +/** + * Flags for tree_many diff options. A combination of these flags can be + * passed in via the `flags` value in the `git_diff_tree_many_options`. + */ +typedef enum { +} git_merge_tree_flags; + +/** + * Automerge options for `git_merge_trees_opts`. + */ +typedef enum { + GIT_MERGE_AUTOMERGE_NORMAL = 0, + GIT_MERGE_AUTOMERGE_NONE = 1, + GIT_MERGE_AUTOMERGE_FAVOR_OURS = 2, + GIT_MERGE_AUTOMERGE_FAVOR_THEIRS = 3, +} git_merge_automerge_flags; + + +typedef struct { + unsigned int version; + git_merge_tree_flags flags; + + /** Flags for automerging content. */ + git_merge_automerge_flags automerge_flags; +} git_merge_tree_opts; + +#define GIT_MERGE_TREE_OPTS_VERSION 1 +#define GIT_MERGE_TREE_OPTS_INIT {GIT_MERGE_TREE_OPTS_VERSION} + + /** * Find a merge base between two commits * @@ -50,6 +82,28 @@ GIT_EXTERN(int) git_merge_base_many( const git_oid input_array[], size_t length); +/** + * Merge two trees, producing a `git_index` that reflects the result of + * the merge. + * + * The returned index must be freed explicitly with `git_index_free`. + * + * @param out pointer to store the index result in + * @param repo repository that contains the given trees + * @param ancestor_tree the common ancestor between the trees (or null if none) + * @param our_tree the tree that reflects the destination tree + * @param their_tree the tree to merge in to `our_tree` + * @param opts the merge tree options (or null for defaults) + * @return zero on success, -1 on failure. + */ +GIT_EXTERN(int) git_merge_trees( + git_index **out, + git_repository *repo, + const git_tree *ancestor_tree, + const git_tree *our_tree, + const git_tree *their_tree, + const git_merge_tree_opts *opts); + /** @} */ GIT_END_DECL #endif diff --git a/src/index.c b/src/index.c index 2e2d373b5..fe3a2104b 100644 --- a/src/index.c +++ b/src/index.c @@ -585,8 +585,9 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const 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) + int ancestor_mode, const git_oid *ancestor_oid, + int our_mode, const git_oid *our_oid, + int their_mode, const git_oid *their_oid) { git_index_reuc_entry *reuc = NULL; @@ -692,7 +693,7 @@ static int index_conflict_to_reuc(git_index *index, const char *path) { git_index_entry *conflict_entries[3]; int ancestor_mode, our_mode, their_mode; - git_oid *ancestor_oid, *our_oid, *their_oid; + git_oid const *ancestor_oid, *our_oid, *their_oid; int ret; if ((ret = git_index_conflict_get(&conflict_entries[0], @@ -946,7 +947,6 @@ int git_index_conflict_get(git_index_entry **ancestor_out, return GIT_ENOTFOUND; for (posmax = git_index_entrycount(index); pos < posmax; ++pos) { - conflict_entry = git_vector_get(&index->entries, pos); if (index->entries_cmp_path(conflict_entry->path, path) != 0) @@ -1048,7 +1048,10 @@ unsigned int git_index_reuc_entrycount(git_index *index) return (unsigned int)index->reuc.length; } -static int index_reuc_insert(git_index *index, git_index_reuc_entry *reuc, int replace) +static int index_reuc_insert( + git_index *index, + git_index_reuc_entry *reuc, + int replace) { git_index_reuc_entry **existing = NULL; size_t position; @@ -1070,9 +1073,9 @@ static int index_reuc_insert(git_index *index, git_index_reuc_entry *reuc, int r } 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) + int ancestor_mode, const git_oid *ancestor_oid, + int our_mode, const git_oid *our_oid, + int their_mode, const git_oid *their_oid) { git_index_reuc_entry *reuc = NULL; int error = 0; diff --git a/src/merge.c b/src/merge.c index e0010d6a4..8df156abe 100644 --- a/src/merge.c +++ b/src/merge.c @@ -5,15 +5,52 @@ * a Linking Exception. For full terms see the included COPYING file. */ +#include "common.h" +#include "posix.h" +#include "buffer.h" #include "repository.h" #include "revwalk.h" -#include "buffer.h" -#include "merge.h" -#include "refs.h" -#include "git2/repository.h" -#include "git2/merge.h" -#include "git2/reset.h" #include "commit_list.h" +#include "merge.h" +#include "path.h" +#include "refs.h" +#include "object.h" +#include "iterator.h" +#include "refs.h" +#include "diff.h" +#include "checkout.h" +#include "tree.h" +#include "merge_file.h" +#include "blob.h" +#include "hashsig.h" + +#include "git2/types.h" +#include "git2/repository.h" +#include "git2/object.h" +#include "git2/commit.h" +#include "git2/merge.h" +#include "git2/refs.h" +#include "git2/reset.h" +#include "git2/checkout.h" +#include "git2/signature.h" +#include "git2/config.h" +#include "git2/tree.h" + +#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) + +typedef enum { + TREE_IDX_ANCESTOR = 0, + TREE_IDX_OURS = 1, + TREE_IDX_THEIRS = 2 +} merge_tree_index_t; + +/* Tracks D/F conflicts */ +struct merge_diff_df_data { + const char *df_path; + const char *prev_path; + git_merge_diff *prev_conflict; +}; + int git_repository_merge_cleanup(git_repository *repo) { @@ -48,6 +85,8 @@ cleanup: return error; } +/* Merge base computation */ + int git_merge_base_many(git_oid *out, git_repository *repo, const git_oid input_array[], size_t length) { git_revwalk *walk; @@ -177,7 +216,7 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l return -1; if (git_commit_list_parse(walk, one) < 0) - return -1; + return -1; one->flags |= PARENT1; if (git_pqueue_insert(&list, one) < 0) @@ -294,3 +333,804 @@ cleanup: return error; } + +GIT_INLINE(int) index_entry_cmp(const git_index_entry *a, const git_index_entry *b) +{ + int value = 0; + + if (a->path == NULL) + return (b->path == NULL) ? 0 : 1; + + if ((value = a->mode - b->mode) == 0 && + (value = git_oid__cmp(&a->oid, &b->oid)) == 0) + value = strcmp(a->path, b->path); + + return value; +} + +/* Conflict resolution */ + +static int merge_conflict_resolve_trivial( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict) +{ + int ancestor_empty, ours_empty, theirs_empty; + int ours_changed, theirs_changed, ours_theirs_differ; + git_index_entry const *result = NULL; + int error = 0; + + assert(resolved && diff_list && conflict); + + *resolved = 0; + + if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + if (conflict->our_status == GIT_DELTA_RENAMED || + conflict->their_status == GIT_DELTA_RENAMED) + return 0; + + ancestor_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry); + ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); + theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); + + ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); + theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); + ours_theirs_differ = ours_changed && theirs_changed && + index_entry_cmp(&conflict->our_entry, &conflict->their_entry); + + /* + * Note: with only one ancestor, some cases are not distinct: + * + * 16: ancest:anc1/anc2, head:anc1, remote:anc2 = result:no merge + * 3: ancest:(empty)^, head:head, remote:(empty) = result:no merge + * 2: ancest:(empty)^, head:(empty), remote:remote = result:no merge + * + * Note that the two cases that take D/F conflicts into account + * specifically do not need to be explicitly tested, as D/F conflicts + * would fail the *empty* test: + * + * 3ALT: ancest:(empty)+, head:head, remote:*empty* = result:head + * 2ALT: ancest:(empty)+, head:*empty*, remote:remote = result:remote + * + * Note that many of these cases need not be explicitly tested, as + * they simply degrade to "all different" cases (eg, 11): + * + * 4: ancest:(empty)^, head:head, remote:remote = result:no merge + * 7: ancest:ancest+, head:(empty), remote:remote = result:no merge + * 9: ancest:ancest+, head:head, remote:(empty) = result:no merge + * 11: ancest:ancest+, head:head, remote:remote = result:no merge + */ + + /* 5ALT: ancest:*, head:head, remote:head = result:head */ + if (ours_changed && !ours_empty && !ours_theirs_differ) + result = &conflict->our_entry; + /* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ + else if (ours_changed && ours_empty && theirs_empty) + *resolved = 0; + /* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ + else if (ours_empty && !theirs_changed) + *resolved = 0; + /* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ + else if (!ours_changed && theirs_empty) + *resolved = 0; + /* 13: ancest:ancest+, head:head, remote:ancest = result:head */ + else if (ours_changed && !theirs_changed) + result = &conflict->our_entry; + /* 14: ancest:ancest+, head:ancest, remote:remote = result:remote */ + else if (!ours_changed && theirs_changed) + result = &conflict->their_entry; + else + *resolved = 0; + + if (result != NULL && + GIT_MERGE_INDEX_ENTRY_EXISTS(*result) && + (error = git_vector_insert(&diff_list->staged, (void *)result)) >= 0) + *resolved = 1; + + /* Note: trivial resolution does not update the REUC. */ + + return error; +} + +static int merge_conflict_resolve_one_removed( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict) +{ + int ours_empty, theirs_empty; + int ours_changed, theirs_changed; + int error = 0; + + assert(resolved && diff_list && conflict); + + *resolved = 0; + + if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); + theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); + + ours_changed = (conflict->our_status != GIT_DELTA_UNMODIFIED); + theirs_changed = (conflict->their_status != GIT_DELTA_UNMODIFIED); + + /* Removed in both */ + if (ours_changed && ours_empty && theirs_empty) + *resolved = 1; + /* Removed in ours */ + else if (ours_empty && !theirs_changed) + *resolved = 1; + /* Removed in theirs */ + else if (!ours_changed && theirs_empty) + *resolved = 1; + + if (*resolved) + git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); + + return error; +} + + +static int merge_conflict_resolve_one_renamed( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict) +{ + int ours_renamed, theirs_renamed; + int ours_changed, theirs_changed; + git_index_entry *merged; + int error = 0; + + assert(resolved && diff_list && conflict); + + *resolved = 0; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) || + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) + return 0; + + ours_renamed = (conflict->our_status == GIT_DELTA_RENAMED); + theirs_renamed = (conflict->their_status == GIT_DELTA_RENAMED); + + if (!ours_renamed && !theirs_renamed) + return 0; + + /* Reject one file in a 2->1 conflict */ + if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || + conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2 || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + ours_changed = (git_oid__cmp(&conflict->ancestor_entry.oid, &conflict->our_entry.oid) != 0); + theirs_changed = (git_oid__cmp(&conflict->ancestor_entry.oid, &conflict->their_entry.oid) != 0); + + /* if both are modified (and not to a common target) require a merge */ + if (ours_changed && theirs_changed && + git_oid__cmp(&conflict->our_entry.oid, &conflict->their_entry.oid) != 0) + return 0; + + if ((merged = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL) + return -1; + + if (ours_changed) + memcpy(merged, &conflict->our_entry, sizeof(git_index_entry)); + else + memcpy(merged, &conflict->their_entry, sizeof(git_index_entry)); + + if (ours_renamed) + merged->path = conflict->our_entry.path; + else + merged->path = conflict->their_entry.path; + + *resolved = 1; + + git_vector_insert(&diff_list->staged, merged); + git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); + + return error; +} + +static int merge_conflict_resolve_automerge( + int *resolved, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict, + unsigned int automerge_flags) +{ + git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT, + ours = GIT_MERGE_FILE_INPUT_INIT, + theirs = GIT_MERGE_FILE_INPUT_INIT; + git_merge_file_result result = GIT_MERGE_FILE_RESULT_INIT; + git_index_entry *index_entry; + git_odb *odb = NULL; + git_oid automerge_oid; + int error = 0; + + assert(resolved && diff_list && conflict); + + *resolved = 0; + + if (automerge_flags == GIT_MERGE_AUTOMERGE_NONE) + return 0; + + /* Reject D/F conflicts */ + if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE) + return 0; + + /* Reject link/file conflicts. */ + if ((S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->our_entry.mode)) || + (S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->their_entry.mode))) + return 0; + + /* Reject name conflicts */ + if (conflict->type == GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 || + conflict->type == GIT_MERGE_DIFF_RENAMED_ADDED) + return 0; + + if ((conflict->our_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && + (conflict->their_status & GIT_DELTA_RENAMED) == GIT_DELTA_RENAMED && + strcmp(conflict->ancestor_entry.path, conflict->their_entry.path) != 0) + return 0; + + if ((error = git_repository_odb(&odb, diff_list->repo)) < 0 || + (error = git_merge_file_input_from_index_entry(&ancestor, diff_list->repo, &conflict->ancestor_entry)) < 0 || + (error = git_merge_file_input_from_index_entry(&ours, diff_list->repo, &conflict->our_entry)) < 0 || + (error = git_merge_file_input_from_index_entry(&theirs, diff_list->repo, &conflict->their_entry)) < 0 || + (error = git_merge_files(&result, &ancestor, &ours, &theirs, automerge_flags)) < 0 || + !result.automergeable || + (error = git_odb_write(&automerge_oid, odb, result.data, result.len, GIT_OBJ_BLOB)) < 0) + goto done; + + if ((index_entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry))) == NULL) + GITERR_CHECK_ALLOC(index_entry); + + index_entry->path = git_pool_strdup(&diff_list->pool, result.path); + GITERR_CHECK_ALLOC(index_entry->path); + + index_entry->file_size = result.len; + index_entry->mode = result.mode; + git_oid_cpy(&index_entry->oid, &automerge_oid); + + git_vector_insert(&diff_list->staged, index_entry); + git_vector_insert(&diff_list->resolved, (git_merge_diff *)conflict); + + *resolved = 1; + +done: + git_merge_file_input_free(&ancestor); + git_merge_file_input_free(&ours); + git_merge_file_input_free(&theirs); + git_merge_file_result_free(&result); + git_odb_free(odb); + + return error; +} + +static int merge_conflict_resolve( + int *out, + git_merge_diff_list *diff_list, + const git_merge_diff *conflict, + unsigned int automerge_flags) +{ + int resolved = 0; + int error = 0; + + *out = 0; + + if ((error = merge_conflict_resolve_trivial(&resolved, diff_list, conflict)) < 0) + goto done; + + if (automerge_flags != GIT_MERGE_AUTOMERGE_NONE) { + if (!resolved && (error = merge_conflict_resolve_one_removed(&resolved, diff_list, conflict)) < 0) + goto done; + + if (!resolved && (error = merge_conflict_resolve_one_renamed(&resolved, diff_list, conflict)) < 0) + goto done; + + if (!resolved && (error = merge_conflict_resolve_automerge(&resolved, diff_list, conflict, automerge_flags)) < 0) + goto done; + } + + *out = resolved; + +done: + return error; +} + +/* Directory/file conflict handling */ + +GIT_INLINE(const char *) merge_diff_path( + const git_merge_diff *conflict) +{ + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) + return conflict->ancestor_entry.path; + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry)) + return conflict->our_entry.path; + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) + return conflict->their_entry.path; + + return NULL; +} + +GIT_INLINE(bool) merge_diff_any_side_added_or_modified( + const git_merge_diff *conflict) +{ + if (conflict->our_status == GIT_DELTA_ADDED || + conflict->our_status == GIT_DELTA_MODIFIED || + conflict->their_status == GIT_DELTA_ADDED || + conflict->their_status == GIT_DELTA_MODIFIED) + return true; + + return false; +} + +GIT_INLINE(bool) path_is_prefixed(const char *parent, const char *child) +{ + size_t child_len = strlen(child); + size_t parent_len = strlen(parent); + + if (child_len < parent_len || + strncmp(parent, child, parent_len) != 0) + return 0; + + return (child[parent_len] == '/'); +} + +GIT_INLINE(int) merge_diff_detect_df_conflict( + struct merge_diff_df_data *df_data, + git_merge_diff *conflict) +{ + const char *cur_path = merge_diff_path(conflict); + + /* Determine if this is a D/F conflict or the child of one */ + if (df_data->df_path && + path_is_prefixed(df_data->df_path, cur_path)) + conflict->type = GIT_MERGE_DIFF_DF_CHILD; + else if(df_data->df_path) + df_data->df_path = NULL; + else if (df_data->prev_path && + merge_diff_any_side_added_or_modified(df_data->prev_conflict) && + merge_diff_any_side_added_or_modified(conflict) && + path_is_prefixed(df_data->prev_path, cur_path)) { + conflict->type = GIT_MERGE_DIFF_DF_CHILD; + + df_data->prev_conflict->type = GIT_MERGE_DIFF_DIRECTORY_FILE; + df_data->df_path = df_data->prev_path; + } + + df_data->prev_path = cur_path; + df_data->prev_conflict = conflict; + + return 0; +} + +/* Conflict handling */ + +GIT_INLINE(int) merge_diff_detect_type( + git_merge_diff *conflict) +{ + if (conflict->our_status == GIT_DELTA_ADDED && + conflict->their_status == GIT_DELTA_ADDED) + conflict->type = GIT_MERGE_DIFF_BOTH_ADDED; + else if (conflict->our_status == GIT_DELTA_MODIFIED && + conflict->their_status == GIT_DELTA_MODIFIED) + conflict->type = GIT_MERGE_DIFF_BOTH_MODIFIED; + else if (conflict->our_status == GIT_DELTA_DELETED && + conflict->their_status == GIT_DELTA_DELETED) + conflict->type = GIT_MERGE_DIFF_BOTH_DELETED; + else if (conflict->our_status == GIT_DELTA_MODIFIED && + conflict->their_status == GIT_DELTA_DELETED) + conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; + else if (conflict->our_status == GIT_DELTA_DELETED && + conflict->their_status == GIT_DELTA_MODIFIED) + conflict->type = GIT_MERGE_DIFF_MODIFIED_DELETED; + else + conflict->type = GIT_MERGE_DIFF_NONE; + + return 0; +} + +GIT_INLINE(int) index_entry_dup( + git_index_entry *out, + git_pool *pool, + const git_index_entry *src) +{ + if (src != NULL) { + memcpy(out, src, sizeof(git_index_entry)); + + if ((out->path = git_pool_strdup(pool, src->path)) == NULL) + return -1; + } + + return 0; +} + +GIT_INLINE(int) merge_delta_type_from_index_entries( + const git_index_entry *ancestor, + const git_index_entry *other) +{ + if (ancestor == NULL && other == NULL) + return GIT_DELTA_UNMODIFIED; + else if (ancestor == NULL && other != NULL) + return GIT_DELTA_ADDED; + else if (ancestor != NULL && other == NULL) + return GIT_DELTA_DELETED; + else if (S_ISDIR(ancestor->mode) ^ S_ISDIR(other->mode)) + return GIT_DELTA_TYPECHANGE; + else if(S_ISLNK(ancestor->mode) ^ S_ISLNK(other->mode)) + return GIT_DELTA_TYPECHANGE; + else if (git_oid__cmp(&ancestor->oid, &other->oid) || + ancestor->mode != other->mode) + return GIT_DELTA_MODIFIED; + + return GIT_DELTA_UNMODIFIED; +} + +static git_merge_diff *merge_diff_from_index_entries( + git_merge_diff_list *diff_list, + const git_index_entry **entries) +{ + git_merge_diff *conflict; + git_pool *pool = &diff_list->pool; + + if ((conflict = git_pool_malloc(pool, sizeof(git_merge_diff))) == NULL) + return NULL; + + if (index_entry_dup(&conflict->ancestor_entry, pool, entries[TREE_IDX_ANCESTOR]) < 0 || + index_entry_dup(&conflict->our_entry, pool, entries[TREE_IDX_OURS]) < 0 || + index_entry_dup(&conflict->their_entry, pool, entries[TREE_IDX_THEIRS]) < 0) + return NULL; + + conflict->our_status = merge_delta_type_from_index_entries( + entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_OURS]); + conflict->their_status = merge_delta_type_from_index_entries( + entries[TREE_IDX_ANCESTOR], entries[TREE_IDX_THEIRS]); + + return conflict; +} + +/* Merge trees */ + +static int merge_index_insert_conflict( + git_merge_diff_list *diff_list, + struct merge_diff_df_data *merge_df_data, + const git_index_entry *tree_items[3]) +{ + git_merge_diff *conflict; + + if ((conflict = merge_diff_from_index_entries(diff_list, tree_items)) == NULL || + merge_diff_detect_type(conflict) < 0 || + merge_diff_detect_df_conflict(merge_df_data, conflict) < 0 || + git_vector_insert(&diff_list->conflicts, conflict) < 0) + return -1; + + return 0; +} + +static int merge_index_insert_unmodified( + git_merge_diff_list *diff_list, + const git_index_entry *tree_items[3]) +{ + int error = 0; + git_index_entry *entry; + + entry = git_pool_malloc(&diff_list->pool, sizeof(git_index_entry)); + GITERR_CHECK_ALLOC(entry); + + if ((error = index_entry_dup(entry, &diff_list->pool, tree_items[0])) >= 0) + error = git_vector_insert(&diff_list->staged, entry); + + return error; +} + +int git_merge_diff_list__find_differences( + git_merge_diff_list *diff_list, + const git_tree *ancestor_tree, + const git_tree *our_tree, + const git_tree *their_tree) +{ + git_iterator *iterators[3] = {0}; + git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3]; + git_vector_cmp entry_compare = git_index_entry__cmp; + struct merge_diff_df_data df_data = {0}; + int cur_item_modified; + size_t i; + int error = 0; + + assert(diff_list && our_tree && their_tree); + + if ((error = git_iterator_for_tree(&iterators[TREE_IDX_ANCESTOR], (git_tree *)ancestor_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || + (error = git_iterator_for_tree(&iterators[TREE_IDX_OURS], (git_tree *)our_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || + (error = git_iterator_for_tree(&iterators[TREE_IDX_THEIRS], (git_tree *)their_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0) + goto done; + + /* Set up the iterators */ + for (i = 0; i < 3; i++) { + if ((error = git_iterator_current(&items[i], iterators[i])) < 0) + goto done; + } + + while (true) { + memset(cur_items, 0x0, sizeof(git_index_entry *) * 3); + best_cur_item = NULL; + cur_item_modified = 0; + + /* Find the next path(s) to consume from each iterator */ + for (i = 0; i < 3; i++) { + if (items[i] == NULL) { + cur_item_modified = 1; + continue; + } + + if (best_cur_item == NULL) { + best_cur_item = items[i]; + cur_items[i] = items[i]; + } else { + int path_diff = entry_compare(items[i], best_cur_item); + + if (path_diff < 0) { + /* + * Found an item that sorts before our current item, make + * our current item this one. + */ + memset(cur_items, 0x0, sizeof(git_index_entry *) * 3); + cur_item_modified = 1; + best_cur_item = items[i]; + cur_items[i] = items[i]; + } else if (path_diff > 0) { + /* No entry for the current item, this is modified */ + cur_item_modified = 1; + } else if (path_diff == 0) { + cur_items[i] = items[i]; + + if (!cur_item_modified) + cur_item_modified = index_entry_cmp(best_cur_item, items[i]); + } + } + } + + if (best_cur_item == NULL) + break; + + if (cur_item_modified) + error = merge_index_insert_conflict(diff_list, &df_data, cur_items); + else + error = merge_index_insert_unmodified(diff_list, cur_items); + + /* Advance each iterator that participated */ + for (i = 0; i < 3; i++) { + if (cur_items[i] != NULL && + (error = git_iterator_advance(&items[i], iterators[i])) < 0) + goto done; + } + } + +done: + for (i = 0; i < 3; i++) + git_iterator_free(iterators[i]); + + return error; +} + +git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo) +{ + git_merge_diff_list *diff_list = git__calloc(1, sizeof(git_merge_diff_list)); + + if (diff_list == NULL) + return NULL; + + diff_list->repo = repo; + + if (git_vector_init(&diff_list->staged, 0, NULL) < 0 || + git_vector_init(&diff_list->conflicts, 0, NULL) < 0 || + git_vector_init(&diff_list->resolved, 0, NULL) < 0 || + git_pool_init(&diff_list->pool, 1, 0) < 0) + return NULL; + + return diff_list; +} + +static int merge_tree_normalize_opts( + git_repository *repo, + git_merge_tree_opts *opts, + const git_merge_tree_opts *given) +{ + git_config *cfg = NULL; + int error = 0; + + assert(repo && opts); + + if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) + return error; + + if (given != NULL) + memcpy(opts, given, sizeof(git_merge_tree_opts)); + else { + git_merge_tree_opts init = GIT_MERGE_TREE_OPTS_INIT; + memcpy(opts, &init, sizeof(init)); + } + + return 0; +} + + +static int merge_index_insert_reuc( + git_index *index, + size_t idx, + const git_index_entry *entry) +{ + const git_index_reuc_entry *reuc; + int mode[3] = { 0, 0, 0 }; + git_oid const *oid[3] = { NULL, NULL, NULL }; + size_t i; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(*entry)) + return 0; + + if ((reuc = git_index_reuc_get_bypath(index, entry->path)) != NULL) { + for (i = 0; i < 3; i++) { + mode[i] = reuc->mode[i]; + oid[i] = &reuc->oid[i]; + } + } + + mode[idx] = entry->mode; + oid[idx] = &entry->oid; + + return git_index_reuc_add(index, entry->path, + mode[0], oid[0], mode[1], oid[1], mode[2], oid[2]); +} + +int index_from_diff_list(git_index **out, git_merge_diff_list *diff_list) +{ + git_index *index; + size_t i; + git_index_entry *entry; + git_merge_diff *conflict; + int error = 0; + + *out = NULL; + + if ((error = git_index_new(&index)) < 0) + return error; + + git_vector_foreach(&diff_list->staged, i, entry) { + if ((error = git_index_add(index, entry)) < 0) + goto on_error; + } + + git_vector_foreach(&diff_list->conflicts, i, conflict) { + const git_index_entry *ancestor = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? + &conflict->ancestor_entry : NULL; + + const git_index_entry *ours = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + &conflict->our_entry : NULL; + + const git_index_entry *theirs = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + &conflict->their_entry : NULL; + + if ((error = git_index_conflict_add(index, ancestor, ours, theirs)) < 0) + goto on_error; + } + + /* Add each rename entry to the rename portion of the index. */ + git_vector_foreach(&diff_list->conflicts, i, conflict) { + const char *ancestor_path, *our_path, *their_path; + + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) + continue; + + ancestor_path = conflict->ancestor_entry.path; + + our_path = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + conflict->our_entry.path : NULL; + + their_path = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + conflict->their_entry.path : NULL; + } + + /* Add each entry in the resolved conflict to the REUC independently, since + * the paths may differ due to renames. */ + git_vector_foreach(&diff_list->resolved, i, conflict) { + const git_index_entry *ancestor = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) ? + &conflict->ancestor_entry : NULL; + + const git_index_entry *ours = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) ? + &conflict->our_entry : NULL; + + const git_index_entry *theirs = + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? + &conflict->their_entry : NULL; + + if (ancestor != NULL && + (error = merge_index_insert_reuc(index, TREE_IDX_ANCESTOR, ancestor)) < 0) + goto on_error; + + if (ours != NULL && + (error = merge_index_insert_reuc(index, TREE_IDX_OURS, ours)) < 0) + goto on_error; + + if (theirs != NULL && + (error = merge_index_insert_reuc(index, TREE_IDX_THEIRS, theirs)) < 0) + goto on_error; + } + + *out = index; + return 0; + +on_error: + git_index_free(index); + + return error; +} + +int git_merge_trees( + git_index **out, + git_repository *repo, + const git_tree *ancestor_tree, + const git_tree *our_tree, + const git_tree *their_tree, + const git_merge_tree_opts *given_opts) +{ + git_merge_diff_list *diff_list; + git_merge_tree_opts opts; + git_merge_diff *conflict; + git_vector changes; + size_t i; + int error = 0; + + assert(out && repo && our_tree && their_tree); + + *out = NULL; + + if ((error = merge_tree_normalize_opts(repo, &opts, given_opts)) < 0) + return error; + + diff_list = git_merge_diff_list__alloc(repo); + GITERR_CHECK_ALLOC(diff_list); + + if ((error = git_merge_diff_list__find_differences(diff_list, ancestor_tree, our_tree, their_tree)) < 0) + goto done; + + memcpy(&changes, &diff_list->conflicts, sizeof(git_vector)); + git_vector_clear(&diff_list->conflicts); + + git_vector_foreach(&changes, i, conflict) { + int resolved = 0; + + if ((error = merge_conflict_resolve(&resolved, diff_list, conflict, opts.automerge_flags)) < 0) + goto done; + + if (!resolved) + git_vector_insert(&diff_list->conflicts, conflict); + } + + error = index_from_diff_list(out, diff_list); + +done: + git_merge_diff_list__free(diff_list); + + return error; +} + +void git_merge_diff_list__free(git_merge_diff_list *diff_list) +{ + if (!diff_list) + return; + + git_vector_free(&diff_list->staged); + git_vector_free(&diff_list->conflicts); + git_vector_free(&diff_list->resolved); + git_pool_clear(&diff_list->pool); + git__free(diff_list); +} diff --git a/src/merge.h b/src/merge.h index 22c644270..6307d1569 100644 --- a/src/merge.h +++ b/src/merge.h @@ -7,16 +7,121 @@ #ifndef INCLUDE_merge_h__ #define INCLUDE_merge_h__ -#include "git2/types.h" -#include "git2/merge.h" -#include "commit_list.h" #include "vector.h" +#include "commit_list.h" +#include "pool.h" + +#include "git2/merge.h" +#include "git2/types.h" #define GIT_MERGE_MSG_FILE "MERGE_MSG" #define GIT_MERGE_MODE_FILE "MERGE_MODE" -#define MERGE_CONFIG_FILE_MODE 0666 +#define GIT_MERGE_TREE_RENAME_THRESHOLD 50 +#define GIT_MERGE_TREE_TARGET_LIMIT 1000 -int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos); +/** Types of changes when files are merged from branch to branch. */ +typedef enum { + /* No conflict - a change only occurs in one branch. */ + GIT_MERGE_DIFF_NONE = 0, + + /* Occurs when a file is modified in both branches. */ + GIT_MERGE_DIFF_BOTH_MODIFIED = (1 << 0), + + /* Occurs when a file is added in both branches. */ + GIT_MERGE_DIFF_BOTH_ADDED = (1 << 1), + + /* Occurs when a file is deleted in both branches. */ + GIT_MERGE_DIFF_BOTH_DELETED = (1 << 2), + + /* Occurs when a file is modified in one branch and deleted in the other. */ + GIT_MERGE_DIFF_MODIFIED_DELETED = (1 << 3), + + /* Occurs when a file is renamed in one branch and modified in the other. */ + GIT_MERGE_DIFF_RENAMED_MODIFIED = (1 << 4), + + /* Occurs when a file is renamed in one branch and deleted in the other. */ + GIT_MERGE_DIFF_RENAMED_DELETED = (1 << 5), + + /* Occurs when a file is renamed in one branch and a file with the same + * name is added in the other. Eg, A->B and new file B. Core git calls + * this a "rename/delete". */ + GIT_MERGE_DIFF_RENAMED_ADDED = (1 << 6), + + /* Occurs when both a file is renamed to the same name in the ours and + * theirs branches. Eg, A->B and A->B in both. Automergeable. */ + GIT_MERGE_DIFF_BOTH_RENAMED = (1 << 7), + + /* Occurs when a file is renamed to different names in the ours and theirs + * branches. Eg, A->B and A->C. */ + GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2 = (1 << 8), + + /* Occurs when two files are renamed to the same name in the ours and + * theirs branches. Eg, A->C and B->C. */ + GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1 = (1 << 9), + + /* Occurs when an item at a path in one branch is a directory, and an + * item at the same path in a different branch is a file. */ + GIT_MERGE_DIFF_DIRECTORY_FILE = (1 << 10), + + /* The child of a folder that is in a directory/file conflict. */ + GIT_MERGE_DIFF_DF_CHILD = (1 << 11), +} git_merge_diff_type_t; + + +typedef struct { + git_repository *repo; + git_pool pool; + + /* Vector of git_index_entry that represent the merged items that + * have been staged, either because only one side changed, or because + * the two changes were non-conflicting and mergeable. These items + * will be written as staged entries in the main index. + */ + git_vector staged; + + /* Vector of git_merge_diff entries that represent the conflicts that + * have not been automerged. These items will be written to high-stage + * entries in the main index. + */ + git_vector conflicts; + + /* Vector of git_merge_diff that have been automerged. These items + * will be written to the REUC when the index is produced. + */ + git_vector resolved; +} git_merge_diff_list; + +/** + * Description of changes to one file across three trees. + */ +typedef struct { + git_merge_diff_type_t type; + + git_index_entry ancestor_entry; + + git_index_entry our_entry; + git_delta_t our_status; + + git_index_entry their_entry; + git_delta_t their_status; +} git_merge_diff; + +int git_merge__bases_many( + git_commit_list **out, + git_revwalk *walk, + git_commit_list_node *one, + git_vector *twos); + +git_merge_diff_list *git_merge_diff_list__alloc(git_repository *repo); + +int git_merge_diff_list__find_differences(git_merge_diff_list *merge_diff_list, + const git_tree *ancestor_tree, + const git_tree *ours_tree, + const git_tree *theirs_tree); + +int git_merge_diff_list__find_renames(git_repository *repo, git_merge_diff_list *merge_diff_list, const git_merge_tree_opts *opts); + +void git_merge_diff_list__free(git_merge_diff_list *diff_list); #endif diff --git a/src/merge_file.c b/src/merge_file.c new file mode 100644 index 000000000..4b3f3730b --- /dev/null +++ b/src/merge_file.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "common.h" +#include "repository.h" +#include "merge_file.h" + +#include "git2/repository.h" +#include "git2/object.h" +#include "git2/index.h" + +#include "xdiff/xdiff.h" + +#define GIT_MERGE_FILE_SIDE_EXISTS(X) ((X)->mode != 0) + +GIT_INLINE(const char *) merge_file_best_path( + const git_merge_file_input *ancestor, + const git_merge_file_input *ours, + const git_merge_file_input *theirs) +{ + if (!GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) { + if (strcmp(ours->path, theirs->path) == 0) + return ours->path; + + return NULL; + } + + if (strcmp(ancestor->path, ours->path) == 0) + return theirs->path; + else if(strcmp(ancestor->path, theirs->path) == 0) + return ours->path; + + return NULL; +} + +GIT_INLINE(int) merge_file_best_mode( + const git_merge_file_input *ancestor, + const git_merge_file_input *ours, + const git_merge_file_input *theirs) +{ + /* + * If ancestor didn't exist and either ours or theirs is executable, + * assume executable. Otherwise, if any mode changed from the ancestor, + * use that one. + */ + if (GIT_MERGE_FILE_SIDE_EXISTS(ancestor)) { + if (ours->mode == GIT_FILEMODE_BLOB_EXECUTABLE || + theirs->mode == GIT_FILEMODE_BLOB_EXECUTABLE) + return GIT_FILEMODE_BLOB_EXECUTABLE; + + return GIT_FILEMODE_BLOB; + } + + if (ancestor->mode == ours->mode) + return theirs->mode; + else if(ancestor->mode == theirs->mode) + return ours->mode; + + return 0; +} + +int git_merge_file_input_from_index_entry( + git_merge_file_input *input, + git_repository *repo, + const git_index_entry *entry) +{ + git_odb *odb = NULL; + int error = 0; + + assert(input && repo && entry); + + if (entry->mode == 0) + return 0; + + if ((error = git_repository_odb(&odb, repo)) < 0 || + (error = git_odb_read(&input->odb_object, odb, &entry->oid)) < 0) + goto done; + + input->mode = entry->mode; + input->path = git__strdup(entry->path); + input->mmfile.size = git_odb_object_size(input->odb_object); + input->mmfile.ptr = (char *)git_odb_object_data(input->odb_object); + + if (input->label == NULL) + input->label = entry->path; + +done: + git_odb_free(odb); + + return error; +} + +int git_merge_file_input_from_diff_file( + git_merge_file_input *input, + git_repository *repo, + const git_diff_file *file) +{ + git_odb *odb = NULL; + int error = 0; + + assert(input && repo && file); + + if (file->mode == 0) + return 0; + + if ((error = git_repository_odb(&odb, repo)) < 0 || + (error = git_odb_read(&input->odb_object, odb, &file->oid)) < 0) + goto done; + + input->mode = file->mode; + input->path = git__strdup(file->path); + input->mmfile.size = git_odb_object_size(input->odb_object); + input->mmfile.ptr = (char *)git_odb_object_data(input->odb_object); + + if (input->label == NULL) + input->label = file->path; + +done: + git_odb_free(odb); + + return error; +} + +int git_merge_files( + git_merge_file_result *out, + git_merge_file_input *ancestor, + git_merge_file_input *ours, + git_merge_file_input *theirs, + git_merge_automerge_flags flags) +{ + xmparam_t xmparam; + mmbuffer_t mmbuffer; + int xdl_result; + int error = 0; + + assert(out && ancestor && ours && theirs); + + memset(out, 0x0, sizeof(git_merge_file_result)); + + if (!GIT_MERGE_FILE_SIDE_EXISTS(ours) || !GIT_MERGE_FILE_SIDE_EXISTS(theirs)) + return 0; + + memset(&xmparam, 0x0, sizeof(xmparam_t)); + xmparam.ancestor = ancestor->label; + xmparam.file1 = ours->label; + xmparam.file2 = theirs->label; + + out->path = merge_file_best_path(ancestor, ours, theirs); + out->mode = merge_file_best_mode(ancestor, ours, theirs); + + if (flags == GIT_MERGE_AUTOMERGE_FAVOR_OURS) + xmparam.favor = XDL_MERGE_FAVOR_OURS; + + if (flags == GIT_MERGE_AUTOMERGE_FAVOR_THEIRS) + xmparam.favor = XDL_MERGE_FAVOR_THEIRS; + + if ((xdl_result = xdl_merge(&ancestor->mmfile, &ours->mmfile, + &theirs->mmfile, &xmparam, &mmbuffer)) < 0) { + giterr_set(GITERR_MERGE, "Failed to merge files."); + error = -1; + goto done; + } + + out->automergeable = (xdl_result == 0); + out->data = (unsigned char *)mmbuffer.ptr; + out->len = mmbuffer.size; + +done: + return error; +} + diff --git a/src/merge_file.h b/src/merge_file.h new file mode 100644 index 000000000..1aa34893d --- /dev/null +++ b/src/merge_file.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_filediff_h__ +#define INCLUDE_filediff_h__ + +#include "xdiff/xdiff.h" + +#include "git2/merge.h" + +typedef struct { + const char *label; + char *path; + unsigned int mode; + mmfile_t mmfile; + + git_odb_object *odb_object; +} git_merge_file_input; + +#define GIT_MERGE_FILE_INPUT_INIT {0} + +typedef struct { + bool automergeable; + + const char *path; + int mode; + + unsigned char *data; + size_t len; +} git_merge_file_result; + +#define GIT_MERGE_FILE_RESULT_INIT {0} + +int git_merge_file_input_from_index_entry( + git_merge_file_input *input, + git_repository *repo, + const git_index_entry *entry); + +int git_merge_file_input_from_diff_file( + git_merge_file_input *input, + git_repository *repo, + const git_diff_file *file); + +int git_merge_files( + git_merge_file_result *out, + git_merge_file_input *ancestor, + git_merge_file_input *ours, + git_merge_file_input *theirs, + git_merge_automerge_flags flags); + +GIT_INLINE(void) git_merge_file_input_free(git_merge_file_input *input) +{ + assert(input); + git__free(input->path); + git_odb_object_free(input->odb_object); +} + +GIT_INLINE(void) git_merge_file_result_free(git_merge_file_result *filediff) +{ + if (filediff == NULL) + return; + + /* xdiff uses malloc() not git_malloc, so we use free(), not git_free() */ + if (filediff->data != NULL) + free(filediff->data); +} + +#endif diff --git a/tests-clar/merge/merge_helpers.c b/tests-clar/merge/merge_helpers.c new file mode 100644 index 000000000..b10e9ec32 --- /dev/null +++ b/tests-clar/merge/merge_helpers.c @@ -0,0 +1,224 @@ +#include "clar_libgit2.h" +#include "buffer.h" +#include "refs.h" +#include "tree.h" +#include "merge_helpers.h" +#include "merge.h" +#include "git2/merge.h" + +int merge_trees_from_branches( + git_index **index, git_repository *repo, + const char *ours_name, const char *theirs_name, + git_merge_tree_opts *opts) +{ + git_commit *our_commit, *their_commit, *ancestor_commit = NULL; + git_tree *our_tree, *their_tree, *ancestor_tree = NULL; + git_oid our_oid, their_oid, ancestor_oid; + git_buf branch_buf = GIT_BUF_INIT; + int error; + + git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours_name); + cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr)); + cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); + + git_buf_clear(&branch_buf); + git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs_name); + cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr)); + cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid)); + + error = git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit)); + + if (error != GIT_ENOTFOUND) { + cl_git_pass(error); + + cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); + cl_git_pass(git_commit_tree(&ancestor_tree, ancestor_commit)); + } + + cl_git_pass(git_commit_tree(&our_tree, our_commit)); + cl_git_pass(git_commit_tree(&their_tree, their_commit)); + + cl_git_pass(git_merge_trees(index, repo, ancestor_tree, our_tree, their_tree, opts)); + + git_buf_free(&branch_buf); + git_tree_free(our_tree); + git_tree_free(their_tree); + git_tree_free(ancestor_tree); + git_commit_free(our_commit); + git_commit_free(their_commit); + git_commit_free(ancestor_commit); + + return 0; +} + +static int index_entry_eq_merge_index_entry(const struct merge_index_entry *expected, const git_index_entry *actual) +{ + git_oid expected_oid; + bool test_oid; + + if (strlen(expected->oid_str) != 0) { + cl_git_pass(git_oid_fromstr(&expected_oid, expected->oid_str)); + test_oid = 1; + } else + test_oid = 0; + + if (actual->mode != expected->mode || + (test_oid && git_oid_cmp(&actual->oid, &expected_oid) != 0) || + git_index_entry_stage(actual) != expected->stage) + return 0; + + if (actual->mode == 0 && (actual->path != NULL || strlen(expected->path) > 0)) + return 0; + + if (actual->mode != 0 && (strcmp(actual->path, expected->path) != 0)) + return 0; + + return 1; +} + +static int name_entry_eq(const char *expected, const char *actual) +{ + if (strlen(expected) == 0) + return (actual == NULL) ? 1 : 0; + + return (strcmp(expected, actual) == 0) ? 1 : 0; +} + +static int index_conflict_data_eq_merge_diff(const struct merge_index_conflict_data *expected, git_merge_diff *actual) +{ + if (!index_entry_eq_merge_index_entry((const struct merge_index_entry *)&expected->ancestor, &actual->ancestor_entry) || + !index_entry_eq_merge_index_entry((const struct merge_index_entry *)&expected->ours, &actual->our_entry) || + !index_entry_eq_merge_index_entry((const struct merge_index_entry *)&expected->theirs, &actual->their_entry)) + return 0; + + if (expected->ours.status != actual->our_status || + expected->theirs.status != actual->their_status) + return 0; + + return 1; +} + +int merge_test_merge_conflicts(git_vector *conflicts, const struct merge_index_conflict_data expected[], size_t expected_len) +{ + git_merge_diff *actual; + size_t i; + + if (conflicts->length != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + actual = conflicts->contents[i]; + + if (!index_conflict_data_eq_merge_diff(&expected[i], actual)) + return 0; + } + + return 1; +} + +int merge_test_index(git_index *index, const struct merge_index_entry expected[], size_t expected_len) +{ + size_t i; + const git_index_entry *index_entry; + + /* + dump_index_entries(&index->entries); + */ + + if (git_index_entrycount(index) != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + if ((index_entry = git_index_get_byindex(index, i)) == NULL) + return 0; + + if (!index_entry_eq_merge_index_entry(&expected[i], index_entry)) + return 0; + } + + return 1; +} + +int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], size_t expected_len) +{ + size_t i; + const git_index_reuc_entry *reuc_entry; + git_oid expected_oid; + + /* + dump_reuc(index); + */ + + if (git_index_reuc_entrycount(index) != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + if ((reuc_entry = git_index_reuc_get_byindex(index, i)) == NULL) + return 0; + + if (strcmp(reuc_entry->path, expected[i].path) != 0 || + reuc_entry->mode[0] != expected[i].ancestor_mode || + reuc_entry->mode[1] != expected[i].our_mode || + reuc_entry->mode[2] != expected[i].their_mode) + return 0; + + if (expected[i].ancestor_mode > 0) { + cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].ancestor_oid_str)); + + if (git_oid_cmp(&reuc_entry->oid[0], &expected_oid) != 0) + return 0; + } + + if (expected[i].our_mode > 0) { + cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].our_oid_str)); + + if (git_oid_cmp(&reuc_entry->oid[1], &expected_oid) != 0) + return 0; + } + + if (expected[i].their_mode > 0) { + cl_git_pass(git_oid_fromstr(&expected_oid, expected[i].their_oid_str)); + + if (git_oid_cmp(&reuc_entry->oid[2], &expected_oid) != 0) + return 0; + } + } + + return 1; +} + +int dircount(void *payload, git_buf *pathbuf) +{ + int *entries = payload; + size_t len = git_buf_len(pathbuf); + + if (len < 5 || strcmp(pathbuf->ptr + (git_buf_len(pathbuf) - 5), "/.git") != 0) + (*entries)++; + + return 0; +} + +int merge_test_workdir(git_repository *repo, const struct merge_index_entry expected[], size_t expected_len) +{ + size_t actual_len = 0, i; + git_oid actual_oid, expected_oid; + git_buf wd = GIT_BUF_INIT; + + git_buf_puts(&wd, repo->workdir); + git_path_direach(&wd, dircount, &actual_len); + + if (actual_len != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + git_blob_create_fromworkdir(&actual_oid, repo, expected[i].path); + git_oid_fromstr(&expected_oid, expected[i].oid_str); + + if (git_oid_cmp(&actual_oid, &expected_oid) != 0) + return 0; + } + + git_buf_free(&wd); + + return 1; +} diff --git a/tests-clar/merge/merge_helpers.h b/tests-clar/merge/merge_helpers.h new file mode 100644 index 000000000..1a0b8921b --- /dev/null +++ b/tests-clar/merge/merge_helpers.h @@ -0,0 +1,62 @@ +#ifndef INCLUDE_cl_merge_helpers_h__ +#define INCLUDE_cl_merge_helpers_h__ + +#include "merge.h" +#include "git2/merge.h" + +struct merge_index_entry { + uint16_t mode; + char oid_str[41]; + int stage; + char path[128]; +}; + +struct merge_name_entry { + char ancestor_path[128]; + char our_path[128]; + char their_path[128]; +}; + +struct merge_index_with_status { + uint16_t mode; + char oid_str[41]; + int stage; + char path[128]; + unsigned int status; +}; + +struct merge_reuc_entry { + char path[128]; + unsigned int ancestor_mode; + unsigned int our_mode; + unsigned int their_mode; + char ancestor_oid_str[41]; + char our_oid_str[41]; + char their_oid_str[41]; +}; + +struct merge_index_conflict_data { + struct merge_index_with_status ancestor; + struct merge_index_with_status ours; + struct merge_index_with_status theirs; + git_merge_diff_type_t change_type; +}; + +int merge_trees_from_branches( + git_index **index, git_repository *repo, + const char *ours_name, const char *theirs_name, + git_merge_tree_opts *opts); + +int merge_test_diff_list(git_merge_diff_list *diff_list, const struct merge_index_entry expected[], size_t expected_len); + +int merge_test_merge_conflicts(git_vector *conflicts, const struct merge_index_conflict_data expected[], size_t expected_len); + +int merge_test_index(git_index *index, const struct merge_index_entry expected[], size_t expected_len); + +int merge_test_names(git_index *index, const struct merge_name_entry expected[], size_t expected_len); + +int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], size_t expected_len); + +int merge_test_workdir(git_repository *repo, const struct merge_index_entry expected[], size_t expected_len); + +#endif diff --git a/tests-clar/merge/trees/automerge.c b/tests-clar/merge/trees/automerge.c new file mode 100644 index 000000000..7592a926e --- /dev/null +++ b/tests-clar/merge/trees/automerge.c @@ -0,0 +1,217 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "buffer.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "fileops.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + +#define THEIRS_AUTOMERGE_BRANCH "branch" + +#define THEIRS_UNRELATED_BRANCH "unrelated" +#define THEIRS_UNRELATED_OID "55b4e4687e7a0d9ca367016ed930f385d4022e6f" +#define THEIRS_UNRELATED_PARENT "d6cf6c7741b3316826af1314042550c97ded1d50" + +#define OURS_DIRECTORY_FILE "df_side1" +#define THEIRS_DIRECTORY_FILE "df_side2" + +/* Non-conflicting files, index entries are common to every merge operation */ +#define ADDED_IN_MASTER_INDEX_ENTRY \ + { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" } +#define AUTOMERGEABLE_INDEX_ENTRY \ + { 0100644, "f2e1550a0c9e53d5811175864a29536642ae3821", 0, "automergeable.txt" } +#define CHANGED_IN_BRANCH_INDEX_ENTRY \ + { 0100644, "4eb04c9e79e88f6640d01ff5b25ca2a60764f216", 0, "changed-in-branch.txt" } +#define CHANGED_IN_MASTER_INDEX_ENTRY \ + { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" } +#define UNCHANGED_INDEX_ENTRY \ + { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" } + +/* Expected REUC entries */ +#define AUTOMERGEABLE_REUC_ENTRY \ + { "automergeable.txt", 0100644, 0100644, 0100644, \ + "6212c31dab5e482247d7977e4f0dd3601decf13b", \ + "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", \ + "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe" } +#define CONFLICTING_REUC_ENTRY \ + { "conflicting.txt", 0100644, 0100644, 0100644, \ + "d427e0b2e138501a3d15cc376077a3631e15bd46", \ + "4e886e602529caa9ab11d71f86634bd1b6e0de10", \ + "2bd0a343aeef7a2cf0d158478966a6e587ff3863" } +#define REMOVED_IN_BRANCH_REUC_ENTRY \ + { "removed-in-branch.txt", 0100644, 0100644, 0, \ + "dfe3f22baa1f6fce5447901c3086bae368de6bdd", \ + "dfe3f22baa1f6fce5447901c3086bae368de6bdd", \ + "" } +#define REMOVED_IN_MASTER_REUC_ENTRY \ + { "removed-in-master.txt", 0100644, 0, 0100644, \ + "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", \ + "", \ + "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5" } + +#define AUTOMERGEABLE_MERGED_FILE \ + "this file is changed in master\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is automergeable\n" \ + "this file is changed in branch\n" + +#define AUTOMERGEABLE_MERGED_FILE_CRLF \ + "this file is changed in master\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is automergeable\r\n" \ + "this file is changed in branch\r\n" + +// Fixture setup and teardown +void test_merge_trees_automerge__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_automerge__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_merge_trees_automerge__automerge(void) +{ + git_index *index; + const git_index_entry *entry; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + git_blob *blob; + + struct merge_index_entry merge_index_entries[] = { + ADDED_IN_MASTER_INDEX_ENTRY, + AUTOMERGEABLE_INDEX_ENTRY, + CHANGED_IN_BRANCH_INDEX_ENTRY, + CHANGED_IN_MASTER_INDEX_ENTRY, + + { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 1, "conflicting.txt" }, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 2, "conflicting.txt" }, + { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 3, "conflicting.txt" }, + + UNCHANGED_INDEX_ENTRY, + }; + + struct merge_reuc_entry merge_reuc_entries[] = { + AUTOMERGEABLE_REUC_ENTRY, + REMOVED_IN_BRANCH_REUC_ENTRY, + REMOVED_IN_MASTER_REUC_ENTRY + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 8)); + cl_assert(merge_test_reuc(index, merge_reuc_entries, 3)); + + cl_assert((entry = git_index_get_bypath(index, "automergeable.txt", 0)) != NULL); + cl_assert(entry->file_size == strlen(AUTOMERGEABLE_MERGED_FILE)); + + cl_git_pass(git_object_lookup((git_object **)&blob, repo, &entry->oid, GIT_OBJ_BLOB)); + cl_assert(memcmp(git_blob_rawcontent(blob), AUTOMERGEABLE_MERGED_FILE, entry->file_size) == 0); + + git_index_free(index); + git_blob_free(blob); +} + +void test_merge_trees_automerge__favor_ours(void) +{ + git_index *index; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + ADDED_IN_MASTER_INDEX_ENTRY, + AUTOMERGEABLE_INDEX_ENTRY, + CHANGED_IN_BRANCH_INDEX_ENTRY, + CHANGED_IN_MASTER_INDEX_ENTRY, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, + UNCHANGED_INDEX_ENTRY, + }; + + struct merge_reuc_entry merge_reuc_entries[] = { + AUTOMERGEABLE_REUC_ENTRY, + CONFLICTING_REUC_ENTRY, + REMOVED_IN_BRANCH_REUC_ENTRY, + REMOVED_IN_MASTER_REUC_ENTRY, + }; + + opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_OURS; + + cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + cl_assert(merge_test_reuc(index, merge_reuc_entries, 4)); + + git_index_free(index); +} + +void test_merge_trees_automerge__favor_theirs(void) +{ + git_index *index; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + ADDED_IN_MASTER_INDEX_ENTRY, + AUTOMERGEABLE_INDEX_ENTRY, + CHANGED_IN_BRANCH_INDEX_ENTRY, + CHANGED_IN_MASTER_INDEX_ENTRY, + { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 0, "conflicting.txt" }, + UNCHANGED_INDEX_ENTRY, + }; + + struct merge_reuc_entry merge_reuc_entries[] = { + AUTOMERGEABLE_REUC_ENTRY, + CONFLICTING_REUC_ENTRY, + REMOVED_IN_BRANCH_REUC_ENTRY, + REMOVED_IN_MASTER_REUC_ENTRY, + }; + + opts.automerge_flags = GIT_MERGE_AUTOMERGE_FAVOR_THEIRS; + + cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_AUTOMERGE_BRANCH, &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 6)); + cl_assert(merge_test_reuc(index, merge_reuc_entries, 4)); + + git_index_free(index); +} + +void test_merge_trees_automerge__unrelated(void) +{ + git_index *index; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, + { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 2, "automergeable.txt" }, + { 0100644, "d07ec190c306ec690bac349e87d01c4358e49bb2", 3, "automergeable.txt" }, + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, + { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 2, "conflicting.txt" }, + { 0100644, "4b253da36a0ae8bfce63aeabd8c5b58429925594", 3, "conflicting.txt" }, + { 0100644, "ef58fdd8086c243bdc81f99e379acacfd21d32d6", 0, "new-in-unrelated1.txt" }, + { 0100644, "948ba6e701c1edab0c2d394fb7c5538334129793", 0, "new-in-unrelated2.txt" }, + { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, + { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, "master", THEIRS_UNRELATED_BRANCH, &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 11)); + + git_index_free(index); +} diff --git a/tests-clar/merge/trees/modeconflict.c b/tests-clar/merge/trees/modeconflict.c new file mode 100644 index 000000000..0661ce5b3 --- /dev/null +++ b/tests-clar/merge/trees/modeconflict.c @@ -0,0 +1,59 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "buffer.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "fileops.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" + +#define DF_SIDE1_BRANCH "df_side1" +#define DF_SIDE2_BRANCH "df_side2" + +// Fixture setup and teardown +void test_merge_trees_modeconflict__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_modeconflict__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_merge_trees_modeconflict__df_conflict(void) +{ + git_index *index; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "49130a28ef567af9a6a6104c38773fedfa5f9742", 2, "dir-10" }, + { 0100644, "6c06dcd163587c2cc18be44857e0b71116382aeb", 3, "dir-10" }, + { 0100644, "43aafd43bea779ec74317dc361f45ae3f532a505", 0, "dir-6" }, + { 0100644, "a031a28ae70e33a641ce4b8a8f6317f1ab79dee4", 3, "dir-7" }, + { 0100644, "5012fd565b1393bdfda1805d4ec38ce6619e1fd1", 1, "dir-7/file.txt" }, + { 0100644, "a5563304ddf6caba25cb50323a2ea6f7dbfcadca", 2, "dir-7/file.txt" }, + { 0100644, "e9ad6ec3e38364a3d07feda7c4197d4d845c53b5", 0, "dir-8" }, + { 0100644, "3ef4d30382ca33fdeba9fda895a99e0891ba37aa", 2, "dir-9" }, + { 0100644, "fc4c636d6515e9e261f9260dbcf3cc6eca97ea08", 1, "dir-9/file.txt" }, + { 0100644, "76ab0e2868197ec158ddd6c78d8a0d2fd73d38f9", 3, "dir-9/file.txt" }, + { 0100644, "5c2411f8075f48a6b2fdb85ebc0d371747c4df15", 0, "file-1/new" }, + { 0100644, "a39a620dae5bc8b4e771cd4d251b7d080401a21e", 1, "file-2" }, + { 0100644, "d963979c237d08b6ba39062ee7bf64c7d34a27f8", 2, "file-2" }, + { 0100644, "5c341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d", 0, "file-2/new" }, + { 0100644, "9efe7723802d4305142eee177e018fee1572c4f4", 0, "file-3/new" }, + { 0100644, "bacac9b3493509aa15e1730e1545fc0919d1dae0", 1, "file-4" }, + { 0100644, "7663fce0130db092936b137cabd693ec234eb060", 3, "file-4" }, + { 0100644, "e49f917b448d1340b31d76e54ba388268fd4c922", 0, "file-4/new" }, + { 0100644, "cab2cf23998b40f1af2d9d9a756dc9e285a8df4b", 2, "file-5/new" }, + { 0100644, "f5504f36e6f4eb797a56fc5bac6c6c7f32969bf2", 3, "file-5/new" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, DF_SIDE1_BRANCH, DF_SIDE2_BRANCH, NULL)); + + cl_assert(merge_test_index(index, merge_index_entries, 20)); + + git_index_free(index); +} diff --git a/tests-clar/merge/trees/treediff.c b/tests-clar/merge/trees/treediff.c new file mode 100644 index 000000000..b2554f8be --- /dev/null +++ b/tests-clar/merge/trees/treediff.c @@ -0,0 +1,279 @@ +#include "clar_libgit2.h" +#include "git2/tree.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "diff.h" +#include "hashsig.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" + +#define TREE_OID_ANCESTOR "0d52e3a556e189ba0948ae56780918011c1b167d" +#define TREE_OID_MASTER "1f81433e3161efbf250576c58fede7f6b836f3d3" +#define TREE_OID_BRANCH "eea9286df54245fea72c5b557291470eb825f38f" + +#define TREE_OID_DF_ANCESTOR "b8a3a806d3950e8c0a03a34f234a92eff0e2c68d" +#define TREE_OID_DF_SIDE1 "ee1d6f164893c1866a323f072eeed36b855656be" +#define TREE_OID_DF_SIDE2 "6178885b38fe96e825ac0f492c0a941f288b37f6" + +void test_merge_trees_treediff__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_treediff__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +struct treediff_cb_data { + struct merge_index_conflict_data *conflict_data; + size_t conflict_data_len; + + size_t idx; +}; + +static void test_find_differences( + const char *ancestor_oidstr, + const char *ours_oidstr, + const char *theirs_oidstr, + struct merge_index_conflict_data *treediff_conflict_data, + size_t treediff_conflict_data_len) +{ + git_merge_diff_list *merge_diff_list = git_merge_diff_list__alloc(repo); + git_oid ancestor_oid, ours_oid, theirs_oid; + git_tree *ancestor_tree, *ours_tree, *theirs_tree; + struct treediff_cb_data treediff_cb_data = {0}; + + cl_git_pass(git_oid_fromstr(&ancestor_oid, ancestor_oidstr)); + cl_git_pass(git_oid_fromstr(&ours_oid, ours_oidstr)); + cl_git_pass(git_oid_fromstr(&theirs_oid, theirs_oidstr)); + + cl_git_pass(git_tree_lookup(&ancestor_tree, repo, &ancestor_oid)); + cl_git_pass(git_tree_lookup(&ours_tree, repo, &ours_oid)); + cl_git_pass(git_tree_lookup(&theirs_tree, repo, &theirs_oid)); + + cl_git_pass(git_merge_diff_list__find_differences(merge_diff_list, ancestor_tree, ours_tree, theirs_tree)); + + /* + dump_merge_index(merge_index); + */ + + cl_assert(treediff_conflict_data_len == merge_diff_list->conflicts.length); + + treediff_cb_data.conflict_data = treediff_conflict_data; + treediff_cb_data.conflict_data_len = treediff_conflict_data_len; + + cl_assert(merge_test_merge_conflicts(&merge_diff_list->conflicts, treediff_conflict_data, treediff_conflict_data_len)); + + git_tree_free(ancestor_tree); + git_tree_free(ours_tree); + git_tree_free(theirs_tree); + + git_merge_diff_list__free(merge_diff_list); +} + +void test_merge_trees_treediff__simple(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt", GIT_DELTA_ADDED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE + }, + + { + { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt", GIT_DELTA_MODIFIED }, + { 0100644, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe", 0, "automergeable.txt", GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_BOTH_MODIFIED + }, + + { + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "4eb04c9e79e88f6640d01ff5b25ca2a60764f216", 0, "changed-in-branch.txt", GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_NONE + }, + + { + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt", GIT_DELTA_MODIFIED }, + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE + }, + + { + { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt", GIT_DELTA_MODIFIED }, + { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 0, "conflicting.txt", GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_BOTH_MODIFIED + }, + + { + { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_NONE + }, + + { + { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE + }, + }; + + test_find_differences(TREE_OID_ANCESTOR, TREE_OID_MASTER, TREE_OID_BRANCH, treediff_conflict_data, 7); +} + +void test_merge_trees_treediff__df_conflicts(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "49130a28ef567af9a6a6104c38773fedfa5f9742", 0, "dir-10", GIT_DELTA_ADDED }, + { 0100644, "6c06dcd163587c2cc18be44857e0b71116382aeb", 0, "dir-10", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_BOTH_ADDED, + }, + + { + { 0100644, "242591eb280ee9eeb2ce63524b9a8b9bc4cb515d", 0, "dir-10/file.txt", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_BOTH_DELETED, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "43aafd43bea779ec74317dc361f45ae3f532a505", 0, "dir-6", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "a031a28ae70e33a641ce4b8a8f6317f1ab79dee4", 0, "dir-7", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_DIRECTORY_FILE, + }, + + { + { 0100644, "5012fd565b1393bdfda1805d4ec38ce6619e1fd1", 0, "dir-7/file.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "a5563304ddf6caba25cb50323a2ea6f7dbfcadca", 0, "dir-7/file.txt", GIT_DELTA_MODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_DF_CHILD, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "e9ad6ec3e38364a3d07feda7c4197d4d845c53b5", 0, "dir-8", GIT_DELTA_ADDED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "3ef4d30382ca33fdeba9fda895a99e0891ba37aa", 0, "dir-9", GIT_DELTA_ADDED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_DIRECTORY_FILE, + }, + + { + { 0100644, "fc4c636d6515e9e261f9260dbcf3cc6eca97ea08", 0, "dir-9/file.txt", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0100644, "76ab0e2868197ec158ddd6c78d8a0d2fd73d38f9", 0, "dir-9/file.txt", GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_DF_CHILD, + }, + + { + { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1", GIT_DELTA_UNMODIFIED }, + { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "5c2411f8075f48a6b2fdb85ebc0d371747c4df15", 0, "file-1/new", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "a39a620dae5bc8b4e771cd4d251b7d080401a21e", 0, "file-2", GIT_DELTA_UNMODIFIED }, + { 0100644, "d963979c237d08b6ba39062ee7bf64c7d34a27f8", 0, "file-2", GIT_DELTA_MODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_DIRECTORY_FILE, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "5c341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d", 0, "file-2/new", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_DF_CHILD, + }, + + { + { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "9efe7723802d4305142eee177e018fee1572c4f4", 0, "file-3/new", GIT_DELTA_ADDED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "bacac9b3493509aa15e1730e1545fc0919d1dae0", 0, "file-4", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0100644, "7663fce0130db092936b137cabd693ec234eb060", 0, "file-4", GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_DIRECTORY_FILE, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "e49f917b448d1340b31d76e54ba388268fd4c922", 0, "file-4/new", GIT_DELTA_ADDED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_DF_CHILD, + }, + + { + { 0100644, "ac4045f965119e6998f4340ed0f411decfb3ec05", 0, "file-5", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_BOTH_DELETED, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "cab2cf23998b40f1af2d9d9a756dc9e285a8df4b", 0, "file-5/new", GIT_DELTA_ADDED }, + { 0100644, "f5504f36e6f4eb797a56fc5bac6c6c7f32969bf2", 0, "file-5/new", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_BOTH_ADDED, + }, + }; + + test_find_differences(TREE_OID_DF_ANCESTOR, TREE_OID_DF_SIDE1, TREE_OID_DF_SIDE2, treediff_conflict_data, 20); +} + diff --git a/tests-clar/merge/trees/trivial.c b/tests-clar/merge/trees/trivial.c new file mode 100644 index 000000000..54b07e74a --- /dev/null +++ b/tests-clar/merge/trees/trivial.c @@ -0,0 +1,396 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "refs.h" +#include "fileops.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + + +// Fixture setup and teardown +void test_merge_trees_trivial__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_trivial__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + + +static int merge_trivial(git_index **index, const char *ours, const char *theirs, bool automerge) +{ + git_commit *our_commit, *their_commit, *ancestor_commit; + git_tree *our_tree, *their_tree, *ancestor_tree; + git_oid our_oid, their_oid, ancestor_oid; + git_buf branch_buf = GIT_BUF_INIT; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + opts.automerge_flags |= automerge ? 0 : GIT_MERGE_AUTOMERGE_NONE; + + git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, ours); + cl_git_pass(git_reference_name_to_id(&our_oid, repo, branch_buf.ptr)); + cl_git_pass(git_commit_lookup(&our_commit, repo, &our_oid)); + + git_buf_clear(&branch_buf); + git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs); + cl_git_pass(git_reference_name_to_id(&their_oid, repo, branch_buf.ptr)); + cl_git_pass(git_commit_lookup(&their_commit, repo, &their_oid)); + + cl_git_pass(git_merge_base(&ancestor_oid, repo, git_commit_id(our_commit), git_commit_id(their_commit))); + cl_git_pass(git_commit_lookup(&ancestor_commit, repo, &ancestor_oid)); + + cl_git_pass(git_commit_tree(&ancestor_tree, ancestor_commit)); + cl_git_pass(git_commit_tree(&our_tree, our_commit)); + cl_git_pass(git_commit_tree(&their_tree, their_commit)); + + cl_git_pass(git_merge_trees(index, repo, ancestor_tree, our_tree, their_tree, &opts)); + + git_buf_free(&branch_buf); + git_tree_free(our_tree); + git_tree_free(their_tree); + git_tree_free(ancestor_tree); + git_commit_free(our_commit); + git_commit_free(their_commit); + git_commit_free(ancestor_commit); + + return 0; +} + +static int merge_trivial_conflict_entrycount(git_index *index) +{ + const git_index_entry *entry; + size_t count = 0; + size_t i; + + for (i = 0; i < git_index_entrycount(index); i++) { + cl_assert(entry = git_index_get_byindex(index, i)); + + if (git_index_entry_stage(entry) > 0) + count++; + } + + return count; +} + +/* 2ALT: ancest:(empty)+, head:*empty*, remote:remote = result:remote */ +void test_merge_trees_trivial__2alt(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-2alt", "trivial-2alt-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "new-in-branch.txt", 0)); + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 3ALT: ancest:(empty)+, head:head, remote:*empty* = result:head */ +void test_merge_trees_trivial__3alt(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-3alt", "trivial-3alt-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "new-in-3alt.txt", 0)); + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 4: ancest:(empty)^, head:head, remote:remote = result:no merge */ +void test_merge_trees_trivial__4(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-4", "trivial-4-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "new-and-different.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "new-and-different.txt", 2)); + cl_assert(entry = git_index_get_bypath(result, "new-and-different.txt", 3)); + + git_index_free(result); +} + +/* 5ALT: ancest:*, head:head, remote:head = result:head */ +void test_merge_trees_trivial__5alt_1(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-5alt-1", "trivial-5alt-1-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "new-and-same.txt", 0)); + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 5ALT: ancest:*, head:head, remote:head = result:head */ +void test_merge_trees_trivial__5alt_2(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-5alt-2", "trivial-5alt-2-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "modified-to-same.txt", 0)); + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ +void test_merge_trees_trivial__6(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 1); + cl_assert(entry = git_index_get_bypath(result, "removed-in-both.txt", 1)); + + git_index_free(result); +} + +/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ +void test_merge_trees_trivial__6_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + const git_index_reuc_entry *reuc; + + cl_git_pass(merge_trivial(&result, "trivial-6", "trivial-6-branch", 1)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-both.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 1); + cl_assert(reuc = git_index_reuc_get_bypath(result, "removed-in-both.txt")); + + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ +void test_merge_trees_trivial__8(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-8.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-8.txt", 3)); + + git_index_free(result); +} + +/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ +void test_merge_trees_trivial__8_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + const git_index_reuc_entry *reuc; + + cl_git_pass(merge_trivial(&result, "trivial-8", "trivial-8-branch", 1)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-8.txt", 0)) == NULL); + + cl_assert(git_index_reuc_entrycount(result) == 1); + cl_assert(reuc = git_index_reuc_get_bypath(result, "removed-in-8.txt")); + + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */ +void test_merge_trees_trivial__7(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 3)); + + git_index_free(result); +} + +/* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */ +void test_merge_trees_trivial__7_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-7", "trivial-7-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-7.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-7.txt", 3)); + + git_index_free(result); +} + +/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ +void test_merge_trees_trivial__10(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 2)); + + git_index_free(result); +} + +/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ +void test_merge_trees_trivial__10_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + const git_index_reuc_entry *reuc; + + cl_git_pass(merge_trivial(&result, "trivial-10", "trivial-10-branch", 1)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-10-branch.txt", 0)) == NULL); + + cl_assert(git_index_reuc_entrycount(result) == 1); + cl_assert(reuc = git_index_reuc_get_bypath(result, "removed-in-10-branch.txt")); + + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */ +void test_merge_trees_trivial__9(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 2)); + + git_index_free(result); +} + +/* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */ +void test_merge_trees_trivial__9_automerge(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-9", "trivial-9-branch", 1)); + + cl_assert((entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 2); + cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "removed-in-9-branch.txt", 2)); + + git_index_free(result); +} + +/* 13: ancest:ancest+, head:head, remote:ancest = result:head */ +void test_merge_trees_trivial__13(void) +{ + git_index *result; + const git_index_entry *entry; + git_oid expected_oid; + + cl_git_pass(merge_trivial(&result, "trivial-13", "trivial-13-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "modified-in-13.txt", 0)); + cl_git_pass(git_oid_fromstr(&expected_oid, "1cff9ec6a47a537380dedfdd17c9e76d74259a2b")); + cl_assert(git_oid_cmp(&entry->oid, &expected_oid) == 0); + + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 14: ancest:ancest+, head:ancest, remote:remote = result:remote */ +void test_merge_trees_trivial__14(void) +{ + git_index *result; + const git_index_entry *entry; + git_oid expected_oid; + + cl_git_pass(merge_trivial(&result, "trivial-14", "trivial-14-branch", 0)); + + cl_assert(entry = git_index_get_bypath(result, "modified-in-14-branch.txt", 0)); + cl_git_pass(git_oid_fromstr(&expected_oid, "26153a3ff3649b6c2bb652d3f06878c6e0a172f9")); + cl_assert(git_oid_cmp(&entry->oid, &expected_oid) == 0); + + cl_assert(git_index_reuc_entrycount(result) == 0); + cl_assert(merge_trivial_conflict_entrycount(result) == 0); + + git_index_free(result); +} + +/* 11: ancest:ancest+, head:head, remote:remote = result:no merge */ +void test_merge_trees_trivial__11(void) +{ + git_index *result; + const git_index_entry *entry; + + cl_git_pass(merge_trivial(&result, "trivial-11", "trivial-11-branch", 0)); + + cl_assert((entry = git_index_get_bypath(result, "modified-in-both.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(result) == 0); + + cl_assert(merge_trivial_conflict_entrycount(result) == 3); + cl_assert(entry = git_index_get_bypath(result, "modified-in-both.txt", 1)); + cl_assert(entry = git_index_get_bypath(result, "modified-in-both.txt", 2)); + cl_assert(entry = git_index_get_bypath(result, "modified-in-both.txt", 3)); + + git_index_free(result); +} diff --git a/tests-clar/merge/setup.c b/tests-clar/merge/workdir/setup.c similarity index 85% rename from tests-clar/merge/setup.c rename to tests-clar/merge/workdir/setup.c index 946c67e7b..6ae9dbb14 100644 --- a/tests-clar/merge/setup.c +++ b/tests-clar/merge/workdir/setup.c @@ -32,15 +32,15 @@ static git_index *repo_index; #define OCTO5_OID "e4f618a2c3ed0669308735727df5ebf2447f022f" // Fixture setup and teardown -void test_merge_setup__initialize(void) +void test_merge_workdir_setup__initialize(void) { repo = cl_git_sandbox_init(TEST_REPO_PATH); - git_repository_index(&repo_index, repo); + git_repository_index(&repo_index, repo); } -void test_merge_setup__cleanup(void) +void test_merge_workdir_setup__cleanup(void) { - git_index_free(repo_index); + git_index_free(repo_index); cl_git_sandbox_cleanup(); } @@ -48,7 +48,8 @@ static void write_file_contents(const char *filename, const char *output) { git_buf file_path_buf = GIT_BUF_INIT; - git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo), filename); + git_buf_printf(&file_path_buf, "%s/%s", git_repository_path(repo), + filename); cl_git_rewritefile(file_path_buf.ptr, output); git_buf_free(&file_path_buf); @@ -72,7 +73,7 @@ static int merge_head_foreach_cb(const git_oid *oid, void *payload) return 0; } -void test_merge_setup__head_notfound(void) +void test_merge_workdir_setup__head_notfound(void) { int error; @@ -81,7 +82,7 @@ void test_merge_setup__head_notfound(void) cl_assert(error == GIT_ENOTFOUND); } -void test_merge_setup__head_invalid_oid(void) +void test_merge_workdir_setup__head_invalid_oid(void) { int error; @@ -92,7 +93,7 @@ void test_merge_setup__head_invalid_oid(void) cl_assert(error == -1); } -void test_merge_setup__head_foreach_nonewline(void) +void test_merge_workdir_setup__head_foreach_nonewline(void) { int error; @@ -103,7 +104,7 @@ void test_merge_setup__head_foreach_nonewline(void) cl_assert(error == -1); } -void test_merge_setup__head_foreach_one(void) +void test_merge_workdir_setup__head_foreach_one(void) { const char *expected = THEIRS_SIMPLE_OID; @@ -117,7 +118,7 @@ void test_merge_setup__head_foreach_one(void) cl_assert(cb_data.i == cb_data.len); } -void test_merge_setup__head_foreach_octopus(void) +void test_merge_workdir_setup__head_foreach_octopus(void) { const char *expected[] = { THEIRS_SIMPLE_OID, OCTO1_OID, OCTO2_OID, OCTO3_OID, OCTO4_OID, OCTO5_OID }; diff --git a/tests-clar/resources/merge-resolve/.gitted/COMMIT_EDITMSG b/tests-clar/resources/merge-resolve/.gitted/COMMIT_EDITMSG new file mode 100644 index 000000000..245b18a2c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/COMMIT_EDITMSG @@ -0,0 +1 @@ +rename conflict theirs diff --git a/tests-clar/resources/merge-resolve/.gitted/HEAD b/tests-clar/resources/merge-resolve/.gitted/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests-clar/resources/merge-resolve/.gitted/ORIG_HEAD b/tests-clar/resources/merge-resolve/.gitted/ORIG_HEAD new file mode 100644 index 000000000..4092d428f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/ORIG_HEAD @@ -0,0 +1 @@ +2392a2dacc9efb562b8635d6579fb458751c7c5b diff --git a/tests-clar/resources/merge-resolve/.gitted/config b/tests-clar/resources/merge-resolve/.gitted/config new file mode 100644 index 000000000..af107929f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true diff --git a/tests-clar/resources/merge-resolve/.gitted/description b/tests-clar/resources/merge-resolve/.gitted/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests-clar/resources/merge-resolve/.gitted/index b/tests-clar/resources/merge-resolve/.gitted/index new file mode 100644 index 0000000000000000000000000000000000000000..230eba9eb269af72a059d8017d293e3b375e751a GIT binary patch literal 624 zcmZ?q402{*U|<4b_P}(lB|w@1Ml&)nurmES{eyv_5h%|16(}VF#InjZoRTMJycOi~ z&i|ZmYW1eO(4?I~I58z9HAOcwPd7KQxFoemucV>`WEc>@%!AQTbAO_l`~98$!W{>= z{?|WHNd3E&BV{-5WS#R2f{CRi`MIe@>8XiHIjLY%VdlVSsCmE8%oALlGHC#i`gwZ z*0A#ER;PtNLNOOD1YqXDXsEe=(9G5H>&Qz`)jYLwwcvI6wq);%+aBB#VBk;A&r8e6 zOfJdHONY7?W)6&on)esYJgNJSKWVR$&p#L9K0(HyZP(+Bd)apxM2k{$^UFx_|35Ty z 1351563869 -0500 commit (initial): initial +c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563886 -0500 checkout: moving from master to branch +c607fc30883e335def28cd686b51f6cfa02b06ec 7cb63eed597130ba4abb87b3e544b85021905520 Edward Thomson 1351563965 -0500 commit: branch +7cb63eed597130ba4abb87b3e544b85021905520 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563968 -0500 checkout: moving from branch to master +c607fc30883e335def28cd686b51f6cfa02b06ec 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351564033 -0500 commit: master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351605785 -0500 checkout: moving from master to ff_branch +977c696519c5a3004c5f1d15d60c89dbeb8f235f 33d500f588fbbe65901d82b4e6b008e549064be0 Edward Thomson 1351605830 -0500 commit: fastforward +33d500f588fbbe65901d82b4e6b008e549064be0 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351605889 -0500 checkout: moving from ff_branch to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874933 -0500 checkout: moving from master to octo1 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 16f825815cfd20a07a75c71554e82d8eede0b061 Edward Thomson 1351874954 -0500 commit: octo1 +16f825815cfd20a07a75c71554e82d8eede0b061 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874957 -0500 checkout: moving from octo1 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874960 -0500 checkout: moving from master to octo2 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 158dc7bedb202f5b26502bf3574faa7f4238d56c Edward Thomson 1351874974 -0500 commit: octo2 +158dc7bedb202f5b26502bf3574faa7f4238d56c 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874976 -0500 checkout: moving from octo2 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874980 -0500 checkout: moving from master to octo3 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 50ce7d7d01217679e26c55939eef119e0c93e272 Edward Thomson 1351874998 -0500 commit: octo3 +50ce7d7d01217679e26c55939eef119e0c93e272 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875006 -0500 checkout: moving from octo3 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875010 -0500 checkout: moving from master to octo4 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875023 -0500 commit: octo4 +54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875031 -0500 checkout: moving from octo4 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875031 -0500 checkout: moving from master to octo5 +977c696519c5a3004c5f1d15d60c89dbeb8f235f e4f618a2c3ed0669308735727df5ebf2447f022f Edward Thomson 1351875041 -0500 commit: octo5 +e4f618a2c3ed0669308735727df5ebf2447f022f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875046 -0500 checkout: moving from octo5 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875046 -0500 checkout: moving from master to octo6 +977c696519c5a3004c5f1d15d60c89dbeb8f235f 4ca408a8c88655f7586a1b580be6fad138121e98 Edward Thomson 1351875057 -0500 commit: octo5 +4ca408a8c88655f7586a1b580be6fad138121e98 b6f610aef53bd343e6c96227de874c66f00ee8e8 Edward Thomson 1351875065 -0500 commit (amend): octo6 +b6f610aef53bd343e6c96227de874c66f00ee8e8 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875071 -0500 checkout: moving from octo6 to master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 4e0d9401aee78eb345a8685a859d37c8c3c0bbed Edward Thomson 1351875091 -0500 merge octo1 octo2 octo3 octo4: Merge made by the 'octopus' strategy. +4e0d9401aee78eb345a8685a859d37c8c3c0bbed 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875108 -0500 reset: moving to 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae +54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875584 -0500 reset: moving to 977c696519c5a3004c5f1d15d60c89dbeb8f235f +bd593285fc7fe4ca18ccdbabf027f5d689101452 33d500f588fbbe65901d82b4e6b008e549064be0 Edward Thomson 1351990193 -0500 checkout: moving from master to ff_branch +33d500f588fbbe65901d82b4e6b008e549064be0 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351990202 -0500 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1351990205 -0500 merge master: Fast-forward +bd593285fc7fe4ca18ccdbabf027f5d689101452 fd89f8cffb663ac89095a0f9764902e93ceaca6a Edward Thomson 1351990229 -0500 commit: fastforward +fd89f8cffb663ac89095a0f9764902e93ceaca6a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1351990233 -0500 checkout: moving from ff_branch to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352091703 -0600 checkout: moving from master to trivial-2alt +c607fc30883e335def28cd686b51f6cfa02b06ec c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352092411 -0600 checkout: moving from trivial-2alt to trivial-2alt-branch +c607fc30883e335def28cd686b51f6cfa02b06ec c9174cef549ec94ecbc43ef03cdc775b4950becb Edward Thomson 1352092434 -0600 commit: 2alt-branch +c9174cef549ec94ecbc43ef03cdc775b4950becb c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352092440 -0600 checkout: moving from trivial-2alt-branch to trivial-2alt +c607fc30883e335def28cd686b51f6cfa02b06ec 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352092452 -0600 commit: 2alt +bd593285fc7fe4ca18ccdbabf027f5d689101452 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352094476 -0600 checkout: moving from master to trivial-3alt +566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094547 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 5459c89aa0026d543ce8343bd89871bce543f9c2 Edward Thomson 1352094580 -0600 commit: 3alt +5459c89aa0026d543ce8343bd89871bce543f9c2 4c9fac0707f8d4195037ae5a681aa48626491541 Edward Thomson 1352094610 -0600 commit: 3alt-branch +4c9fac0707f8d4195037ae5a681aa48626491541 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352094620 -0600 checkout: moving from trivial-3alt to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352094752 -0600 checkout: moving from master to trivial-4 +566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094764 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352094815 -0600 commit: trivial-4 +cc3e3009134cb88014129fc8858d1101359e5e2f c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094843 -0600 checkout: moving from trivial-4 to trivial-4-branch +c607fc30883e335def28cd686b51f6cfa02b06ec 183310e30fb1499af8c619108ffea4d300b5e778 Edward Thomson 1352094856 -0600 commit: trivial-4-branch +183310e30fb1499af8c619108ffea4d300b5e778 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352094860 -0600 checkout: moving from trivial-4-branch to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352096588 -0600 checkout: moving from master to trivial-4 +cc3e3009134cb88014129fc8858d1101359e5e2f c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096612 -0600 checkout: moving from trivial-4 to trivial-5alt-1 +c607fc30883e335def28cd686b51f6cfa02b06ec 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096643 -0600 commit: 5alt-1 +4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096661 -0600 checkout: moving from trivial-5alt-1 to trivial-5alt-1-branch +c607fc30883e335def28cd686b51f6cfa02b06ec 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096671 -0600 checkout: moving from trivial-5alt-1-branch to trivial-5alt-1 +4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096678 -0600 checkout: moving from trivial-5alt-1 to trivial-5alt-1-branch +c607fc30883e335def28cd686b51f6cfa02b06ec 478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 Edward Thomson 1352096689 -0600 commit: 5alt-1-branch +478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096701 -0600 checkout: moving from trivial-5alt-1-branch to trivial-5alt-1 +4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096715 -0600 checkout: moving from trivial-5alt-1 to trivial-5alt-2 +c607fc30883e335def28cd686b51f6cfa02b06ec ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096764 -0600 commit: existing file +ebc09d0137cfb0c26697aed0109fb943ad906f3f 3b47b031b3e55ae11e14a05260b1c3ffd6838d55 Edward Thomson 1352096815 -0600 commit: 5alt-2 +3b47b031b3e55ae11e14a05260b1c3ffd6838d55 ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096840 -0600 checkout: moving from trivial-5alt-2 to trivial-5alt-2-branch +ebc09d0137cfb0c26697aed0109fb943ad906f3f f48097eb340dc5a7cae55aabcf1faf4548aa821f Edward Thomson 1352096855 -0600 commit: 5alt-2-branch +f48097eb340dc5a7cae55aabcf1faf4548aa821f bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352096858 -0600 checkout: moving from trivial-5alt-2-branch to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352097377 -0600 checkout: moving from master to trivial-6 +c607fc30883e335def28cd686b51f6cfa02b06ec f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097389 -0600 commit: 6 +f7c332bd4d4d4b777366cae4d24d1687477576bf 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 Edward Thomson 1352097404 -0600 commit: trivial-6 +99b4f7e4f24470fa06b980bc21f1095c2a9425c0 f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097420 -0600 checkout: moving from trivial-6 to trivial-6-branch +f7c332bd4d4d4b777366cae4d24d1687477576bf a43150a738849c59376cf30bb2a68348a83c8f48 Edward Thomson 1352097431 -0600 commit: 6-branch +a43150a738849c59376cf30bb2a68348a83c8f48 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352097442 -0600 checkout: moving from trivial-6-branch to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 Edward Thomson 1352098040 -0600 checkout: moving from master to trivial-6 +99b4f7e4f24470fa06b980bc21f1095c2a9425c0 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352098057 -0600 checkout: moving from trivial-6 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352098792 -0600 checkout: moving from master to trivial-4 +cc3e3009134cb88014129fc8858d1101359e5e2f c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352098818 -0600 checkout: moving from trivial-4 to trivial-8 +c607fc30883e335def28cd686b51f6cfa02b06ec 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098884 -0600 commit: trivial-8 +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098947 -0600 checkout: moving from trivial-8 to trivial-8-branch +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 Edward Thomson 1352098979 -0600 commit: trivial-8-branch +52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098982 -0600 checkout: moving from trivial-8-branch to trivial-8 +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 3575826c96a975031d2c14368529cc5c4353a8fd Edward Thomson 1352099000 -0600 commit: trivial-8 +3575826c96a975031d2c14368529cc5c4353a8fd bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352099008 -0600 checkout: moving from trivial-8 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352099776 -0600 checkout: moving from master to trivial-7 +c607fc30883e335def28cd686b51f6cfa02b06ec 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099790 -0600 commit: trivial-7 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099799 -0600 checkout: moving from trivial-7 to trivial-7-branch +092ce8682d7f3a2a3a769a6daca58950168ba5c4 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c Edward Thomson 1352099812 -0600 commit: trivial-7-branch +73cbfdc4fe843169e5b2af8dcad03cbf3acf306c 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099815 -0600 checkout: moving from trivial-7-branch to trivial-7 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c Edward Thomson 1352099838 -0600 checkout: moving from trivial-7 to trivial-7-branch +73cbfdc4fe843169e5b2af8dcad03cbf3acf306c 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099874 -0600 reset: moving to 092ce8682d7f3a2a3a769a6daca58950168ba5c4 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 009b9cab6fdac02915a88ecd078b7a792ed802d8 Edward Thomson 1352099921 -0600 commit: removed in 7 +009b9cab6fdac02915a88ecd078b7a792ed802d8 5195a1b480f66691b667f10a9e41e70115a78351 Edward Thomson 1352099927 -0600 commit (amend): trivial-7-branch +5195a1b480f66691b667f10a9e41e70115a78351 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099937 -0600 checkout: moving from trivial-7-branch to trivial-7 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 d874671ef5b20184836cb983bb273e5280384d0b Edward Thomson 1352099947 -0600 commit: trivial-7 +d874671ef5b20184836cb983bb273e5280384d0b bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352099949 -0600 checkout: moving from trivial-7 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100174 -0600 checkout: moving from master to trivial-10 +c607fc30883e335def28cd686b51f6cfa02b06ec 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100193 -0600 commit: trivial-10 +53825f41ac8d640612f9423a2f03a69f3d96809a 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100200 -0600 checkout: moving from trivial-10 to trivial-10-branch +53825f41ac8d640612f9423a2f03a69f3d96809a 11f4f3c08b737f5fd896cbefa1425ee63b21b2fa Edward Thomson 1352100211 -0600 commit: trivial-10-branch +11f4f3c08b737f5fd896cbefa1425ee63b21b2fa 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100214 -0600 checkout: moving from trivial-10-branch to trivial-10 +53825f41ac8d640612f9423a2f03a69f3d96809a 0ec5f433959cd46177f745903353efb5be08d151 Edward Thomson 1352100223 -0600 commit: trivial-10 +0ec5f433959cd46177f745903353efb5be08d151 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100225 -0600 checkout: moving from trivial-10 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100270 -0600 checkout: moving from master to trivial-9 +c607fc30883e335def28cd686b51f6cfa02b06ec f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100304 -0600 commit: trivial-9 +f0053b8060bb3f0be5cbcc3147a07ece26bf097e f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100310 -0600 checkout: moving from trivial-9 to trivial-9-branch +f0053b8060bb3f0be5cbcc3147a07ece26bf097e 13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e Edward Thomson 1352100317 -0600 commit: trivial-9-branch +13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100319 -0600 checkout: moving from trivial-9-branch to trivial-9 +f0053b8060bb3f0be5cbcc3147a07ece26bf097e c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a Edward Thomson 1352100333 -0600 commit: trivial-9 +c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100335 -0600 checkout: moving from trivial-9 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100576 -0600 checkout: moving from master to trivial-13 +c607fc30883e335def28cd686b51f6cfa02b06ec 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100589 -0600 commit: trivial-13 +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100604 -0600 checkout: moving from trivial-13 to trivial-13-branch +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa 05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c Edward Thomson 1352100610 -0600 commit: trivial-13-branch +05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100612 -0600 checkout: moving from trivial-13-branch to trivial-13 +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa a3fabece9eb8748da810e1e08266fef9b7136ad4 Edward Thomson 1352100625 -0600 commit: trivial-13 +a3fabece9eb8748da810e1e08266fef9b7136ad4 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100627 -0600 checkout: moving from trivial-13 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100936 -0600 checkout: moving from master to trivial-11 +c607fc30883e335def28cd686b51f6cfa02b06ec 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100958 -0600 commit: trivial-11 +35632e43612c06a3ea924bfbacd48333da874c29 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100964 -0600 checkout: moving from trivial-11 to trivial-11-branch +35632e43612c06a3ea924bfbacd48333da874c29 6718a45909532d1fcf5600d0877f7fe7e78f0b86 Edward Thomson 1352100978 -0600 commit: trivial-11-branch +6718a45909532d1fcf5600d0877f7fe7e78f0b86 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100981 -0600 checkout: moving from trivial-11-branch to trivial-11 +35632e43612c06a3ea924bfbacd48333da874c29 3168dca1a561889b045a6441909f4c56145e666d Edward Thomson 1352100992 -0600 commit: trivial-11 +3168dca1a561889b045a6441909f4c56145e666d bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352100996 -0600 checkout: moving from trivial-11 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352101098 -0600 checkout: moving from master to trivial-14 +c607fc30883e335def28cd686b51f6cfa02b06ec 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101113 -0600 commit: trivial-14 +596803b523203a4851c824c07366906f8353f4ad 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101117 -0600 checkout: moving from trivial-14 to trivial-14-branch +596803b523203a4851c824c07366906f8353f4ad 8187117062b750eed4f93fd7e899f17b52ce554d Edward Thomson 1352101132 -0600 commit: trivial-14-branch +8187117062b750eed4f93fd7e899f17b52ce554d 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101135 -0600 checkout: moving from trivial-14-branch to trivial-14 +596803b523203a4851c824c07366906f8353f4ad 7e2d058d5fedf8329db44db4fac610d6b1a89159 Edward Thomson 1352101141 -0600 commit: trivial-14 +7e2d058d5fedf8329db44db4fac610d6b1a89159 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1352101145 -0600 checkout: moving from trivial-14 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353177749 -0600 checkout: moving from master to renames1 +c607fc30883e335def28cd686b51f6cfa02b06ec 412b32fb66137366147f1801ecc962452757d48a Edward Thomson 1353177886 -0600 commit: renames +412b32fb66137366147f1801ecc962452757d48a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794607 -0600 checkout: moving from renames1 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794647 -0600 checkout: moving from master to renames2 +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353794677 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec ab40af3cb8a3ed2e2843e96d9aa7871336b94573 Edward Thomson 1353794852 -0600 commit: renames2 +ab40af3cb8a3ed2e2843e96d9aa7871336b94573 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794883 -0600 checkout: moving from renames2 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1354574697 -0600 checkout: moving from master to df_side1 +bd593285fc7fe4ca18ccdbabf027f5d689101452 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354574962 -0600 commit: df_ancestor +d4207f77243500bec335ab477f9227fcdb1e271a c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1354575027 -0600 commit: df_side1 +c94b27e41064c521120627e07e2035cca1d24ffa d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354575070 -0600 checkout: moving from df_side1 to df_side2 +d4207f77243500bec335ab477f9227fcdb1e271a f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1354575206 -0600 commit: df_side2 +f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1354575381 -0600 checkout: moving from df_side2 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1355017614 -0600 checkout: moving from master to df_side1 +c94b27e41064c521120627e07e2035cca1d24ffa a90bc3fb6f15181972a2959a921429efbd81a473 Edward Thomson 1355017650 -0600 commit: df_added +a90bc3fb6f15181972a2959a921429efbd81a473 c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1355017673 -0600 checkout: moving from df_side1 to c94b27e +c94b27e41064c521120627e07e2035cca1d24ffa d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355017673 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017673 -0600 rebase -i (squash): df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017676 -0600 rebase -i (finish): returning to refs/heads/df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1355017715 -0600 reset: moving to df_side2 +f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 8c749d9968d4b10dcfb06c9f97d0e5d92d337071 Edward Thomson 1355017744 -0600 commit: df_added +8c749d9968d4b10dcfb06c9f97d0e5d92d337071 f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1355017754 -0600 checkout: moving from df_side1 to f8958bd +f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355017754 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017754 -0600 rebase -i (squash): df_side2 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017756 -0600 rebase -i (finish): returning to refs/heads/df_side1 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017793 -0600 reset: moving to 005b6fcc8fec71d2550bef8462d169b3c26aa14b +005b6fcc8fec71d2550bef8462d169b3c26aa14b 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017826 -0600 reset: moving to 0204a84 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355017847 -0600 checkout: moving from df_side1 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355168677 -0600 checkout: moving from master to df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355168829 -0600 checkout: moving from df_side1 to df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355168838 -0600 checkout: moving from df_side1 to df_side1 +005b6fcc8fec71d2550bef8462d169b3c26aa14b e8107f24196736b870a318a0e28f048e29f6feff Edward Thomson 1355169065 -0600 commit: df_side1 +e8107f24196736b870a318a0e28f048e29f6feff 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355169081 -0600 checkout: moving from df_side1 to 005b6fc +005b6fcc8fec71d2550bef8462d169b3c26aa14b d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169081 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169081 -0600 rebase -i (squash): df_side1 +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169084 -0600 rebase -i (finish): returning to refs/heads/df_side1 +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355169141 -0600 checkout: moving from df_side1 to df_side2 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 944f5dd1a867cab4c2bbcb896493435cae1dcc1a Edward Thomson 1355169174 -0600 commit: both +944f5dd1a867cab4c2bbcb896493435cae1dcc1a 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355169182 -0600 checkout: moving from df_side2 to 0204a84 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169182 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169182 -0600 rebase -i (squash): df_side2 +57079a46233ae2b6df62e9ade71c4948512abefb 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169185 -0600 rebase -i (finish): returning to refs/heads/df_side2 +57079a46233ae2b6df62e9ade71c4948512abefb 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169241 -0600 checkout: moving from df_side2 to df_side1 +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 Edward Thomson 1355169419 -0600 commit: side1 +e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169431 -0600 checkout: moving from df_side1 to 80a8fbb +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169431 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169431 -0600 rebase -i (squash): df_side1 +5dc1018e90b19654bee986b7a0c268804d39659d 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169435 -0600 rebase -i (finish): returning to refs/heads/df_side1 +5dc1018e90b19654bee986b7a0c268804d39659d 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169439 -0600 checkout: moving from df_side1 to df_side2 +57079a46233ae2b6df62e9ade71c4948512abefb 58e853f66699fd02629fd50bde08082bc005933a Edward Thomson 1355169460 -0600 commit: side2 +58e853f66699fd02629fd50bde08082bc005933a 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169469 -0600 checkout: moving from df_side2 to 57079a4 +57079a46233ae2b6df62e9ade71c4948512abefb d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169469 -0600 rebase -i (squash): updating HEAD +d4207f77243500bec335ab477f9227fcdb1e271a fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169469 -0600 rebase -i (squash): df_side2 +fada9356aa3f74622327a3038ae9c6f92e1c5c1d fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169471 -0600 rebase -i (finish): returning to refs/heads/df_side2 +fada9356aa3f74622327a3038ae9c6f92e1c5c1d 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169494 -0600 checkout: moving from df_side2 to df_side1 +5dc1018e90b19654bee986b7a0c268804d39659d d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169663 -0600 checkout: moving from df_side1 to d4207f77243500bec335ab477f9227fcdb1e271a +d4207f77243500bec335ab477f9227fcdb1e271a 849619b03ae540acee4d1edec96b86993da6b497 Edward Thomson 1355169683 -0600 commit: both_dirs +849619b03ae540acee4d1edec96b86993da6b497 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1355169691 -0600 checkout: moving from 849619b03ae540acee4d1edec96b86993da6b497 to d4207f7 +d4207f77243500bec335ab477f9227fcdb1e271a bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355169691 -0600 rebase -i (squash): updating HEAD +bd593285fc7fe4ca18ccdbabf027f5d689101452 a765fb87eb2f7a1920b73b2d5a057f8f8476a42b Edward Thomson 1355169691 -0600 rebase -i (squash): df_ancestor +a765fb87eb2f7a1920b73b2d5a057f8f8476a42b 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169706 -0600 checkout: moving from a765fb87eb2f7a1920b73b2d5a057f8f8476a42b to df_side1 +5dc1018e90b19654bee986b7a0c268804d39659d a765fb87eb2f7a1920b73b2d5a057f8f8476a42b Edward Thomson 1355169715 -0600 checkout: moving from df_side1 to a765fb87eb2f7a1920b73b2d5a057f8f8476a42b^0 +a765fb87eb2f7a1920b73b2d5a057f8f8476a42b bc744705e1d8a019993cf88f62bc4020f1b80919 Edward Thomson 1355169801 -0600 commit: df_side1 +bc744705e1d8a019993cf88f62bc4020f1b80919 bc744705e1d8a019993cf88f62bc4020f1b80919 Edward Thomson 1355169822 -0600 checkout: moving from bc744705e1d8a019993cf88f62bc4020f1b80919 to df_side1 +bc744705e1d8a019993cf88f62bc4020f1b80919 fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169826 -0600 checkout: moving from df_side1 to df_side2 +fada9356aa3f74622327a3038ae9c6f92e1c5c1d a765fb87eb2f7a1920b73b2d5a057f8f8476a42b Edward Thomson 1355169866 -0600 checkout: moving from df_side2 to a765fb87eb2f7a1920b73b2d5a057f8f8476a42b^0 +a765fb87eb2f7a1920b73b2d5a057f8f8476a42b 95646149ab6b6ba6edc83cff678582538b457b2b Edward Thomson 1355169897 -0600 rebase: df_side2 +95646149ab6b6ba6edc83cff678582538b457b2b 95646149ab6b6ba6edc83cff678582538b457b2b Edward Thomson 1355169897 -0600 rebase finished: returning to refs/heads/df_side2 +95646149ab6b6ba6edc83cff678582538b457b2b bc744705e1d8a019993cf88f62bc4020f1b80919 Edward Thomson 1355169949 -0600 checkout: moving from df_side2 to df_side1 +bc744705e1d8a019993cf88f62bc4020f1b80919 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355170046 -0600 checkout: moving from df_side1 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355181639 -0600 checkout: moving from master to df_ancestor +bd593285fc7fe4ca18ccdbabf027f5d689101452 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355181673 -0600 commit: df_ancestor +2da538570bc1e5b2c3e855bf702f35248ad0735f a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181715 -0600 commit: df_side1 +a7dbfcbfc1a60709cb80b5ca24539008456531d0 a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181743 -0600 checkout: moving from df_ancestor to df_ancestor +a7dbfcbfc1a60709cb80b5ca24539008456531d0 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355181775 -0600 commit: df_side2 +9a301fbe6fada7dcb74fcd7c20269b5c743459a7 a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181793 -0600 checkout: moving from df_ancestor to df_side1 +a7dbfcbfc1a60709cb80b5ca24539008456531d0 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355181797 -0600 checkout: moving from df_side1 to df_side2 +9a301fbe6fada7dcb74fcd7c20269b5c743459a7 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355182062 -0600 checkout: moving from df_side2 to df_ancestor +9a301fbe6fada7dcb74fcd7c20269b5c743459a7 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182067 -0600 reset: moving to 2da538570bc1e5b2c3e855bf702f35248ad0735f +2da538570bc1e5b2c3e855bf702f35248ad0735f 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182087 -0600 checkout: moving from df_ancestor to df_side2 +2da538570bc1e5b2c3e855bf702f35248ad0735f fc90237dc4891fa6c69827fc465632225e391618 Edward Thomson 1355182104 -0600 commit: df_side2 +fc90237dc4891fa6c69827fc465632225e391618 a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355182111 -0600 checkout: moving from df_side2 to df_side1 +a7dbfcbfc1a60709cb80b5ca24539008456531d0 fc90237dc4891fa6c69827fc465632225e391618 Edward Thomson 1355182115 -0600 checkout: moving from df_side1 to df_side2 +fc90237dc4891fa6c69827fc465632225e391618 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355182122 -0600 checkout: moving from df_side2 to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 d6cf6c7741b3316826af1314042550c97ded1d50 Edward Thomson 1358997543 -0600 checkout: moving from master to unrelated +d6cf6c7741b3316826af1314042550c97ded1d50 55b4e4687e7a0d9ca367016ed930f385d4022e6f Edward Thomson 1358997664 -0600 commit: conflicting changes +55b4e4687e7a0d9ca367016ed930f385d4022e6f bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1358997675 -0600 checkout: moving from unrelated to master +bd593285fc7fe4ca18ccdbabf027f5d689101452 88e185910a15cd13bdf44854ad037f4842b03b29 Edward Thomson 1365714471 -0500 checkout: moving from master to rename_conflict_ours +88e185910a15cd13bdf44854ad037f4842b03b29 bef6e37b3ee632ba74159168836f382fed21d77d Edward Thomson 1365714516 -0500 checkout: moving from rename_conflict_ours to bef6e37b3ee632ba74159168836f382fed21d77d +bef6e37b3ee632ba74159168836f382fed21d77d 01f149e1b8f84bd8896aaff6d6b22af88459ded0 Edward Thomson 1365714831 -0500 commit: rename ancestor +0000000000000000000000000000000000000000 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365714958 -0500 commit (initial): rename conflict ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 88e185910a15cd13bdf44854ad037f4842b03b29 Edward Thomson 1365714980 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_ours +88e185910a15cd13bdf44854ad037f4842b03b29 7c2c5228c9e90170d4a35e6558e47163daf092e5 Edward Thomson 1365715250 -0500 commit: rename conflict ours +7c2c5228c9e90170d4a35e6558e47163daf092e5 2f4024ce528d36d8670c289cce5a7963e625bb0c Edward Thomson 1365715274 -0500 checkout: moving from rename_conflict_ours to rename_conflict_theirs +2f4024ce528d36d8670c289cce5a7963e625bb0c 56a638b76b75e068590ac999c2f8621e7f3e264c Edward Thomson 1365715362 -0500 commit: rename conflict theirs +56a638b76b75e068590ac999c2f8621e7f3e264c 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715368 -0500 checkout: moving from rename_conflict_theirs to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 56a638b76b75e068590ac999c2f8621e7f3e264c Edward Thomson 1365715371 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_theirs +56a638b76b75e068590ac999c2f8621e7f3e264c 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715404 -0500 checkout: moving from rename_conflict_theirs to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715438 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_ours +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715480 -0500 checkout: moving from rename_conflict_ours to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715486 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_ours +2392a2dacc9efb562b8635d6579fb458751c7c5b f3293571dcd708b6a3faf03818cd2844d000e198 Edward Thomson 1365715538 -0500 commit: rename conflict ours +f3293571dcd708b6a3faf03818cd2844d000e198 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715546 -0500 checkout: moving from rename_conflict_ours to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715550 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_thiers +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715554 -0500 checkout: moving from rename_conflict_thiers to rename_conflict_ancestor +2392a2dacc9efb562b8635d6579fb458751c7c5b 2392a2dacc9efb562b8635d6579fb458751c7c5b Edward Thomson 1365715557 -0500 checkout: moving from rename_conflict_ancestor to rename_conflict_theirs +2392a2dacc9efb562b8635d6579fb458751c7c5b a802e06f1782a9645b9851bc7202cee74a8a4972 Edward Thomson 1365715572 -0500 commit: rename conflict theirs +a802e06f1782a9645b9851bc7202cee74a8a4972 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1365715620 -0500 checkout: moving from rename_conflict_theirs to master diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/branch new file mode 100644 index 000000000..8b0acb702 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563886 -0500 branch: Created from HEAD +c607fc30883e335def28cd686b51f6cfa02b06ec 7cb63eed597130ba4abb87b3e544b85021905520 Edward Thomson 1351563965 -0500 commit: branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_ancestor b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_ancestor new file mode 100644 index 000000000..df7695a66 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_ancestor @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1355181639 -0600 branch: Created from HEAD +bd593285fc7fe4ca18ccdbabf027f5d689101452 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355181673 -0600 commit: df_ancestor +2da538570bc1e5b2c3e855bf702f35248ad0735f a7dbfcbfc1a60709cb80b5ca24539008456531d0 Edward Thomson 1355181715 -0600 commit: df_side1 +a7dbfcbfc1a60709cb80b5ca24539008456531d0 9a301fbe6fada7dcb74fcd7c20269b5c743459a7 Edward Thomson 1355181775 -0600 commit: df_side2 +9a301fbe6fada7dcb74fcd7c20269b5c743459a7 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182067 -0600 reset: moving to 2da538570bc1e5b2c3e855bf702f35248ad0735f diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side1 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side1 new file mode 100644 index 000000000..a504ad610 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side1 @@ -0,0 +1,14 @@ +0000000000000000000000000000000000000000 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1354574697 -0600 branch: Created from HEAD +bd593285fc7fe4ca18ccdbabf027f5d689101452 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354574962 -0600 commit: df_ancestor +d4207f77243500bec335ab477f9227fcdb1e271a c94b27e41064c521120627e07e2035cca1d24ffa Edward Thomson 1354575027 -0600 commit: df_side1 +c94b27e41064c521120627e07e2035cca1d24ffa a90bc3fb6f15181972a2959a921429efbd81a473 Edward Thomson 1355017650 -0600 commit: df_added +a90bc3fb6f15181972a2959a921429efbd81a473 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017676 -0600 rebase -i (finish): refs/heads/df_side1 onto c94b27e +005b6fcc8fec71d2550bef8462d169b3c26aa14b f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1355017715 -0600 reset: moving to df_side2 +f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 8c749d9968d4b10dcfb06c9f97d0e5d92d337071 Edward Thomson 1355017744 -0600 commit: df_added +8c749d9968d4b10dcfb06c9f97d0e5d92d337071 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017756 -0600 rebase -i (finish): refs/heads/df_side1 onto f8958bd +0204a84f822acbf6386b36d33f1f6bc68bbbf858 005b6fcc8fec71d2550bef8462d169b3c26aa14b Edward Thomson 1355017793 -0600 reset: moving to 005b6fcc8fec71d2550bef8462d169b3c26aa14b +005b6fcc8fec71d2550bef8462d169b3c26aa14b 0204a84f822acbf6386b36d33f1f6bc68bbbf858 Edward Thomson 1355017826 -0600 reset: moving to 0204a84 +005b6fcc8fec71d2550bef8462d169b3c26aa14b e8107f24196736b870a318a0e28f048e29f6feff Edward Thomson 1355169065 -0600 commit: df_side1 +e8107f24196736b870a318a0e28f048e29f6feff 80a8fbb3abb1ba423d554e9630b8fc2e5698f86b Edward Thomson 1355169084 -0600 rebase -i (finish): refs/heads/df_side1 onto 005b6fc +80a8fbb3abb1ba423d554e9630b8fc2e5698f86b e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 Edward Thomson 1355169419 -0600 commit: side1 +e65a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 5dc1018e90b19654bee986b7a0c268804d39659d Edward Thomson 1355169435 -0600 rebase -i (finish): refs/heads/df_side1 onto 80a8fbb diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side2 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side2 new file mode 100644 index 000000000..27d833eda --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/df_side2 @@ -0,0 +1,9 @@ +0000000000000000000000000000000000000000 d4207f77243500bec335ab477f9227fcdb1e271a Edward Thomson 1354575051 -0600 branch: Created from d4207f77243500bec335ab477f9227fcdb1e271a +d4207f77243500bec335ab477f9227fcdb1e271a f8958bdf4d365a84a9a178b1f5f35ff1dacbd884 Edward Thomson 1354575206 -0600 commit: df_side2 +0204a84f822acbf6386b36d33f1f6bc68bbbf858 944f5dd1a867cab4c2bbcb896493435cae1dcc1a Edward Thomson 1355169174 -0600 commit: both +944f5dd1a867cab4c2bbcb896493435cae1dcc1a 57079a46233ae2b6df62e9ade71c4948512abefb Edward Thomson 1355169185 -0600 rebase -i (finish): refs/heads/df_side2 onto 0204a84 +57079a46233ae2b6df62e9ade71c4948512abefb 58e853f66699fd02629fd50bde08082bc005933a Edward Thomson 1355169460 -0600 commit: side2 +58e853f66699fd02629fd50bde08082bc005933a fada9356aa3f74622327a3038ae9c6f92e1c5c1d Edward Thomson 1355169471 -0600 rebase -i (finish): refs/heads/df_side2 onto 57079a4 +fada9356aa3f74622327a3038ae9c6f92e1c5c1d 95646149ab6b6ba6edc83cff678582538b457b2b Edward Thomson 1355169897 -0600 rebase finished: refs/heads/df_side2 onto a765fb87eb2f7a1920b73b2d5a057f8f8476a42b +0000000000000000000000000000000000000000 2da538570bc1e5b2c3e855bf702f35248ad0735f Edward Thomson 1355182087 -0600 branch: Created from HEAD +2da538570bc1e5b2c3e855bf702f35248ad0735f fc90237dc4891fa6c69827fc465632225e391618 Edward Thomson 1355182104 -0600 commit: df_side2 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/ff_branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/ff_branch new file mode 100644 index 000000000..c4706175d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/ff_branch @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351605785 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 33d500f588fbbe65901d82b4e6b008e549064be0 Edward Thomson 1351605830 -0500 commit: fastforward +33d500f588fbbe65901d82b4e6b008e549064be0 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351990202 -0500 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1351990205 -0500 merge master: Fast-forward +bd593285fc7fe4ca18ccdbabf027f5d689101452 fd89f8cffb663ac89095a0f9764902e93ceaca6a Edward Thomson 1351990229 -0500 commit: fastforward diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/master b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/master new file mode 100644 index 000000000..60475992a --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/master @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1351563869 -0500 commit (initial): initial +c607fc30883e335def28cd686b51f6cfa02b06ec 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351564033 -0500 commit: master +977c696519c5a3004c5f1d15d60c89dbeb8f235f 4e0d9401aee78eb345a8685a859d37c8c3c0bbed Edward Thomson 1351875091 -0500 merge octo1 octo2 octo3 octo4: Merge made by the 'octopus' strategy. +4e0d9401aee78eb345a8685a859d37c8c3c0bbed 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875108 -0500 reset: moving to 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae +54269b3f6ec3d7d4ede24dd350dd5d605495c3ae 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875584 -0500 reset: moving to 977c696519c5a3004c5f1d15d60c89dbeb8f235f diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo1 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo1 new file mode 100644 index 000000000..0b6c9214a --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo1 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874933 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 16f825815cfd20a07a75c71554e82d8eede0b061 Edward Thomson 1351874954 -0500 commit: octo1 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo2 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo2 new file mode 100644 index 000000000..5392a4f86 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo2 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874960 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 158dc7bedb202f5b26502bf3574faa7f4238d56c Edward Thomson 1351874974 -0500 commit: octo2 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo3 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo3 new file mode 100644 index 000000000..7db5617c8 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo3 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351874980 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 50ce7d7d01217679e26c55939eef119e0c93e272 Edward Thomson 1351874998 -0500 commit: octo3 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo4 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo4 new file mode 100644 index 000000000..b0f9e42ef --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo4 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875010 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 54269b3f6ec3d7d4ede24dd350dd5d605495c3ae Edward Thomson 1351875023 -0500 commit: octo4 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo5 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo5 new file mode 100644 index 000000000..614563edf --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo5 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875031 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f e4f618a2c3ed0669308735727df5ebf2447f022f Edward Thomson 1351875041 -0500 commit: octo5 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo6 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo6 new file mode 100644 index 000000000..4c812eacc --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/octo6 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 977c696519c5a3004c5f1d15d60c89dbeb8f235f Edward Thomson 1351875046 -0500 branch: Created from HEAD +977c696519c5a3004c5f1d15d60c89dbeb8f235f 4ca408a8c88655f7586a1b580be6fad138121e98 Edward Thomson 1351875057 -0500 commit: octo5 +4ca408a8c88655f7586a1b580be6fad138121e98 b6f610aef53bd343e6c96227de874c66f00ee8e8 Edward Thomson 1351875065 -0500 commit (amend): octo6 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames1 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames1 new file mode 100644 index 000000000..58a7e0565 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames1 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353177745 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 412b32fb66137366147f1801ecc962452757d48a Edward Thomson 1353177886 -0600 commit: renames diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames2 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames2 new file mode 100644 index 000000000..5645ecee7 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/renames2 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 bd593285fc7fe4ca18ccdbabf027f5d689101452 Edward Thomson 1353794647 -0600 branch: Created from HEAD +bd593285fc7fe4ca18ccdbabf027f5d689101452 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1353794677 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec ab40af3cb8a3ed2e2843e96d9aa7871336b94573 Edward Thomson 1353794852 -0600 commit: renames2 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10 new file mode 100644 index 000000000..b6bd247e7 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100171 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100193 -0600 commit: trivial-10 +53825f41ac8d640612f9423a2f03a69f3d96809a 0ec5f433959cd46177f745903353efb5be08d151 Edward Thomson 1352100223 -0600 commit: trivial-10 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10-branch new file mode 100644 index 000000000..14ce9e545 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-10-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 53825f41ac8d640612f9423a2f03a69f3d96809a Edward Thomson 1352100200 -0600 branch: Created from HEAD +53825f41ac8d640612f9423a2f03a69f3d96809a 11f4f3c08b737f5fd896cbefa1425ee63b21b2fa Edward Thomson 1352100211 -0600 commit: trivial-10-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11 new file mode 100644 index 000000000..3e6b77437 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100930 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100958 -0600 commit: trivial-11 +35632e43612c06a3ea924bfbacd48333da874c29 3168dca1a561889b045a6441909f4c56145e666d Edward Thomson 1352100992 -0600 commit: trivial-11 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11-branch new file mode 100644 index 000000000..30d5ec7a3 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-11-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 35632e43612c06a3ea924bfbacd48333da874c29 Edward Thomson 1352100964 -0600 branch: Created from HEAD +35632e43612c06a3ea924bfbacd48333da874c29 6718a45909532d1fcf5600d0877f7fe7e78f0b86 Edward Thomson 1352100978 -0600 commit: trivial-11-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13 new file mode 100644 index 000000000..3a7302dea --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100559 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100589 -0600 commit: trivial-13 +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa a3fabece9eb8748da810e1e08266fef9b7136ad4 Edward Thomson 1352100625 -0600 commit: trivial-13 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13-branch new file mode 100644 index 000000000..bb2604244 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-13-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa Edward Thomson 1352100604 -0600 branch: Created from HEAD +8f4433f8593ddd65b7dd43dd4564d841f4d9c8aa 05f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c Edward Thomson 1352100610 -0600 commit: trivial-13-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14 new file mode 100644 index 000000000..4b70d2898 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352101083 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101113 -0600 commit: trivial-14 +596803b523203a4851c824c07366906f8353f4ad 7e2d058d5fedf8329db44db4fac610d6b1a89159 Edward Thomson 1352101141 -0600 commit: trivial-14 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14-branch new file mode 100644 index 000000000..8e491ca68 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-14-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 596803b523203a4851c824c07366906f8353f4ad Edward Thomson 1352101117 -0600 branch: Created from HEAD +596803b523203a4851c824c07366906f8353f4ad 8187117062b750eed4f93fd7e899f17b52ce554d Edward Thomson 1352101132 -0600 commit: trivial-14-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt new file mode 100644 index 000000000..a2a28d401 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352091695 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 566ab53c220a2eafc1212af1a024513230280ab9 Edward Thomson 1352092452 -0600 commit: 2alt diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt-branch new file mode 100644 index 000000000..a0a48ae35 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-2alt-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352092411 -0600 branch: Created from HEAD +c607fc30883e335def28cd686b51f6cfa02b06ec c9174cef549ec94ecbc43ef03cdc775b4950becb Edward Thomson 1352092434 -0600 commit: 2alt-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt new file mode 100644 index 000000000..4374d3888 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt @@ -0,0 +1,3 @@ +566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094547 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 5459c89aa0026d543ce8343bd89871bce543f9c2 Edward Thomson 1352094580 -0600 commit: 3alt +5459c89aa0026d543ce8343bd89871bce543f9c2 4c9fac0707f8d4195037ae5a681aa48626491541 Edward Thomson 1352094610 -0600 commit: 3alt-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt-branch new file mode 100644 index 000000000..7a2e6f822 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-3alt-branch @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094594 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4 new file mode 100644 index 000000000..3ee6d2503 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4 @@ -0,0 +1,2 @@ +566ab53c220a2eafc1212af1a024513230280ab9 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094764 -0600 reset: moving to c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec cc3e3009134cb88014129fc8858d1101359e5e2f Edward Thomson 1352094815 -0600 commit: trivial-4 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4-branch new file mode 100644 index 000000000..51f8a9290 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-4-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352094830 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 183310e30fb1499af8c619108ffea4d300b5e778 Edward Thomson 1352094856 -0600 commit: trivial-4-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1 new file mode 100644 index 000000000..14497029a --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1 @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096606 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 4fe93c0ec83eb6305cbace3dace88ecee1b63cb6 Edward Thomson 1352096643 -0600 commit: 5alt-1 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1-branch new file mode 100644 index 000000000..4cff83526 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-1-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096657 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 478172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 Edward Thomson 1352096689 -0600 commit: 5alt-1-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2 new file mode 100644 index 000000000..3ca077b29 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352096711 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096764 -0600 commit: existing file +ebc09d0137cfb0c26697aed0109fb943ad906f3f 3b47b031b3e55ae11e14a05260b1c3ffd6838d55 Edward Thomson 1352096815 -0600 commit: 5alt-2 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2-branch new file mode 100644 index 000000000..e7bb901f2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-5alt-2-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 ebc09d0137cfb0c26697aed0109fb943ad906f3f Edward Thomson 1352096833 -0600 branch: Created from ebc09d0 +ebc09d0137cfb0c26697aed0109fb943ad906f3f f48097eb340dc5a7cae55aabcf1faf4548aa821f Edward Thomson 1352096855 -0600 commit: 5alt-2-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6 new file mode 100644 index 000000000..7c717a210 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352097371 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097389 -0600 commit: 6 +f7c332bd4d4d4b777366cae4d24d1687477576bf 99b4f7e4f24470fa06b980bc21f1095c2a9425c0 Edward Thomson 1352097404 -0600 commit: trivial-6 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6-branch new file mode 100644 index 000000000..715f3ae1c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-6-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 f7c332bd4d4d4b777366cae4d24d1687477576bf Edward Thomson 1352097414 -0600 branch: Created from f7c332bd4d4d4b777366cae4d24d1687477576bf +f7c332bd4d4d4b777366cae4d24d1687477576bf a43150a738849c59376cf30bb2a68348a83c8f48 Edward Thomson 1352097431 -0600 commit: 6-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7 new file mode 100644 index 000000000..a014f1722 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352099765 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099790 -0600 commit: trivial-7 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 d874671ef5b20184836cb983bb273e5280384d0b Edward Thomson 1352099947 -0600 commit: trivial-7 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7-branch new file mode 100644 index 000000000..22331d78c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-7-branch @@ -0,0 +1,5 @@ +0000000000000000000000000000000000000000 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099799 -0600 branch: Created from HEAD +092ce8682d7f3a2a3a769a6daca58950168ba5c4 73cbfdc4fe843169e5b2af8dcad03cbf3acf306c Edward Thomson 1352099812 -0600 commit: trivial-7-branch +73cbfdc4fe843169e5b2af8dcad03cbf3acf306c 092ce8682d7f3a2a3a769a6daca58950168ba5c4 Edward Thomson 1352099874 -0600 reset: moving to 092ce8682d7f3a2a3a769a6daca58950168ba5c4 +092ce8682d7f3a2a3a769a6daca58950168ba5c4 009b9cab6fdac02915a88ecd078b7a792ed802d8 Edward Thomson 1352099921 -0600 commit: removed in 7 +009b9cab6fdac02915a88ecd078b7a792ed802d8 5195a1b480f66691b667f10a9e41e70115a78351 Edward Thomson 1352099927 -0600 commit (amend): trivial-7-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8 new file mode 100644 index 000000000..7670c3506 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352098816 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098884 -0600 commit: trivial-8 +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 3575826c96a975031d2c14368529cc5c4353a8fd Edward Thomson 1352099000 -0600 commit: trivial-8 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8-branch new file mode 100644 index 000000000..c4d68edcf --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-8-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 75a811bf6bc57694adb3fe604786f3a4efd1cd1b Edward Thomson 1352098947 -0600 branch: Created from HEAD +75a811bf6bc57694adb3fe604786f3a4efd1cd1b 52d8bc572af2b6d4ee0d5e62ed5d1fbad92210a9 Edward Thomson 1352098979 -0600 commit: trivial-8-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9 b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9 new file mode 100644 index 000000000..09a343bdb --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9 @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 c607fc30883e335def28cd686b51f6cfa02b06ec Edward Thomson 1352100268 -0600 branch: Created from c607fc30883e335def28cd686b51f6cfa02b06ec +c607fc30883e335def28cd686b51f6cfa02b06ec f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100304 -0600 commit: trivial-9 +f0053b8060bb3f0be5cbcc3147a07ece26bf097e c35dee9bcc0e989f3b0c40f68372a9a51b6c4e6a Edward Thomson 1352100333 -0600 commit: trivial-9 diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9-branch b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9-branch new file mode 100644 index 000000000..1b126fb7b --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/trivial-9-branch @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 f0053b8060bb3f0be5cbcc3147a07ece26bf097e Edward Thomson 1352100310 -0600 branch: Created from HEAD +f0053b8060bb3f0be5cbcc3147a07ece26bf097e 13d1be4ea52a6ced1d7a1d832f0ee3c399348e5e Edward Thomson 1352100317 -0600 commit: trivial-9-branch diff --git a/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/unrelated b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/unrelated new file mode 100644 index 000000000..a83ffc26a --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/logs/refs/heads/unrelated @@ -0,0 +1 @@ +d6cf6c7741b3316826af1314042550c97ded1d50 55b4e4687e7a0d9ca367016ed930f385d4022e6f Edward Thomson 1358997664 -0600 commit: conflicting changes diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/00/5b6fcc8fec71d2550bef8462d169b3c26aa14b b/tests-clar/resources/merge-resolve/.gitted/objects/00/5b6fcc8fec71d2550bef8462d169b3c26aa14b new file mode 100644 index 0000000000000000000000000000000000000000..82a8da597f013237fc97a4940452778fd54fd7ac GIT binary patch literal 168 zcmV;Z09XHb0hNwB4#F@HM5%oWUjVf0-#QXPG~9q5`LkA1I7W#P*C(J{fNtiE^fal} zI(4axKJ=@j`Xe(xjfb>Gl~x~dQMW-^iD7U literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/00/9b9cab6fdac02915a88ecd078b7a792ed802d8 b/tests-clar/resources/merge-resolve/.gitted/objects/00/9b9cab6fdac02915a88ecd078b7a792ed802d8 new file mode 100644 index 0000000000000000000000000000000000000000..f663a3c5146f02f7aeabdee6732abab596d9cbee GIT binary patch literal 164 zcmV;V09*ff0i}-14Z<)GL^->PZ2)9D{;h-%7doJU&3dEc;20SL?Gq3kaGQCf84cG` zmJZg%U2h^FCK8KrXoE|PnSIn|r0m&6nlPI&Xm*0?MorcZ8ZAo-$>ul>WNDxnkU}OV zpU`U)(nwob(WB3`!6m<_Ww_3@-0KQQ+2}`|Y S8P%lJr({@Gi0Tb@V^GR)1x=s; literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/00/c7d33f1ffa79d19c2272b370fcaeaadba49c08 b/tests-clar/resources/merge-resolve/.gitted/objects/00/c7d33f1ffa79d19c2272b370fcaeaadba49c08 new file mode 100644 index 0000000000000000000000000000000000000000..72698dc3df0cac29445308ad42e04b1954cab618 GIT binary patch literal 147 zcmV;E0Brww0V^p=O;s>7wqP(Z00M=i{E`gal+2=H22-BA&5V419IUe6W+)pa2aCLX z8)0Z*U}j>XkdhXkn39s3!k{i}yPRp4O~QID#+Ny&q5mCRuT6rf$t+@M-!dsF;d+&I zt6brmb8OACuLW!}gjkc7nUktlQc=Q?zi;FeH-sWH BMcn`Z literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/01/f149e1b8f84bd8896aaff6d6b22af88459ded0 b/tests-clar/resources/merge-resolve/.gitted/objects/01/f149e1b8f84bd8896aaff6d6b22af88459ded0 new file mode 100644 index 0000000000000000000000000000000000000000..aa6336d3fac865556fb2c7e9f84e69a304fb13b0 GIT binary patch literal 166 zcmV;X09pTd0i}*f4gw(%06p`H{(uIWr6DoKi$CxKEKOz(42Hq@eaAO=tJI-Vxwp1X zK!c|_n4xAWl)SW+Vle0}nQE$+n2@!}1!YX3gdkpV@HQcFb*w3AW~VVlGRg+!yw|R3 zkCh9mLR3V2&!rD|lusN5o=b0g-{8uJ{n5RxdGx*4dC9%qKxt=58Lt(brIk_~_86V~ UM?xIOu`$Fg^FI3!Uu`Z<;^BBtW&i*H literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/02/04a84f822acbf6386b36d33f1f6bc68bbbf858 b/tests-clar/resources/merge-resolve/.gitted/objects/02/04a84f822acbf6386b36d33f1f6bc68bbbf858 new file mode 100644 index 0000000000000000000000000000000000000000..2f0a0e1bb139f469d893b97328c111886fdc93d1 GIT binary patch literal 168 zcmV;Z09XHb0hNwH3IZ_@1U=^!`G7K+WOg90$m)T^39(E%!;`d#}4|waYhN4rQ z=UcZJ{H8Zmn_!SQDUCr=h$4WAh@5wrqhcH}MVE^MbC;$|w>cniVO|9UFlq9hWD3kB zB63N2a*FK4$g^K-v#0!$mhJgk=SN-aURU}_NBs`Jwo7$BSm!Aa6T)D(FaVg9u4lXc Wts!vC6n+|$%jI#)islV~F;1nsUQS^E literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/02/251f990ca8e92e7ae61d3426163fa821c64001 b/tests-clar/resources/merge-resolve/.gitted/objects/02/251f990ca8e92e7ae61d3426163fa821c64001 new file mode 100644 index 0000000000000000000000000000000000000000..d623117c5451f527ebff27812643d7856fbe5a0a GIT binary patch literal 264 zcmV+j0r&oR0V^p=O;s>9H()R{FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRUTQg- zLz>xdT8Tz7FFi7~EW)1W;kW;tHGELTMX9;@Wf(5M|M-*kD*60#A?_1o4BB=*&bXI- z7gGb0%VVrFmdhXc6>Fw{xjimexF#!V`%9H)b$2FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRZhlH; zS|-#r`6Upy{0m|K6R_0k%@$dyym`yF2|aCG-wst@l$x7ghT-`8k3VUzlFvUE;yyvf zpl#RVjC4GGj0_FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nPt zDo)BT$o((3Q3>52inSC)Oh*VHo652`3RBQY->;)JB4#JuDTu&Jwa zTo%1>nY7m1ad-Bbc2m2#Ol!I^H6XcJ@ZM^MO_!H_UCeITv4)jLw>mBK5llmVURq9O za!F=hI@oN#j=Tg_%~LB^3tpFROZL9F?ZG_(69XVn0J@do>N06=&q+%@oLbTTi({*b z;dAxf`A~z>GNFEMZ z`ve(-wq1`i?q%PFYA6MI85{y&x1IQquV=k!nqx_N-NX;8UtM@&GcOhZ40*2>4RNg| literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/03/dad1005e5d06d418f50b12e0bcd48ff2306a03 b/tests-clar/resources/merge-resolve/.gitted/objects/03/dad1005e5d06d418f50b12e0bcd48ff2306a03 new file mode 100644 index 0000000000000000000000000000000000000000..04011a2ceb576207e2311a43982bbd4414831946 GIT binary patch literal 264 zcmV+j0r&oR0V^p=O;s>9vt%$dFfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRQEF~} z8N@LbV6{`{K8p)$DiPwpKhNst_iE7qAw^G2wMY)X|M-*kD*60#A?_1o4BB=*&bXI- z7gGb0!(*&7mdhXc6>Fw{xjimexF#!V`%z>-JwUU=aE literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/05/1ffd7901a442faf56b226161649074f15c7c47 b/tests-clar/resources/merge-resolve/.gitted/objects/05/1ffd7901a442faf56b226161649074f15c7c47 new file mode 100644 index 000000000..65fa6894f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/05/1ffd7901a442faf56b226161649074f15c7c47 @@ -0,0 +1 @@ +x+)JMU06`040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5&ؽ +gz43^2 I{| 2mg˾15ӿ,\})TC)0Xvz֛9MՅ'6b# \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/05/8541fc37114bfc1dddf6bd6bffc7fae5c2e6fe b/tests-clar/resources/merge-resolve/.gitted/objects/05/8541fc37114bfc1dddf6bd6bffc7fae5c2e6fe new file mode 100644 index 0000000000000000000000000000000000000000..d79dc30ba7155121f8e844b28d20c391df897375 GIT binary patch literal 63 zcmV-F0Korv0ZYosPf{>4F=r^r$ShV!%gjkt0Md!2CHc9jMd_)DNja%p!$&GPBQY;M VHANvaPa&x&F)ulT3jm+qT_Q;S7;yjq literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/05/f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c b/tests-clar/resources/merge-resolve/.gitted/objects/05/f3c1a2a56ca95c3d2ef28dc9ddf32b5cd6c91c new file mode 100644 index 0000000000000000000000000000000000000000..7b4b152f34b81cc4b40ed01324ac1946c396b058 GIT binary patch literal 170 zcmV;b09F5Z0i}*nYQr!PMDwjv=mHK}X;)UDg#P3PxxiYx!iLx?irQX3PRI@N_vQ@@ zlk2)J-Fote-c&6M6ETtik{=}pDR~4`h8#(}g2pmw8qE(k-MUQ$F@%!n6htJ_G>YJk zND(C=6qHj=%!YsaT${bfKR2=0xvuxR*)QGglfLy;ywfq)^=u)K2j?OxVO@x8-l)+W=vh8gF?v4}39G9kOy#6aWAK literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/07/a759da919f737221791d542f176ab49c88837f b/tests-clar/resources/merge-resolve/.gitted/objects/07/a759da919f737221791d542f176ab49c88837f new file mode 100644 index 0000000000000000000000000000000000000000..a34b6c23561a462aec7a79e840174db595fd093c GIT binary patch literal 165 zcmV;W09yZe0i}-1jRG+cL^(T(P5{()`zx&w7cw9LPrI$*V2r#5(q~w02HdLNlS;+C zwd(|9!)^`{5YiHIAt@%sYOGKsw#i|&KIoK47(*1R?s>><0(%UV31cK7az(0%TzvG4 z)75j$XcqLsDnI7h2b{|*j{=vqx8Ht)AKB<9o#apaw*&Wf1Wit-n9y3-qeE01-Of(= Taz-tEt}vwarxf)DDF;yiw$w}5 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/07/c514b04698e068892b31c8d352b85813b99c6e b/tests-clar/resources/merge-resolve/.gitted/objects/07/c514b04698e068892b31c8d352b85813b99c6e new file mode 100644 index 0000000000000000000000000000000000000000..23ab9217148566bcba07573afa4c376fd0f80c40 GIT binary patch literal 32 ocmbS$%Kcz!PVJJx=MLe89wz^nv|30NO4M_W%F@ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/09/055301463b7f2f8ee5d368f8ed5c0a40ad8515 b/tests-clar/resources/merge-resolve/.gitted/objects/09/055301463b7f2f8ee5d368f8ed5c0a40ad8515 new file mode 100644 index 0000000000000000000000000000000000000000..bf5b0fcc57ff618efc5784f508aee1634073bce2 GIT binary patch literal 41 zcmV+^0M`F_0ZYosPf{>4X9&s2ELKR%%t=)M(s`-n3YmEd`N<{uMtWQT%DoF6bTtwL literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/09/17bb159596aea4d295f4857da77e8f96b3c7dc b/tests-clar/resources/merge-resolve/.gitted/objects/09/17bb159596aea4d295f4857da77e8f96b3c7dc new file mode 100644 index 0000000000000000000000000000000000000000..9fb640dd5c947abdbcfa0a83f0d421d755fc5d1a GIT binary patch literal 36 ucmV+<0Nej~0ZYosPf{>4VkpVTEan2Dl*}Uiw9K4TL%ouU5-tFg0turl1P{3Y literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/09/2ce8682d7f3a2a3a769a6daca58950168ba5c4 b/tests-clar/resources/merge-resolve/.gitted/objects/09/2ce8682d7f3a2a3a769a6daca58950168ba5c4 new file mode 100644 index 0000000000000000000000000000000000000000..b709cf461bec50d06c7e92a4d9dc386fbe054808 GIT binary patch literal 163 zcmV;U09^lg0i}-74FVw$ME#};8aT7S-2#a*{@8&HEXxuv@x&l%`<})Q{F`}`ybRZ6 znY*^*xamzqm*ia_1IQ&q^fVHuh%Clg;bbTykC?!z8#TFh%?Q4*gAklJH)Sa{aK?aX zGG&zz*aRr7=+V!$>0^FT%ldS#%e`LpPFDI!2l)=aw&l9)wQ-Y$7<~ji00O9$u4lXa RsZqVn&zUZRS8o8yP?i&^P>KKm literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/09/3bebf072dd4bbba88833667d6ffe454df199e1 b/tests-clar/resources/merge-resolve/.gitted/objects/09/3bebf072dd4bbba88833667d6ffe454df199e1 new file mode 100644 index 0000000000000000000000000000000000000000..ae13207d7490a064ecf276149d49ccc8ddad31f4 GIT binary patch literal 266 zcmV+l0rmcP0V^p=O;s>9H)k+3FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRQEF~} z8N@M$2FUI?HtEeb1@;4L=5NZ=TG4V()A*j~TTDGj9=QMbllCh4{Bt4h6J!k9c0JCx zmwgvg1Cj?~tTUF&ANdt)rhmCTE?BrGD{A{vsD@HtsDJ|r?EDiS^7X7YO>-9H)b$2FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRZhlH; zS|-pnCHcC=iMbHR$KK_CmOqpCz|-^d-{j7A3vzfFTn|-Wl$x7ghT-`8k3VUzlFvUE z;yyvfpl#RVjC9H)b$2FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRZhlH; zS|-pnCHcC=iMbHRdwbk_YvpXox&PX>)wbRfO}ewbq(IddrRL_BVL1N&<4@YF4dj#_=z*Y27YHWA2KmGY-VEu0Hgp4jsO4v literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/0d/52e3a556e189ba0948ae56780918011c1b167d b/tests-clar/resources/merge-resolve/.gitted/objects/0d/52e3a556e189ba0948ae56780918011c1b167d new file mode 100644 index 0000000000000000000000000000000000000000..4b633e5043d1b0ba3cbb9ac4b0223b2a93342f38 GIT binary patch literal 235 zcmV9GG#C{FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRQEF~} z8HQu-KmMe>NBDf3F=Qyo$ShVU&&>GO3h2mO-)hA%u~oOEh^?p%u7*7 vP01{Q2$f`{W&#DdG&1v2Qd3iO6f#Q`fSS=2XmW9pVd$t95~BeC!$_Pzca$Uz literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/0e/c5f433959cd46177f745903353efb5be08d151 b/tests-clar/resources/merge-resolve/.gitted/objects/0e/c5f433959cd46177f745903353efb5be08d151 new file mode 100644 index 0000000000000000000000000000000000000000..1bee56c14b889c8933ce73c9797c99532081c84a GIT binary patch literal 165 zcmV;W09yZe0i}-74FVw$ME#};8qh4ez(Hb+KXzaP%dx~uyu%=B`<})Q{F`|%nao({ zdFmRi+w>-)AySf5V8EPhN{K@VMBWeCmm=2LTuh8&)Qy`gT{{ZsiZwij>@9eMC0ZoL z0>nNR%FzditoYF{wdqrSam)IAsq?)qdM_*eq@#SrukFS3X)y TpEIhr={fOrYe2mLSIb)7unqPA literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/11/f4f3c08b737f5fd896cbefa1425ee63b21b2fa b/tests-clar/resources/merge-resolve/.gitted/objects/11/f4f3c08b737f5fd896cbefa1425ee63b21b2fa new file mode 100644 index 000000000..6555194cb --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/11/f4f3c08b737f5fd896cbefa1425ee63b21b2fa @@ -0,0 +1 @@ +xQ D\fw)c^` ۴-Q/ơdb^ץjEDC$u> , z@8qjk<٩G>z2Lva2)Veŏ:%˜{A|Ǽ5K@mg9jY _;n,YyP \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/13/d1be4ea52a6ced1d7a1d832f0ee3c399348e5e b/tests-clar/resources/merge-resolve/.gitted/objects/13/d1be4ea52a6ced1d7a1d832f0ee3c399348e5e new file mode 100644 index 0000000000000000000000000000000000000000..4e4e175e8164e9fdc33ed173a3089ea2c7e75be1 GIT binary patch literal 168 zcmV;Z09XHb0i}-J4Z<)GgL%#rS)k}HY5pXHcwqw;xJ$2UCEB16V0{W=1K#Y
  • iU zWp3Iy+_fsAVQ@w)Ip+mqVuI9166ZsNgb@%kGWsy68&z4G9s!)?2p*X22rMph&KCPX z5G0H7JVFYh=+UN9^?7(v9rR@?%e}1nARGOtlYE1p+vl3VJOMSEan2Dl*}Uiw9K4TL%ouU5-yG8jKsY3)D(rxJcX3B Q_~OizR6|WJ0Kk(F;!lblxc~qF literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/15/8dc7bedb202f5b26502bf3574faa7f4238d56c b/tests-clar/resources/merge-resolve/.gitted/objects/15/8dc7bedb202f5b26502bf3574faa7f4238d56c new file mode 100644 index 000000000..064423d0c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/15/8dc7bedb202f5b26502bf3574faa7f4238d56c @@ -0,0 +1,2 @@ +xK!D]sCboi2. bK*Eep73UӾ*NYYIԔ)jL:8<{NޓH6iDC"mqH!9Tm9>R^i.= +G'+~@@j+7أENsFt]7bN) \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/16/f825815cfd20a07a75c71554e82d8eede0b061 b/tests-clar/resources/merge-resolve/.gitted/objects/16/f825815cfd20a07a75c71554e82d8eede0b061 new file mode 100644 index 000000000..82d65253b --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/16/f825815cfd20a07a75c71554e82d8eede0b061 @@ -0,0 +1 @@ +xK!D]sObo hJqo6AJـT1h3'Lՠ.{ec,a`ZJT1#e+هJUi">\+ ץG_X6IvN;^bYgGMM \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/17/8940b450f238a56c0d75b7955cb57b38191982 b/tests-clar/resources/merge-resolve/.gitted/objects/17/8940b450f238a56c0d75b7955cb57b38191982 new file mode 100644 index 0000000000000000000000000000000000000000..94e571e6547c9f6826e73200aeb24b334dc6b5a5 GIT binary patch literal 65 zcmV-H0KWft0ZYosPf{>8FlQ*q$ShV!%gjktD9_BvQAkQvC`!#s%uP+<%FI(p$}h=K XNGeLqOU_6w=HePv3l0YWsc3D@sF55# literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/18/3310e30fb1499af8c619108ffea4d300b5e778 b/tests-clar/resources/merge-resolve/.gitted/objects/18/3310e30fb1499af8c619108ffea4d300b5e778 new file mode 100644 index 0000000000000000000000000000000000000000..1c4010d0479c8f28d62969968746d6c346597c5c GIT binary patch literal 170 zcmV;b09F5Z0i}*nYQ!)MMEmVi_yQ?%6e|vtWq*2uy?`vqB+$gg>us;!Z0Qa9H}f70 zBX!@m?#CEjdNcE!(yWRLE1D_=D6&98l}y1V;2eQw)Zjk3+0nfa%ta7VLPLydWlW-! zD92Dp3d5LzOdLP@TAP2@Z*J;uYu)el@Nag~XS&+2_-n6H_lpl0M_8s5$qzsP?xg40 YZvUKdy=`9`e+<)*8y~W|ANj&k)P+J+s{jB1 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/18/cb316b1cefa0f8a6946f0e201a8e1a6f845ab9 b/tests-clar/resources/merge-resolve/.gitted/objects/18/cb316b1cefa0f8a6946f0e201a8e1a6f845ab9 new file mode 100644 index 0000000000000000000000000000000000000000..30f3110f122695066575e549207def7ff17a06ca GIT binary patch literal 68 zcmV-K0K5Nq0ZYosPf{>8GiE5s$ShVU&&>GO3h2mO-)hA%u~oOEh^?p%u7*7 aNzF+ufryo4q-Fv|xkmMn6$Suk#)28*xEz!K literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/19/b7ac485269b672a101060894de3ba9c2a24dd1 b/tests-clar/resources/merge-resolve/.gitted/objects/19/b7ac485269b672a101060894de3ba9c2a24dd1 new file mode 100644 index 0000000000000000000000000000000000000000..e34ccb855c0976b4a5f87a375b8af037a39364b7 GIT binary patch literal 53 zcmV-50LuS(0ZYosPf{>3W(Z2n%`Zz$QOL|wP&ZdsNGdH+$jwj5Ov{9c=_VB=<|SvS L>u~`9q0|r1O8^$N literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/1c/ff9ec6a47a537380dedfdd17c9e76d74259a2b b/tests-clar/resources/merge-resolve/.gitted/objects/1c/ff9ec6a47a537380dedfdd17c9e76d74259a2b new file mode 100644 index 0000000000000000000000000000000000000000..30802bcecd777a4452e76f2739946e26dfe9e50a GIT binary patch literal 33 pcmb9GG;I|FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nPt zDo)Nw%u9!uo>Y{Wmz)9CusX+O(F>PJYrP$JXRm2DwVTVdrW;cOl5+&_t!CJCdD+*+ z?3NvCSb21-(?TD?H00-{tM4hkQNjP177p((5LESpDk4 M6PtOl0L5v7+NnT@tpET3 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/20/91d94c8bd3eb0835dc5220de5e8bb310fa1513 b/tests-clar/resources/merge-resolve/.gitted/objects/20/91d94c8bd3eb0835dc5220de5e8bb310fa1513 new file mode 100644 index 0000000000000000000000000000000000000000..a843890c07c438afbf35caec02aa95cb7ed8e0bf GIT binary patch literal 271 zcmV+q0r38K0V^p=O;s>9w_q?dFfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRZhlH; zS|-Fbh9<}kQWLeZ|C};AM|)e)gf0V^p=O;s>AVK6i>Ff%bxNXyJgHPkDqC}9w>f^`v?#EoR&lyh^e#{@%Ki-H+b=~r`cK9q$OdT=Amb4 zI7AhRQQ6|k1TmDowh)aFv52xGJ)>tva{@OO-j*2g#va!7L?mJgZg5!K5&nhe+pk}` I0OLKb{)H1UA^-pY literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/23/3c0919c998ed110a4b6ff36f353aec8b713487 b/tests-clar/resources/merge-resolve/.gitted/objects/23/3c0919c998ed110a4b6ff36f353aec8b713487 new file mode 100644 index 0000000000000000000000000000000000000000..d0c8c9e1df90d8ef56a1aefeeed35636eed062cb GIT binary patch literal 43 zcmb literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/23/92a2dacc9efb562b8635d6579fb458751c7c5b b/tests-clar/resources/merge-resolve/.gitted/objects/23/92a2dacc9efb562b8635d6579fb458751c7c5b new file mode 100644 index 0000000000000000000000000000000000000000..86127a344bcd2dc01885a87ad9e6aa346a11d7c4 GIT binary patch literal 142 zcmV;90CE3#0i}(>4FVw$0DV)%HlSHK5J-&iV+S_CElchaVH0kR?R(bXZ!(V=lGauQ zi_<{|GgJyC%n^MJIXN4BaMjg_cD6h@Di-scN=hcbb&&y&^2wvXbCI@5hb!;)NB6eU wkWH$dNZJj~)5V9gOFqI8J)+s|K34uCVFvfy7)W}3t)!4U@uo7&7i`-^t=uR3FlQ*q$ShVU&&>GO3h2mO-)hA%u^`INX;xN=1R;< ZQAkb6EP)8-mjZ>jMzzpB!~oPvkr~kB9dG~u literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/24/2591eb280ee9eeb2ce63524b9a8b9bc4cb515d b/tests-clar/resources/merge-resolve/.gitted/objects/24/2591eb280ee9eeb2ce63524b9a8b9bc4cb515d new file mode 100644 index 0000000000000000000000000000000000000000..74a01373f44bdc87acb162136fd0dbe4527f9b49 GIT binary patch literal 30 mcmbxmhoiK()PmVkaVRdHKV~G30t^@$Pd<$;? literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/24/90b9f1a079420870027deefb49f51d6656cf74 b/tests-clar/resources/merge-resolve/.gitted/objects/24/90b9f1a079420870027deefb49f51d6656cf74 new file mode 100644 index 0000000000000000000000000000000000000000..60497caa56d0a276b89635791f80b13b00d2f717 GIT binary patch literal 268 zcmV+n0rUQN0V^p=O;s>9GGH(?FfcPQQAjK;$5Ep%1PBLsVHH1XTNaA0j~e` z4-``WZskbX%{y7=JXCRVMq*xiYKm@Vo^Dc6VqS6vSi|ZZmqjmJCav{$+?~Cq-PCR_ z)0%Ef4Y`TMC8e=fv*f{a1iuE!bovhP9-F9muI>{qbKCqCrsS#O%=Sdv~h S@x$s@7oOP6iv<9|ErgF|_<-vG literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/25/9d08ca43af9200e9ea9a098e44a5a350ebd9b3 b/tests-clar/resources/merge-resolve/.gitted/objects/25/9d08ca43af9200e9ea9a098e44a5a350ebd9b3 new file mode 100644 index 0000000000000000000000000000000000000000..2bae66998977385146fbe69aeb71f387b4ba800d GIT binary patch literal 381 zcmV-@0fPQ`0V^p=O;s>4Gh{F{FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nOy zF#rOEr2LW$-IUCtVg^&5yv>Y!e;ll`-)1NqB?pVVd>a8ZFgYVJFCF57q@u*UOYd*4uG+_L_E6ySYqjx-m5%Ia%=DYKBdhmwjE#ZrQPhl}EQaE%XsgLw;Ub zPG)jRW?nkjY`>1Y1XaybD_09%mv2k}vs=3?Y6_%Y+6?{=WG;V%n}>bdE3T zT_Umff6y_9l~5CkQgidmFuZ*K@h9z7^7-dN+$YEwwC#GFaWDHWR6{8+SiqqKcK?YF b`Fhryra6|R*G>Ge`qhOeHuGWur60HSw0OLC literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/25/c40b7660c08c8fb581f770312f41b9b03119d1 b/tests-clar/resources/merge-resolve/.gitted/objects/25/c40b7660c08c8fb581f770312f41b9b03119d1 new file mode 100644 index 0000000000000000000000000000000000000000..185214727f41552c6820f66bf63641d28505021e GIT binary patch literal 31 ncmbL(MnP81`KAxtJm>9ygvkL$KyV?si literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/26/153a3ff3649b6c2bb652d3f06878c6e0a172f9 b/tests-clar/resources/merge-resolve/.gitted/objects/26/153a3ff3649b6c2bb652d3f06878c6e0a172f9 new file mode 100644 index 0000000000000000000000000000000000000000..4fcaa07e228f0f20883cb11889c7b2bf3af0bc2c GIT binary patch literal 48 zcmV-00MGw;0ZYosPf{>8V(`sR$xO>kO;O0qQ&2A{$}G!F%+WP8(M>8!%uCKt=K=r< Gt_7HfJy~00M=i{E`gal+2=Hh9%O{+b-<0QTm&@!ZK-Ar!bX?Dpyx@zbD6GK&}#)8#aoDm3ypo%2b) zAU1Pb)t$$Nh6V;^CMF7LnK`L?B^4zMU2Es^EjF1dyQDfv%01fhOy2d#{QwO{Hryq0 BNbLXs literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2b/5f1f181ee3b58ea751f5dd5d8f9b445520a136 b/tests-clar/resources/merge-resolve/.gitted/objects/2b/5f1f181ee3b58ea751f5dd5d8f9b445520a136 new file mode 100644 index 0000000000000000000000000000000000000000..d24231eda0f690b57f01446f58ae5499ab63533d GIT binary patch literal 53 zcmV-50LuS(0ZYosPf{>3Heo2q$ShVU&&>GO3h2mO-)hA%u^`INX;xN<{FhA Lbio1u#AcpFSWp&g literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2b/d0a343aeef7a2cf0d158478966a6e587ff3863 b/tests-clar/resources/merge-resolve/.gitted/objects/2b/d0a343aeef7a2cf0d158478966a6e587ff3863 new file mode 100644 index 0000000000000000000000000000000000000000..d10ca636b6bf5f66bce633362d871d17d9a292c6 GIT binary patch literal 56 zcmV-80LTA$0ZYosPf{>3VkpVTELKR%%t=)M(#aW#dFiPs3YmEdNkxfy$r%cXc_|9H OiNz(UMO*-@y%7?c&=$P_ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2d/a538570bc1e5b2c3e855bf702f35248ad0735f b/tests-clar/resources/merge-resolve/.gitted/objects/2d/a538570bc1e5b2c3e855bf702f35248ad0735f new file mode 100644 index 000000000..83253f81c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/2d/a538570bc1e5b2c3e855bf702f35248ad0735f @@ -0,0 +1,2 @@ +xK +1D]N"n{t:L$ UEQ>~7:L D [5ɇ,y2eT@z*.([žunum3VhBpj%`Zz$QOL|wP`A`gDoV^t&QMoKDlJjS%}>cp%Y;d( Ka{&OEIuE5qZx!?a literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2f/4024ce528d36d8670c289cce5a7963e625bb0c b/tests-clar/resources/merge-resolve/.gitted/objects/2f/4024ce528d36d8670c289cce5a7963e625bb0c new file mode 100644 index 0000000000000000000000000000000000000000..0100fd70e832555800236cc897868c9a56402c62 GIT binary patch literal 179 zcmV;k08IaQ0iBLZYQr!PhP&1&bb*Gk9y1bzkWFvUz0qTY4V4vSgi~AMo*| zR_i*Xvh*=Jv-C{GXzPtDL_|8cfUYV{^3jR49TAo&RnKpg8K hJNONZLp1iph{HToo>SY(&zi_|Št@ +apg%haJYծA8թ훠fN4;h[%cOuJWyΏ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2f/598248eeccfc27e5ca44d9d96383f6dfea7b16 b/tests-clar/resources/merge-resolve/.gitted/objects/2f/598248eeccfc27e5ca44d9d96383f6dfea7b16 new file mode 100644 index 000000000..1d9f226e2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/2f/598248eeccfc27e5ca44d9d96383f6dfea7b16 @@ -0,0 +1 @@ +x+)JMU067c040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvQjn~13zדm9Wu]:$I{| 2mg˾15ӿ,\})TC)0Pavz֛9MՅ'6b \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/31/68dca1a561889b045a6441909f4c56145e666d b/tests-clar/resources/merge-resolve/.gitted/objects/31/68dca1a561889b045a6441909f4c56145e666d new file mode 100644 index 000000000..2de1c5a79 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/31/68dca1a561889b045a6441909f4c56145e666d @@ -0,0 +1,2 @@ +xQ +0D)rJMxMHz}xfރaRYipkUD $1fQ2q-=Y3R76ġg9e7 bw GJe*˽ |ůSY"5&Нƨng9Z3_;kdO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/31/d5472536041a83d986829240bbbdc897c6f8a6 b/tests-clar/resources/merge-resolve/.gitted/objects/31/d5472536041a83d986829240bbbdc897c6f8a6 new file mode 100644 index 0000000000000000000000000000000000000000..5ec5acb596853e163ca7c0de2dddb36f8ed17446 GIT binary patch literal 41 zcmV+^0M`F_0ZYosPf{>4X9&s2ELKR%%t=)M(s`-n3YmEd`N<{u#(G=;%D@XAcs~+| literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/32/21dd512b7e2dc4b5bd03046df6c81b2ab2070b b/tests-clar/resources/merge-resolve/.gitted/objects/32/21dd512b7e2dc4b5bd03046df6c81b2ab2070b new file mode 100644 index 0000000000000000000000000000000000000000..d36138d796c849f28fc5131ef23a56a58b747c01 GIT binary patch literal 47 zcmbSr<#>h{|9Gnb DkgXG9 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/33/46d64325b39e5323733492cd55f808994a2475 b/tests-clar/resources/merge-resolve/.gitted/objects/33/46d64325b39e5323733492cd55f808994a2475 new file mode 100644 index 0000000000000000000000000000000000000000..11546cea449c383f0c292d17e7e773de4c722ed3 GIT binary patch literal 33 pcmby>隿ïm6*Rn>O \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/34/bfafff88eaf118402b44e6f3e2dbbf1a582b05 b/tests-clar/resources/merge-resolve/.gitted/objects/34/bfafff88eaf118402b44e6f3e2dbbf1a582b05 new file mode 100644 index 000000000..c653cec50 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/34/bfafff88eaf118402b44e6f3e2dbbf1a582b05 @@ -0,0 +1 @@ +xKj1D) >`7A. $<`Morlm4G&dVd[j2JCъgu_Gu%2:3XزQ'";?wpkm׾&Pf! %QJ%:Cez=6q;iO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/0c6eb3010efc403a6bed682332635314e9ed58 b/tests-clar/resources/merge-resolve/.gitted/objects/35/0c6eb3010efc403a6bed682332635314e9ed58 new file mode 100644 index 0000000000000000000000000000000000000000..2eee602335c69d4c9f13f8a8b4e3e20096b21190 GIT binary patch literal 92 zcmV-i0HgnS0V^p=O;xZoWH2-^Ff%bxNK8pdP0`KF(@n}R$LJ2x0gUIYNNCnV+hk|<>W literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/411bfb77cd2cc431f3a03a2b4976ed94b5d241 b/tests-clar/resources/merge-resolve/.gitted/objects/35/411bfb77cd2cc431f3a03a2b4976ed94b5d241 new file mode 100644 index 0000000000000000000000000000000000000000..ea024ccd9e3dce798de1762fcababd72d55f9e43 GIT binary patch literal 31 ncmbL(MnP81`KAxsem>9ygvhxD~yWtBo literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/4704d3613ad4228e4786fc76656b11e98236c4 b/tests-clar/resources/merge-resolve/.gitted/objects/35/4704d3613ad4228e4786fc76656b11e98236c4 new file mode 100644 index 0000000000000000000000000000000000000000..1dd13c44a00f1c388d5b23fa12cdb68a82fde9c7 GIT binary patch literal 41 xcmb5!L_z literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/632e43612c06a3ea924bfbacd48333da874c29 b/tests-clar/resources/merge-resolve/.gitted/objects/35/632e43612c06a3ea924bfbacd48333da874c29 new file mode 100644 index 000000000..be7684f19 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/35/632e43612c06a3ea924bfbacd48333da874c29 @@ -0,0 +1 @@ +xN !LdMb60^,40;iUFf+)1vB939fG(DIݸʵA$sk]l|L{Ig$m.N5y.\a/]|Ʋ@[g4< Hl?gTsˠzCP \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/35/75826c96a975031d2c14368529cc5c4353a8fd b/tests-clar/resources/merge-resolve/.gitted/objects/35/75826c96a975031d2c14368529cc5c4353a8fd new file mode 100644 index 0000000000000000000000000000000000000000..24e33bc41cfc3d41d574d366c4311ffd44d005a9 GIT binary patch literal 163 zcmV;U09^lg0i}*z3c@fDgniB_a)HWj^A94vcmpr6Nj9`#8;Mb`ZxwIg+syaDFsUxf z+~uhCt~X{0*^I2n7|ZBGBna9Q8|yp-^njQ!qIFr^sPWpRGvpCtu`wBEgQgr+VGG)M zTNG(78B@k6=+URzxtJKOos R8PVJPoas7v@dn@TPdO==P_O_1 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/36/219b49367146cb2e6a1555b5a9ebd4d0328495 b/tests-clar/resources/merge-resolve/.gitted/objects/36/219b49367146cb2e6a1555b5a9ebd4d0328495 new file mode 100644 index 0000000000000000000000000000000000000000..7f8044372ad4d15a6ed522b15fa7c3fdcb6f01fd GIT binary patch literal 68 zcmV-K0K5Nq0ZYosPf{>3G-W8s$ShVU&&>GO3h2mO-)hA%u~oOEh^?p%u7*7 aNzF+ufryo4q-Fv|xkmNSEers*8I)M#?Hu0# literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/36/4bbe4ce80c7bd31e6307dce77d46e3e1759fb3 b/tests-clar/resources/merge-resolve/.gitted/objects/36/4bbe4ce80c7bd31e6307dce77d46e3e1759fb3 new file mode 100644 index 0000000000000000000000000000000000000000..90fd9651f8c2a1f4e6803607a09b2f47b8ce092b GIT binary patch literal 35 rcmb4X9&s2ELKR%%t=)M(s`-n3YmEd`N<{urg~fe%Ek*IcT*B@ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/38/5c8a0f26ddf79e9041e15e17dc352ed2c4cced b/tests-clar/resources/merge-resolve/.gitted/objects/38/5c8a0f26ddf79e9041e15e17dc352ed2c4cced new file mode 100644 index 000000000..e95ff3a88 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/38/5c8a0f26ddf79e9041e15e17dc352ed2c4cced @@ -0,0 +1,2 @@ +x-MK +1 uSYRą6C6뛪oknYt Ep iDCddLB+8%qk +e6fHB1J4F1l \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/3b/47b031b3e55ae11e14a05260b1c3ffd6838d55 b/tests-clar/resources/merge-resolve/.gitted/objects/3b/47b031b3e55ae11e14a05260b1c3ffd6838d55 new file mode 100644 index 0000000000000000000000000000000000000000..82086466f5eb3142bf86233dbb9d3600ec655264 GIT binary patch literal 161 zcmV;S0ABxi0i}-J4FVw$gngz88aT7S@w16BzSw~cz_R2_yu%>I_C;d{zRi4-%na3a zy>_W*wd;*p0(ut`XRTcT$_au+7fgxhyeFcNZPb>OxW~p@mz)SNgEF2<0@BW*k30Zi zNjRIB5nM4v#Ajb>ljr=3Ez8SN*GJvtfd~Dl6MuuB+f!YSQW>jZtSc)gZ~$V^aklfH PHNwVQpR{-bS`tn#OrcCs literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/3b/bf0bf59b20df5d5fc58b9fc1dc07be637c301f b/tests-clar/resources/merge-resolve/.gitted/objects/3b/bf0bf59b20df5d5fc58b9fc1dc07be637c301f new file mode 100644 index 0000000000000000000000000000000000000000..723a9ae4c919bbd0cad50bb475b5a80764e28dd0 GIT binary patch literal 269 zcmV+o0rLKM0V^p=O;s>9GGH(?FfcPQQAjK;$5Ep%1PBLsVHH1XTNaA0j~e` z4-``WZskbX%{y7=JXCRVMq*xiYKm@Vo^Dc6VqS6vSi|ZZmqjmJCav{$+?~Cq-PCR_ z)0%Ef4Y`TMC802Pi7oB#j- literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/3e/f9bfe82f9635518ae89152322f3b46fd4ba25b b/tests-clar/resources/merge-resolve/.gitted/objects/3e/f9bfe82f9635518ae89152322f3b46fd4ba25b new file mode 100644 index 0000000000000000000000000000000000000000..3b5998ca61dbf820b46e70619c4143407fa11688 GIT binary patch literal 172 zcmV;d08{^X0i}*j4#FT5gk5tAE}-G3JZNH!8*kvg0p25RBE?V|uP+*J;BMxdWM*Q? zd1+i3b7+-_kILdO4mx7MIC=n!!4asKQ20SQE0i|TNcQxV*2V)RAZ>#t06V=yrQ0)>>!B8IEWq`5sOE%|V2Mf)#~tty7k)pzF`8W@"nt:x}xwUxjum'뫈.9=y 6$@T8&Lhf4Aܻf0B(.K>9S< +z_f}]Z]eO:wzރP.ިaNU6O \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/43/aafd43bea779ec74317dc361f45ae3f532a505 b/tests-clar/resources/merge-resolve/.gitted/objects/43/aafd43bea779ec74317dc361f45ae3f532a505 new file mode 100644 index 0000000000000000000000000000000000000000..ac86823b67ad33129ed2a6874cb5ed85a4318ec0 GIT binary patch literal 37 tcmb9G-oh0FfcPQQAjK;$5Ep%1PBLsVHH1XTNaA0j~e` z4-``WZskbX%{y7=JXCRVMq*xiYKm@Vo^Dc6VqS6vSi|ZZmqjmJCav{$+?~Cq-PCR_ z)0%Ef4Y`TMC8-4F=Qyo$ShV!%gjkt0Md!2CHc9jMd_)DNja%pLrlujKvkhQ QGdD9Qu?U~j0Zl+!Z0_9{>i_@% literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/46/6daf8552b891e5c22bc58c9d7fc1a2eb8f0289 b/tests-clar/resources/merge-resolve/.gitted/objects/46/6daf8552b891e5c22bc58c9d7fc1a2eb8f0289 new file mode 100644 index 0000000000000000000000000000000000000000..c39b53aa8f4435495440249b2c4b1186bce3460f GIT binary patch literal 382 zcmV-^0fGK_0V^p=O;s>4Gh{F{FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nOy zF#rOEr2LW$-IUCtVunN$zIWG6_?NAy)O|lI(qeb4i^*=Nfyo((dFc=rBo!s*C1-#Q zU7h2y=!MIqwcd`qv)8nn+RbHJ(~YSC$;pEERx@n6yzJ{@cFT@6tUS8aX`zo`8uIhf zax#-kGV{{GX8U#IC8%niTDe;Ax_n!*_r+}w?g>DZrliG#!-GLx*mgP7E}Mk)T8uAq zR73wexL%tCQsGnKH|N-zXI~50WC-zdS|&7D^7qZ(5z}`4qH}yv z?-Gf<|AUS>tc03Sl$x7ghT-M=k3VUzlFvUE;yyvfpl#RVjC8-%)vqo*v6&YO02yex1P1}fp#T5? literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/47/6dbb3e207313d1d8aaa120c6ad204bf1295e53 b/tests-clar/resources/merge-resolve/.gitted/objects/47/6dbb3e207313d1d8aaa120c6ad204bf1295e53 new file mode 100644 index 0000000000000000000000000000000000000000..3e5f66e5560744991baf7532f0bb954b9600e11f GIT binary patch literal 522 zcmV+l0`>iP0V^p=O;xZkGh#3_FfcPQQ7}l<&CAzK&PdElPt_}_C}GGrcEX!eQtkLn zu4T(-Yaia7b?0m!Ol^{GQEGWnW=TnEo^EEIZhmP|F<8%sbJ~5LZ5+O{4f?mMb3PF{ zWViJhOiwbZo|25zOsFpXFd;_vYYjrPVy92ss(4zic+p!!s4l}qpsu{c+|(49J-VqW znI#Y|k`ae5=)Lb$IDB|J>J^4Jn-w? z*#6lrp$ZGlpn8muZB5EA$pC8*?{wG_@X2Cn4sYr9sWDrtEhHtIpc;%Z11BXlClxbv zBu*P<%e-IkW7(8^J_V^hsr;6xoiH=7`4!0&xM$52XM36zx}Da`5)IwD^7WMqMlDmJ zW|&~QBQYffBaW2HCvDYQ#jV`^is4ONz-*=@d$Asv3D{f#Hv{g58CP}L4{X@|X-lfd zw^czxQxBaEy$vq40teuYU*+4H4Vn(VGTYwN6`||n+@TTx)ntaM zsW>wwRo4)#X^Xnh`Iob#0=TsT|IP5@?kZ>6C5T58#HMZYUzk5RcmB%BB|LYQAGC05 MYroG904*0qfHpz+zW@LL literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/47/8172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 b/tests-clar/resources/merge-resolve/.gitted/objects/47/8172cb2f5ff9b514bc9d04d3bd5ef5840cb3b2 new file mode 100644 index 0000000000000000000000000000000000000000..d9e250e6664438ecd41046a769dab963dd08e2df GIT binary patch literal 165 zcmV;W09yZe0i}*n4#FT1ME&LzT%cxwvO;2vKiOoDGt{LHw*+B?SobySt4V*CG zU6`fRD literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/49/130a28ef567af9a6a6104c38773fedfa5f9742 b/tests-clar/resources/merge-resolve/.gitted/objects/49/130a28ef567af9a6a6104c38773fedfa5f9742 new file mode 100644 index 0000000000000000000000000000000000000000..e2c49f5c45ebcceed1bcfdd595a2c5be008a778f GIT binary patch literal 37 tcmbtR22&{sO^Tl}?;T=y^QaQ46y9M}m0fEje0 V?fTCdgL3QB(&WgSc>?+*PaNcdRCE9U literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4c/a408a8c88655f7586a1b580be6fad138121e98 b/tests-clar/resources/merge-resolve/.gitted/objects/4c/a408a8c88655f7586a1b580be6fad138121e98 new file mode 100644 index 0000000000000000000000000000000000000000..15cb7f29af812ea83abf3da21b8d664ebc3053db GIT binary patch literal 159 zcmV;Q0AT-k0i}*h4gw(%L|t(zG%FGyH~H0N~Koo zZAfikH#+kKf=ERLaAY)i2cTVMF40gym90gaiZkLKI&VXgbIFoLMG3-FQ6X z$Fy~x-**>0-t3#1t1WXAR?a>}45Da~OOob2#H2}USHVuxN7-!I9mbxB6LRZHP(X?d zKQaePq{&PTDnz{MIcbw>S_!CgrN}_FdzR2kksin=<=8HIhGwFofP@ky8^y-sxNO!D zvq8(=NUryApqQ)g(V8E&F!obW^$e=45jc$he6gu~?#Fd=&-zt1b+5;DKCO#;u)+SI zC;M&uRrhV3A02weBn%nd9WcN&*b&}t{~R;D*!DJ}-^$XCc5;Wc?JFK`&wwt#A6!}V MOoqes4Yh%VE1n{S9RL6T literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4e/886e602529caa9ab11d71f86634bd1b6e0de10 b/tests-clar/resources/merge-resolve/.gitted/objects/4e/886e602529caa9ab11d71f86634bd1b6e0de10 new file mode 100644 index 0000000000000000000000000000000000000000..53168a038b77edb9bb0073f155cf7e2315c07f59 GIT binary patch literal 56 zcmV-80LTA$0ZYosPf{>3VkpVTELKR%%t=)M(#aW#dFiPs3YmEdxrxOksYMEjc_|7> OMTvRI8C(FZ2N4pV?iL9E literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/4e/b04c9e79e88f6640d01ff5b25ca2a60764f216 b/tests-clar/resources/merge-resolve/.gitted/objects/4e/b04c9e79e88f6640d01ff5b25ca2a60764f216 new file mode 100644 index 0000000000000000000000000000000000000000..f4ec0efecb41f295973d32a8d8714c6003cdd54e GIT binary patch literal 34 qcmbMm*mHjKlI>-x^RwRVL07t|lYWDr+e@8~)?x6Fh+4 J7+ib=ngRRb6OsS` literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/50/ce7d7d01217679e26c55939eef119e0c93e272 b/tests-clar/resources/merge-resolve/.gitted/objects/50/ce7d7d01217679e26c55939eef119e0c93e272 new file mode 100644 index 0000000000000000000000000000000000000000..e2f9f67fdf9f04909cb4b067bb05982887bc686a GIT binary patch literal 159 zcmV;Q0AT-k0i}-74FVw$ME#};8qh2U3v6PHKXzaPuq-)0ILwK$eNSTt&ezPFWHQ`a zyA3@#*o{?0Gv+Lakf{PW=W^L(g{v(T7_ysE3emH=r&X4rDFpW9(GX*@0FJSmVz7AN zNF_^-b+TAhdXBlT`chtLE&4k5_UMZ~%0@r#EZ^dn4&2*G8;d3eM-=rQ5I}8oJ3Hjh N8P$1otKOQ@Y$wPd_em07lC}d8I^8``N~S YV#0cThS//SYe'+~mrh\cQwFMQϙ]b5M R \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/53/825f41ac8d640612f9423a2f03a69f3d96809a b/tests-clar/resources/merge-resolve/.gitted/objects/53/825f41ac8d640612f9423a2f03a69f3d96809a new file mode 100644 index 0000000000000000000000000000000000000000..08cb0b66fe7341717f2a9cffd560cb5881568657 GIT binary patch literal 164 zcmV;V09*ff0i}-14FWL`Lpi64G_Yv$n@uEyxX=L&t~VkMP6Y}XW|@)>A$V)8QiyZHoJkvmyJ?(_kܖ6-$#-Zzvȟ3 +:NqMB \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/54/7607c690372fe81fab8e3bb44c530e129118fd b/tests-clar/resources/merge-resolve/.gitted/objects/54/7607c690372fe81fab8e3bb44c530e129118fd new file mode 100644 index 0000000000000000000000000000000000000000..dccd220068018e53496f4cd75b5184f91c646594 GIT binary patch literal 58 zcmV-A0LA}!0ZYosPf{>3VJOMSEan2Dl*}Uiw9K4TBfXM}5-yG8jKsY3)D(rxJcX3B Q_~OizR3l9;0Kl>k$^Rb[{=coj'|褯UjeKLnn5СPY|2`zzQ{ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/57/079a46233ae2b6df62e9ade71c4948512abefb b/tests-clar/resources/merge-resolve/.gitted/objects/57/079a46233ae2b6df62e9ade71c4948512abefb new file mode 100644 index 0000000000000000000000000000000000000000..c7eabc46b2d774774dcc7b7caa89f632b5703db5 GIT binary patch literal 168 zcmV;Z09XHb0hNwP4gw(%MO||WE}(&eVn~c};|<&!h9cdIZVZj_`l9Izxcfu?%TIM# z=FUN@LvKV}8q(XK1u`o;3(ttQ`OpB2rQcL)6w5 z4=^S0rmOTprt;3D^hVy-y-?yGlI( literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/58/43febcb23480df0b5edb22a21c59c772bb8e29 b/tests-clar/resources/merge-resolve/.gitted/objects/58/43febcb23480df0b5edb22a21c59c772bb8e29 new file mode 100644 index 0000000000000000000000000000000000000000..f6b2a2bfeb4d48d806b494808d911568d1f0596e GIT binary patch literal 71 zcmV-N0J#5n0ZYosPf{>4He@i>w^Yc<%u6j+NGwWK$jnnn&d<%w&*Lh|$ShV!%gh0a d0i{Yy@^e#*(o++Ya#FeIqlLN-0066CQ>C;SA)^2Q literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/58/e853f66699fd02629fd50bde08082bc005933a b/tests-clar/resources/merge-resolve/.gitted/objects/58/e853f66699fd02629fd50bde08082bc005933a new file mode 100644 index 0000000000000000000000000000000000000000..cf6db633cb14c78d897ce66f18b6c3b8eaf0be8e GIT binary patch literal 160 zcmV;R0AK%j0i}-14Z<)GL^-<(Hvn3%Kgmi6aiIemSlb&V2gk@UqJ09Q18y_#Nux=% zl%;EQaOh1$qo)jGVrO|G1P~G?1{%dV_G~>!%oMG9aFexbKfplj0$R(0G2|(r5N8=o za^yyDkfTgd@w3mh>05qr%lbaovei|eWv8EXm9O}x{njrHCHasl)a0)X1-ezwb> OGiqD1pn3x#AWl##I7qhu literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/59/6803b523203a4851c824c07366906f8353f4ad b/tests-clar/resources/merge-resolve/.gitted/objects/59/6803b523203a4851c824c07366906f8353f4ad new file mode 100644 index 0000000000000000000000000000000000000000..cbc8cbef31cfa7d4903799d2b4ff665e98991f28 GIT binary patch literal 163 zcmV;U09^lg0i}*z3c@fDgniB_a)HWj{tF_$cmpqxZZ@=F8;Mb`ZxnAJ^D^@d3`1pI zmnN05yH=ScSj;*35ilB~a?I9EN;&K@BY2b1k|*QEEmq!|BnLi|h7dGsZ4+k|D7oOK zKIAAzP!l*N5g%%AflE7H~`UUKil}v R8PV$UT;g>=Bi;=0PayLcMuh+X literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5c/2411f8075f48a6b2fdb85ebc0d371747c4df15 b/tests-clar/resources/merge-resolve/.gitted/objects/5c/2411f8075f48a6b2fdb85ebc0d371747c4df15 new file mode 100644 index 0000000000000000000000000000000000000000..7b41413dad72f58fe84603614b4841980a210781 GIT binary patch literal 37 tcmb4V<^eUELH%bqSV~{veXoX%shqM#Nv|FA}#>O3=5lsKNCg( literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5d/c1018e90b19654bee986b7a0c268804d39659d b/tests-clar/resources/merge-resolve/.gitted/objects/5d/c1018e90b19654bee986b7a0c268804d39659d new file mode 100644 index 0000000000000000000000000000000000000000..7500b99146bf4f8687cc39ff009bb767740ab83e GIT binary patch literal 168 zcmV;Z09XHb0hNwT3c@fDgE2 z#$ZkqH5=4HgjbtNl{b2aO7cFHWh<*Zb5FnO%D-ZFr&N}U)D|2dD1-8-yi%g4{cPjE WF`)hEtllw#@?)EcwfF#MV^6TQs!*%| literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5d/dd0fe66f990dc0e5cf9fec6d9b465240e9537f b/tests-clar/resources/merge-resolve/.gitted/objects/5d/dd0fe66f990dc0e5cf9fec6d9b465240e9537f new file mode 100644 index 0000000000000000000000000000000000000000..9d8691eb231f4bb873bb27c7ba7f170cac33bda3 GIT binary patch literal 43 zcmbfc@eT%#r#wpmh@cW4 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/5e/b7bb6a146eb3c7fd3990b240a2308eceb1cf8d b/tests-clar/resources/merge-resolve/.gitted/objects/5e/b7bb6a146eb3c7fd3990b240a2308eceb1cf8d new file mode 100644 index 0000000000000000000000000000000000000000..aca2666cfbbc4bc54b331124e3fd1219af9ba422 GIT binary patch literal 268 zcmV+n0rUQN0V^p=O;s>9GGH(?FfcPQQAjK;$5Ep%1PBLsVHH1XTNaA0j~e` z4-``WZskbX%{y7=JXCRVMq*xiYKm@Vo^Dc6VqS6vSi|ZZmqjmJCav{$+?~Cq-PCR_ z)0%Ef4Y`TMC84Fk>(@FfcPQQAo~6%u7#A(ap@$O)5&vOU}?MsVHGso#V3T zh0CP1-j2Jo*R-43&1G8Cjj16wvA86)h@gi2ytJImJK(OvPIRvu)a;_v-25^O$J~GXNqd!i{<#qM2{Hz4yB=rU%f5@L0m(5j))~v?kNk=? z)4$vv7c5+p6}5dSTti-BF3<*31F%~nod50FWYTb-JMOm9BALkJMZ5bn(Nvn7f>kcB z3R^P2-|CUm19kC_eY=nG#2j@-Q)vk?(^Yeh%+d$dyX0?jIJ4$&jr^G{9|cue3JhOx haD$CJ@gZN&debz=lJvTXA6CD*@Wf_bEC3IeppN(ik30YX literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/60/91fc2c036a382a69489e3f518ee5aae9a4e567 b/tests-clar/resources/merge-resolve/.gitted/objects/60/91fc2c036a382a69489e3f518ee5aae9a4e567 new file mode 100644 index 0000000000000000000000000000000000000000..fa63afba1ca8ab9a3ce31f0d78e2a27de4e1a923 GIT binary patch literal 258 zcmV+d0sa1X0V^p=O;s>9GG#C{FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su{!Ffqg$O8`Us{WKQApOGr1%)FCDD(iu!|1 z4=nwQCzLNvmJ{9U231;=nwwvS;h6i6KWVR$&p#L9K0(HyZP(+Bd)ap}H6S@A z#yVrU{E=U=X8M=g8-%)vqo*v6&YO I051iBvbQ&TDgXcg literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/61/340eeed7340fa6a8792def9a5938bb5d4434bb b/tests-clar/resources/merge-resolve/.gitted/objects/61/340eeed7340fa6a8792def9a5938bb5d4434bb new file mode 100644 index 0000000000000000000000000000000000000000..e830cafe5eff805763300f2b48d7c9200bfda9e7 GIT binary patch literal 92 zcmV-i0HgnS0V^p=O;xZoWH2-^Ff%bxNK8pdP0`KF(@n}R$y(6_CBq$XC literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/61/78885b38fe96e825ac0f492c0a941f288b37f6 b/tests-clar/resources/merge-resolve/.gitted/objects/61/78885b38fe96e825ac0f492c0a941f288b37f6 new file mode 100644 index 0000000000000000000000000000000000000000..bedc5f27ecdb5d005c8e8c787350359c204911de GIT binary patch literal 289 zcmV++0p9+20V^p=O;s>9He@g~FfcPQQAo)w(ls<-$YHy4F*%|}=V12}kMIZE1;s41 zUL&b6V{l&e*LmOa$~Ps3wTBbGL_Pj$w3HP|fjPqh!$n=s`HYu2p7ZYNPZs~Uy7Jx= z69XUsTVcTv(DFyCW82zu3&FX8D n-zfWSNI0ZYosPf{>4F=i;q$ShV!%gjkt0Md!2CHc9jMd_)DNja%p!&M3ZEje5) D!8{Wo literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/62/269111c3b02a9355badcb9da8678b1bf41787b b/tests-clar/resources/merge-resolve/.gitted/objects/62/269111c3b02a9355badcb9da8678b1bf41787b new file mode 100644 index 0000000000000000000000000000000000000000..0edf6599447ee43958038f7768201d1320ca0e42 GIT binary patch literal 269 zcmV+o0rLKM0V^p=O;s>9GGH(?FfcPQQAjK;$5Ep%1PBLsVHH1XTNaA0j~e` z4-``WZskbX%{y7=JXCRVMq*xiYKm@Vo^Dc6VqS6vSi|ZZmqjmJCav{$+?~Cq-PCR_ z)0%Ef4Y`TMC89V=y!@Ff%bxNXyJg)hnqeVJKV8r;#C9cQE4awd1{Ay!zK| LEq($3HxCdv1CbQA literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/63/247125386de9ec90a27ad36169307bf8a11a38 b/tests-clar/resources/merge-resolve/.gitted/objects/63/247125386de9ec90a27ad36169307bf8a11a38 new file mode 100644 index 000000000..bc2d7384d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/63/247125386de9ec90a27ad36169307bf8a11a38 @@ -0,0 +1 @@ +xݏ;1 D}AV\8HIVp|?LyOuN7C] ͥlt:iA(xip,O;o7 UYZ Bý]dUmyk[cͥ)!X{Z \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/67/18a45909532d1fcf5600d0877f7fe7e78f0b86 b/tests-clar/resources/merge-resolve/.gitted/objects/67/18a45909532d1fcf5600d0877f7fe7e78f0b86 new file mode 100644 index 000000000..ffda698f0 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/67/18a45909532d1fcf5600d0877f7fe7e78f0b86 @@ -0,0 +1 @@ +xM1 DNi`ǹDB~ǧ]ݠY74M89H)1d}FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8uy7hhOYd*4uG+_L_E6ySYqjx-m5%IR~GH{JgZB%;b{H zymYYHSJWSDdT0?KWh;8dJfVDXvYhB%H>lY~sk!-O7>>FB_>=Z3`TTPs?h|AT+IBt8 zxR-qwQv;G?VyrWk%OCj_Yo>p>JuX9vt%$dFfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRUTV2+ zVqS`FabhmS;iuCkFYhRfZgSxYdGPA2E7nZ^a(i5`a7|X!_N7n_rNGbt2M*ZTCqCrsS#O%= WSdv~h@x$s@7oOP6iv<87+mri?YJ;Qz literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/6b/7e37be8ce0b897093f2878a9dcd8f396beda2c b/tests-clar/resources/merge-resolve/.gitted/objects/6b/7e37be8ce0b897093f2878a9dcd8f396beda2c new file mode 100644 index 0000000000000000000000000000000000000000..c39318683c48cf2f6efd2d7534311546e5f52536 GIT binary patch literal 53 zcmV-50LuS(0V^p=O;s>9V=y!@Ff%bxNXyJg)hnqeVOSbw%yReJsa>k41B|TnmVLkd LXYDBfM0pYg4$u|k literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/6c/06dcd163587c2cc18be44857e0b71116382aeb b/tests-clar/resources/merge-resolve/.gitted/objects/6c/06dcd163587c2cc18be44857e0b71116382aeb new file mode 100644 index 0000000000000000000000000000000000000000..2f54be818f84403317ba606d205d00e2a67f14b8 GIT binary patch literal 30 mcmb20V^p=O;s>7FfnE@G%zqTF;Or`)XmG+P0mQnOHb7+sVHH{ICjFDQ&R2t zO|E6jXKNqcoptAIA53kMZc1rEPG)jqNotC2W}a?-X;Cp)(}#1~eV%O`zOxPbx2tnL z5jkYH^%+7_QEGWnW=TnE9*UmFWxwyTz5bwhQeEZNe6=r5LdAY|Fg?k-D0)gVQZu18 zy+0`=fA7|Z?u89o?e_2aE`6orEhki$Aeu{4Lbbo89EZD4YOt5FZi)+ zN0RG(CSOVm!N877!!B&MVw`yA{FrSeHzwN`N}cfVqIQx`CsDal@}2WCPNvb&+7 z1vdj8SohlX9w&BpdQN(I@nQF(*N?&$3jKtdU`m`DE*H*yYwDt_WQp=MI$s zs7`ZKoyD0csk%nsVBa?Xh53_n=dYYx!gFW&K?}FG_WSHuHGx%cQ5QP@a+Xv8w^rc4 Q8GhVd(@FfcPQQAjK;$5Ep%1PBLsVHH%P`VYWA! z+-pqcwO^2Nj(9SA6I5|>eqLHmW^zepUOHH*x2o;pEUp*(&n2&0edFlX7R^baQ=m%o zQpA(GGaI=Zf^vM7aA5L>elTZQx literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/6f/be9fb85c86d7d1435f728da418bdff52c640a9 b/tests-clar/resources/merge-resolve/.gitted/objects/6f/be9fb85c86d7d1435f728da418bdff52c640a9 new file mode 100644 index 0000000000000000000000000000000000000000..a2c8d93ad5351c7bd8d8cb65b82c56b464480bdf GIT binary patch literal 83 zcmV-Z0IdIb0V^p=O;xZkWH2-^Ff%bx$V)BPP0P$l)hnqeVK}&Lsr2slLqD{|M1&4s p;*R{2xnTmDIwP>cwF_M)c{ZAr%V*wol}J0aXT!_)vjCBvBKOVWCfNW0 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/71/17467b18605a660ebe5586df69e2311ed5609f b/tests-clar/resources/merge-resolve/.gitted/objects/71/17467b18605a660ebe5586df69e2311ed5609f new file mode 100644 index 0000000000000000000000000000000000000000..02e183144619b23cdaa815ce9571b136b323f1bd GIT binary patch literal 265 zcmV+k0rviQ0V^p=O;s>9H)1d}FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRQEF~} z8PqZPB@m~u9~If)Hse7?r?%mV%RxILgm=!#!=fDF_WO@NX|IycKNsRYLB^nM*W-+P z*>^EDAh|upI%B!~kzcW9`j^||f`x0cqP8!EYA6K;2snJeEw literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/71/2ebba6669ea847d9829e4f1059d6c830c8b531 b/tests-clar/resources/merge-resolve/.gitted/objects/71/2ebba6669ea847d9829e4f1059d6c830c8b531 new file mode 100644 index 0000000000000000000000000000000000000000..dd7d58f1fd9cd06cf97f859c9583c94dbf1bd5be GIT binary patch literal 152 zcmV;J0B8Sr0qv4O4#GePMP1J+IDlhtnrN%C4D=K%}in1?r(Csl&(Hz z;et-JW9{C9H)Aj~FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRQEF~} z8N@M`$j+I=on!Lee3sLVh!6JfEt2`&vnMiPYC&@U{l}lQSIOs}3vr(yW6-wiamKyu zyOJ?$_k[Q,"Zz˟39 LO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/76/63fce0130db092936b137cabd693ec234eb060 b/tests-clar/resources/merge-resolve/.gitted/objects/76/63fce0130db092936b137cabd693ec234eb060 new file mode 100644 index 0000000000000000000000000000000000000000..f578a4a680a3ea718e8bdda793058aecb3df291a GIT binary patch literal 49 zcmV-10M7q-0ZYosPf{>8WhlwWELH%bw9K4T1rr60-29Zxw9M2Lh0HvKqRjM+5=|}u HFjWoVCBYV3 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/76/ab0e2868197ec158ddd6c78d8a0d2fd73d38f9 b/tests-clar/resources/merge-resolve/.gitted/objects/76/ab0e2868197ec158ddd6c78d8a0d2fd73d38f9 new file mode 100644 index 0000000000000000000000000000000000000000..4d41ad8cd0441142957aa75ba9b07914728eb842 GIT binary patch literal 37 tcmb9H)b$2FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRZhlH; zS|-#r`6UpyTzw-L^iTEWzXOb&uNgMqF1)RBNCK+9C^a{~48!sFAAizbC7*vT#C?K{ zLEEm!8TYd9VroEge2jI*a`_{_V$Jj~x5otw*JMR)UkcSw3Jei&0D+x;;zPck^`>c# VCFyk&KdgRr;fc+>SODQ{mRtGjeQ^K) literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/7c/2c5228c9e90170d4a35e6558e47163daf092e5 b/tests-clar/resources/merge-resolve/.gitted/objects/7c/2c5228c9e90170d4a35e6558e47163daf092e5 new file mode 100644 index 0000000000000000000000000000000000000000..52fde92a14135ddf042413bcc61825ef840ba4ac GIT binary patch literal 172 zcmV;d08{^X0i}*fP6ROw06FIs{s72{?JN>PT=)SWNN3TsMA|5w(R_cJH*hP}p;Sf3 z*cUhsFKf02zLN`-3I)g2R_Rg1r9_xI#puy@#=t(B-#pu~AjW2+B#YTfsg}0dnWJ#7 zNTG9Nw;^pVnS5V2o$ys3c~)i6%hxC`b6M|YlZVvl$DPu*_@#X)>rtX+g@8yX2QUDl(|)$4 TKW9X%%X9J90ZF_8=h01b0%1%w literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/7f/7a2da58126226986d71c6ddfab4afba693280d b/tests-clar/resources/merge-resolve/.gitted/objects/7f/7a2da58126226986d71c6ddfab4afba693280d new file mode 100644 index 0000000000000000000000000000000000000000..2f833c2924a9765de95b5d05b189c632dc944c5c GIT binary patch literal 199 zcmV;&067160i{nnPDLRQwPqD`uhI+*!zVGu#?sCWz%Y0%xELPB?TbcNU~_VQImzMC z``gk8{$@=P-Fy*nNo;fsEmbasgClYnBNagcE19fO?|I6(bg7ikMrs_IIL;9{oWZ^ZJi!m}2@%l!Y3%IL#1&`u7 z&-bR$*EaM*Bb%y6K1!$Gbe7++wFB4rq>c5?lLsWdhX9~D?Pr_( Wt??!#h-TBMGTzpE5u-i`{!TB?T2e3o literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/81/87117062b750eed4f93fd7e899f17b52ce554d b/tests-clar/resources/merge-resolve/.gitted/objects/81/87117062b750eed4f93fd7e899f17b52ce554d new file mode 100644 index 0000000000000000000000000000000000000000..19cac9faf4a65b1ebae6515b1ea3c58745f85e87 GIT binary patch literal 170 zcmV;b09F5Z0i}*xYQr!TMEk8(Xaf%Sp{vMHLVmh~Za|M~Y^bfED(UvCmh2#ZGiTs1 zx$gVcEeXB#rfLahEVIiY71jiSrDP$3qM{)sMpz;Wvbn{kN4GNj0Gx!FfTIh7Igrb6 zX76Y4%MkG5VlnaF*V^ny`H8LA&$aH~^|0?c=wG_(|L|<5T=$Db7D7N|vJ-d!Gw3+m Y^+k>8ZF_9-YeF}r7LUA|U!_%0xC}*EumAu6 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/83/07d93a155903a5c49576583f0ce1f6ff897c0e b/tests-clar/resources/merge-resolve/.gitted/objects/83/07d93a155903a5c49576583f0ce1f6ff897c0e new file mode 100644 index 0000000000000000000000000000000000000000..5a96a4e4e3c624146e03fd75965117b132d562e8 GIT binary patch literal 30 mcmb!yw5#gVhE67`v(BN9t4Ghi?@FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nOy zF#rOEr2LW$-IUCtVupu8vu%Dy%y{to8ry@@4Vy~i0xl*(4NT5R%u9#3AgL%ZFF6Bj z=;|DoMK4??t@U=?oxP^r)NU@*nr=)DNKO{Kx0+$odm6iz&m9DjO`4*c@m0ePu zB;_7$c_#0A%m3;oW5cdf(25q|@XWYxa3)N5x3>9!7ft`Qi cL%yE%rfH5P>2(u7tbTRjiOsxN0LB=(`fXvqU;qFB literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/84/9619b03ae540acee4d1edec96b86993da6b497 b/tests-clar/resources/merge-resolve/.gitted/objects/84/9619b03ae540acee4d1edec96b86993da6b497 new file mode 100644 index 000000000..67271ac50 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/84/9619b03ae540acee4d1edec96b86993da6b497 @@ -0,0 +1,3 @@ +xK +1D]v7t3L$ UEV4X9&s2ELKR%%t=)M(s`-n3YmEd`N<{uhI(88%DM|2b}JG< literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/86/088dae8bade454995b21a1c88107b0e1accdab b/tests-clar/resources/merge-resolve/.gitted/objects/86/088dae8bade454995b21a1c88107b0e1accdab new file mode 100644 index 0000000000000000000000000000000000000000..623a747f01c770b9e71d758624383a1d6967dfd7 GIT binary patch literal 47 zcmV+~0MP$<0ZYosPf{>8W+=(XEan2DM6R^VoK!B2%shpXj8uihyyVp4lKdh~E&vNJ F4D}Gn7F7TM literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/87/b4926260d77a3b851e71ecce06839bd650b231 b/tests-clar/resources/merge-resolve/.gitted/objects/87/b4926260d77a3b851e71ecce06839bd650b231 new file mode 100644 index 0000000000000000000000000000000000000000..91944ffb57fde51caf171042f60e03d565e03f5d GIT binary patch literal 43 zcmV+`0M!3@0ZYosPf{?lWGKnVEan2DM6R^VoK!B2%shpZwD{u8lvE>4E&$k?3p&Qe B6oUW& literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/88/e185910a15cd13bdf44854ad037f4842b03b29 b/tests-clar/resources/merge-resolve/.gitted/objects/88/e185910a15cd13bdf44854ad037f4842b03b29 new file mode 100644 index 0000000000000000000000000000000000000000..ae1c5e242c1878b29dce3a1aa7b5372f92c958b6 GIT binary patch literal 177 zcmV;i08amS0iBLPYC|CyguC_>ULZyNpFV|9vdIm)59&XXKz$aUA=j@7IYDPN^9>A> zTdlVtjkO=612QitAdSGtQ$CrrFmVYnW|O(VgkYWa;x~3|LnaglS`z_|Op5EGZP3np za)rDpV550mS;YIewl2^7h@Iv4wbi|C@`y>F?u1wIPM^8eFR95XWyonQ56UYgCY@&o f{xRd7CI6lg^Lebe8XDG?YEan2DM6R^VoK!B2ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jv^j9!Ɖ9%`<sBާHrS3d Ң2 wI{| 2mg˾15ӿ,\})TC)00avʉz֛9MՅ'6bG \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/8b/095d8fd01594f4d14454d073e3ac57b9ce485f b/tests-clar/resources/merge-resolve/.gitted/objects/8b/095d8fd01594f4d14454d073e3ac57b9ce485f new file mode 100644 index 0000000000000000000000000000000000000000..4ec0138816823c0fad877882b0bf10fff18ddfd5 GIT binary patch literal 201 zcmV;)05<=40i};UP6aUxgsF3ibgu$Aaef>LAsR|LE?_4POOXxATg3HQ5S)N+=9|$- zQ|B0Oheb#?$5OQ&yK^Z>B8gdCDN#}+CQs-=Q|k!iI;(l-rTbx}#e$wkxX#_) z>q)=Wqy7ZH?yk=9U>zm^zzEUa0s)wlp63qz=ZtyQ^{Q4D?{%}6^EVH@`iuDjY}aAH DgREd- literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/8b/5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a b/tests-clar/resources/merge-resolve/.gitted/objects/8b/5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a new file mode 100644 index 000000000..f4249c23d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/8b/5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a @@ -0,0 +1 @@ +x퐱 0 S{"2d,0^?&SH[8눪E`фrZ*drl, cbF/'gв \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/8c/749d9968d4b10dcfb06c9f97d0e5d92d337071 b/tests-clar/resources/merge-resolve/.gitted/objects/8c/749d9968d4b10dcfb06c9f97d0e5d92d337071 new file mode 100644 index 000000000..e42393cf7 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/8c/749d9968d4b10dcfb06c9f97d0e5d92d337071 @@ -0,0 +1,2 @@ +xAB!C]s +.acxf`|_ bh5m^mzL`}$26#"8`s.`ԝܺ.!bH\< i",K8ٗ_X>MeЏ:7]AC40뭙Q]Q\.,VO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/8f/4433f8593ddd65b7dd43dd4564d841f4d9c8aa b/tests-clar/resources/merge-resolve/.gitted/objects/8f/4433f8593ddd65b7dd43dd4564d841f4d9c8aa new file mode 100644 index 0000000000000000000000000000000000000000..d2de777ccdec25efd39427d93f9d31fbb6850225 GIT binary patch literal 164 zcmV;V09*ff0i}*n3c@fDME%Ywa)HVw>824x{P6}}V7t4a1#2Wmy}nhvfqyga!7yBw zWp38@xM@|@k`N;GD6U682nWeLxL(O|MDgl0=26pNZdCQ!EJqkJ2S_Ps2q>C;Vu>k^ z=yK#t;75qch8}Gy)t=-D60 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/90/a336c7dacbe295159413559b0043b8bdc60d57 b/tests-clar/resources/merge-resolve/.gitted/objects/90/a336c7dacbe295159413559b0043b8bdc60d57 new file mode 100644 index 0000000000000000000000000000000000000000..35453ebfd5d3284e933cfe2358d17e7f9fe4cff6 GIT binary patch literal 271 zcmV+q0r38K0V^p=O;s>9H)Jq0FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRZhlH; zS|-FbhQ?skGXLitTT&HV+;H#yUGbC8b4yfbX+u>PrRL_BVL1K%<4@YF9Ghr|^FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nPt zDo)Nw%u9!uo>Y{Wmz)9CusX+O(F>PJYrP$JXRm2DwVTVdrW;cOl5_UX*>aYvoM-3S z)A8pN6`kHYypl16X~@q@%gIbG$;?X!o9)+;m!PV7YUOId>+)^M-WRt$xF-NrnwMG* z@@85ZSfQEsKA#sn)tBXx+3!5Bb$k4L(Mncx6@%~Lw3ea>7oH3@vq#L$0?;}ZZT_z%8A4N0YI#v+Nl9uRik`=1zwffW{-AhLUFFt%wJ%OW#eQ}$J;}N#dP*`>1-*CQ1Do%c zw%oXAb-*BaB9Aa5P9wnHyKp7aPwdmfiR_Pm)h)BDTJ_%`{x?iV640q2JHY`0u?5Lm zcnH0ns{BmP)h^)f?1u?iA1BY;nP*vr#|W^s+VS!da*wz6Ef4&9H@1JaOQ^y^GpHUT zWUnUWmt=r7h<7?{3HW5OG>5lz`_!1N)fSSHO;8QSn1Pd$nv;qdIufT1vt`~d__1tC zKA(bApHzNJ)J~`wCYWX}F5$Ve{Gf$fTl;->teU`9Y*80F Z|8ka80Jm1)zZrhqUFA%>1OY*1MnrK80~P=P literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/93/77fccdb210540b8c0520cc6e80eb632c20bd25 b/tests-clar/resources/merge-resolve/.gitted/objects/93/77fccdb210540b8c0520cc6e80eb632c20bd25 new file mode 100644 index 0000000000000000000000000000000000000000..4b2d93b07de774c1c0c7aa7cf266e6034d4ac9b2 GIT binary patch literal 53 zcmbXvEU#p|pKHt;UtbER6gj5# d+XD%?D8yil28|jcL2~arFGPE?-~;t=8hU`!AFKcX literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/95/646149ab6b6ba6edc83cff678582538b457b2b b/tests-clar/resources/merge-resolve/.gitted/objects/95/646149ab6b6ba6edc83cff678582538b457b2b new file mode 100644 index 000000000..de9ba2894 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/95/646149ab6b6ba6edc83cff678582538b457b2b @@ -0,0 +1,3 @@ +xM ]s +.Obo eHh1E {?y_XenR}hY* HFS +S !$1œ*MwUv4It:8KFEA6*oM5T=+ݝƲ\ѠCV`nLjۜXiO\ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/95/9de65e568274120fdf9e3af9f77b1550122149 b/tests-clar/resources/merge-resolve/.gitted/objects/95/9de65e568274120fdf9e3af9f77b1550122149 new file mode 100644 index 0000000000000000000000000000000000000000..e998de849c865efaac9d2aa5e89b23d36dc55a4f GIT binary patch literal 40 ycmV+@0N4L`0ZYosPf{>4VF*gi%`Zz$QOL|wP%kOUEXz#H(X~+5;{pJy9|`qUiV=bU literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/96/8ca794a4597f7f6abbb2b8d940b4078a0f3fd4 b/tests-clar/resources/merge-resolve/.gitted/objects/96/8ca794a4597f7f6abbb2b8d940b4078a0f3fd4 new file mode 100644 index 0000000000000000000000000000000000000000..359e43a8834a5bd911de3f1c2c258301ab22eff6 GIT binary patch literal 53 zcmV-50LuS(0V^p=O;s>9V=y!@Ff%bxNXyJg)hnqeVL0Ctb7Do5{MRMB0w3(D`I;7% LIms6QRPquG^QRP3 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/97/7c696519c5a3004c5f1d15d60c89dbeb8f235f b/tests-clar/resources/merge-resolve/.gitted/objects/97/7c696519c5a3004c5f1d15d60c89dbeb8f235f new file mode 100644 index 0000000000000000000000000000000000000000..e561b473f8a3cbd55205277cfe1017a51fbb124e GIT binary patch literal 160 zcmV;R0AK%j0i}*X4#F@D1Ucsw`2fhVn>0uWap4Diz;zszLmJcu@qGf~2i$gNrO`?) z<=!j~Zr4^-n`q=TA|rSV(Ps$=PLT5v91y1g6T*0$%!5~5nw0=!7J?W_iG0$GQBsIu z@-7F-3^+khG5l;*Rs{cp0v|Xy6AWKwS&}hwvN2>VE`h#2M=I6?Pr_* OsWFAOE-`NlT~2zA6-V&^ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/98/ba4205fcf31f5dd93c916d35fe3f3b3d0e6714 b/tests-clar/resources/merge-resolve/.gitted/objects/98/ba4205fcf31f5dd93c916d35fe3f3b3d0e6714 new file mode 100644 index 000000000..6f5e97978 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/98/ba4205fcf31f5dd93c916d35fe3f3b3d0e6714 @@ -0,0 +1 @@ +x- 0  G%ȅ"M!@yj񼽊vj:AAM~dА{.3);l]vi6D% 9f|.z \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/98/d52d07c0b0bbf2b46548f6aa521295c2cb55db b/tests-clar/resources/merge-resolve/.gitted/objects/98/d52d07c0b0bbf2b46548f6aa521295c2cb55db new file mode 100644 index 000000000..c8d636e8b --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/98/d52d07c0b0bbf2b46548f6aa521295c2cb55db @@ -0,0 +1,3 @@ +xA +0=y}NˮtaJ[ +/^r$<, "1*[\ Yj (;m9 oNxcz"1(7yۗ. \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/99/b4f7e4f24470fa06b980bc21f1095c2a9425c0 b/tests-clar/resources/merge-resolve/.gitted/objects/99/b4f7e4f24470fa06b980bc21f1095c2a9425c0 new file mode 100644 index 0000000000000000000000000000000000000000..01ad66eaac30ec303895cc9307a6615643841fba GIT binary patch literal 164 zcmV;V09*ff0i}-J2?8+?gndpGX+YT|o826U_+ke(ke@y7z%vq~w(lu+AoDWw4Gfd( zvdmpu#7%D^8j82#qW2^w3@O5ZA&MssFqiU1gvn6l;FvVV4AlmmAqK0eCQ8OvCmwO-dzaCdRP&IE4m^aM2omO~ zEt&v879AQ@K*VRC+A1&Q71tuKQ(Lxnmq#A-9WH2-^Ff%bx$V)9}crt%twM(zC!)DpCr{0S@)cUWSR006| Gr4E*%ITSzu literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/9c/0b6c34ef379a42d858f03fef38630f476b9102 b/tests-clar/resources/merge-resolve/.gitted/objects/9c/0b6c34ef379a42d858f03fef38630f476b9102 new file mode 100644 index 0000000000000000000000000000000000000000..e6f8500790efd5b74d9339fbc567300bb5719056 GIT binary patch literal 38 ucmbqhTS#F!Zm<7~gOe4TPyl^GbPwdmfiR_Pm)h)BDTJ_%`{x?iVl5SpVImlLo_mHfG z2a<}E0PES=GuVwvq)RNKI|ZHg?9#wv1lU^bczFrA$6NcB2Y$U9+dtbSRAHeRRF4s| ztx5SM8DI_Koeo<9K3Ocy;Vs=hHD+tIg`{K?RD&@#cc!G~q(Z|7?oczu*`8*FZm0FK zL_@c(e0}ADQOi`Q879Egg77OifD=2C>;QpgL)Th!1s?za literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/9e/fe7723802d4305142eee177e018fee1572c4f4 b/tests-clar/resources/merge-resolve/.gitted/objects/9e/fe7723802d4305142eee177e018fee1572c4f4 new file mode 100644 index 0000000000000000000000000000000000000000..c63fc2c969e292d9cd3aad9e53818bb4a8d7acf8 GIT binary patch literal 36 scmb7FfnE@G%zqTF;Or`)XmG+P0mQnOHb7+sVHH{ICjFDQ&R2t zO|E6jXKNqcoptAIA53kMZc1rEPG)jqNotC2W}a?-X;Cp)(}#1~eV%O`zOxPbx2tnL z5jkYH^%+7_QEGWnW=TnE9*UmFWxwyTz5bwhQeEZNe6=r5LdAY|Fg?k-D0)gVQZu18 zy+0`=fA7|Z?u89o?e_2aE`6orEhki$Aeu{4Lbbo89EZD4YOt5FZi)+ zN0RG(CSOVm!N877!!B&MVw`yA{FrSeHzwN`N}cfVqIQx`CsDal@}2WCPNvb&+7 z1vdj8SohlX9w&BpdQN(I@nQF(*N?&$3jKtdU`m`DE*H*Rxi8;LSX6a6G1H*> z$3iI!s0n7epg4o497Elbd|e|%cDnJad|R_Y)4^9}+nc%~bbXvVR05zn%~5q0XQrg; z8i9j-+x!>iPtKjca&igJo#h8D+}hgjvt!i+R=q`C=={rBQUTmrf&XUsad(w7?Ggk4 HRR@?)?dUH% literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/a0/31a28ae70e33a641ce4b8a8f6317f1ab79dee4 b/tests-clar/resources/merge-resolve/.gitted/objects/a0/31a28ae70e33a641ce4b8a8f6317f1ab79dee4 new file mode 100644 index 0000000000000000000000000000000000000000..a6c05d1821889a71bfd029059b1ff84cf2992a7f GIT binary patch literal 37 tcmb+2;a~44FIfP3wHnj literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/a3/fabece9eb8748da810e1e08266fef9b7136ad4 b/tests-clar/resources/merge-resolve/.gitted/objects/a3/fabece9eb8748da810e1e08266fef9b7136ad4 new file mode 100644 index 0000000000000000000000000000000000000000..24d7dbc2eb253f6470cb837fbe8b70361e5b6e94 GIT binary patch literal 164 zcmV;V09*ff0i}*n4#FT1ME&LzT%cxwT?&aY{&)i~04z^>ZTZmRHC0XtU2$<{N~$4PwW*`@@A9)cM+`qNu+sJ{dpl+8B}V{{JS3 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/a4/3150a738849c59376cf30bb2a68348a83c8f48 b/tests-clar/resources/merge-resolve/.gitted/objects/a4/3150a738849c59376cf30bb2a68348a83c8f48 new file mode 100644 index 0000000000000000000000000000000000000000..06ae09eb6d090f5a394cd7c39882de7d68e82565 GIT binary patch literal 162 zcmV;T0A2rh0i}*h3IZ_@L|x|;xxh#|pY8-i+;{^okWUZeA`^)bukVa_1F22bD<~?r zTJJ+@YYw9`OI4g^6P-f_A5v7o`p6E+s{mdBWJrKi#3OcIhny)Jqf@cF5)m219N89a z3!o=U8VJOMSELH%bL(MnP87o`X?VaJJb+r$_3V(p YF=%}9$^0;?)C(;vkI}k%17&AXZjo(N>Hq)$ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/a7/7a56a49f8f3ae242e02717f18ebbc60c5cc543 b/tests-clar/resources/merge-resolve/.gitted/objects/a7/7a56a49f8f3ae242e02717f18ebbc60c5cc543 new file mode 100644 index 0000000000000000000000000000000000000000..76dd5f91b42a319c9ab512351b355f50e2cbeaa7 GIT binary patch literal 65 zcmV-H0KWft0ZYosPf{>4wqz*D$ShV!%gjkt0Md!2CHc9jMd_)DNja%p#7dc)swxy` X=4R$377?w7Je%<7BGM56^gmd;=`kMA literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/a7/dbfcbfc1a60709cb80b5ca24539008456531d0 b/tests-clar/resources/merge-resolve/.gitted/objects/a7/dbfcbfc1a60709cb80b5ca24539008456531d0 new file mode 100644 index 000000000..67126c90b --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/a7/dbfcbfc1a60709cb80b5ca24539008456531d0 @@ -0,0 +1 @@ +xN !L4a/v{`1,Ec?/R.ޘ%3$L15fe53'427^G1yBGVLAG *|R) sm^%yk*O<C,{eCg;9#RoKboN \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/a8/02e06f1782a9645b9851bc7202cee74a8a4972 b/tests-clar/resources/merge-resolve/.gitted/objects/a8/02e06f1782a9645b9851bc7202cee74a8a4972 new file mode 100644 index 0000000000000000000000000000000000000000..d39034b82f3cd141006946fc99129f860142c13a GIT binary patch literal 172 zcmV;d08{^X0i}*zs=_c3Mt#mIW&=ty?c@h87hl|g8%QP-S}={I5w~w#gKr-PzQf^K z%GLoFf9g#HQZ#6EuxyBJPR2UIiG7SFBQKU5hUg`cdWI(ZIL;meroikaM=}_lnJF2v zKF5WeCC!#8s_^P-ZE#EP&=TC&T8_HIpA7n4*RpY|N6r1hwfuvghe8usg!4qxqy`ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jv^jnb^nJfZZjQj^ X#3|>^U:'A2R2 I{| 2mg˾15ӿ,\})TC)0H!vʉz֛9MՅ'6bGx \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/a9/0bc3fb6f15181972a2959a921429efbd81a473 b/tests-clar/resources/merge-resolve/.gitted/objects/a9/0bc3fb6f15181972a2959a921429efbd81a473 new file mode 100644 index 000000000..91113ee8e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/a9/0bc3fb6f15181972a2959a921429efbd81a473 @@ -0,0 +1,2 @@ +xK +1D]};7d=oo^UQT\;hk6@g 5rѓ]uOMndgz&c圈'} NJ7p?(G\8CآGTg9x$faxN" \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ab/40af3cb8a3ed2e2843e96d9aa7871336b94573 b/tests-clar/resources/merge-resolve/.gitted/objects/ab/40af3cb8a3ed2e2843e96d9aa7871336b94573 new file mode 100644 index 0000000000000000000000000000000000000000..7da1da656f6ab89f34f15cc1162a92b04458e657 GIT binary patch literal 161 zcmV;S0ABxi0i}-74FVw$ME#};8qjbo%VA=SKXzaPu{8eW`=4h z_pYsjU2n`9B}vL;Tyjj&c|j*GAVeUHQzo`SaPp`gvGLk9c{2-v2>}=YGm8zBeeek< z@g&jMWIU6K&%V^AulW^Q*0-gWt*-jSgMQS7zroKPsFt&y0AW6kb*uNr8>0ptXFLB{ PqsH@Cc(dva#nMn^m!eK? literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ab/6c44a2e84492ad4b41bb6bac87353e9d02ac8b b/tests-clar/resources/merge-resolve/.gitted/objects/ab/6c44a2e84492ad4b41bb6bac87353e9d02ac8b new file mode 100644 index 0000000000000000000000000000000000000000..d840c1a573d3e52ace510582218e0665a8806093 GIT binary patch literal 33 pcmbL(MnP87o`X?V;(m3biX?o>}lPD{Lxft&)08*I{F#rGn literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ac/4045f965119e6998f4340ed0f411decfb3ec05 b/tests-clar/resources/merge-resolve/.gitted/objects/ac/4045f965119e6998f4340ed0f411decfb3ec05 new file mode 100644 index 0000000000000000000000000000000000000000..4c32d63f82cfe08f3000fc0e168eecba1dc7b0f0 GIT binary patch literal 29 lcmb4WhlwWEan2D#Jv2HjMO59ywq~8w9K4TE&#U}3f_356G;F7 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ad/a55a45d14527dc3dfc714ea1c65d2e1e6fbe87 b/tests-clar/resources/merge-resolve/.gitted/objects/ad/a55a45d14527dc3dfc714ea1c65d2e1e6fbe87 new file mode 100644 index 000000000..3091b8f3d --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/ad/a55a45d14527dc3dfc714ea1c65d2e1e6fbe87 @@ -0,0 +1 @@ +x+)JMU067d040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5`nלU7 V.6t6L/R2 I{| 2mg˾15ӿ,\})TC)0<vʉz֛9MՅ'6bN* \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/b2/d399ae15224e1d58066e3c8df70ce37de7a656 b/tests-clar/resources/merge-resolve/.gitted/objects/b2/d399ae15224e1d58066e3c8df70ce37de7a656 new file mode 100644 index 000000000..20fa838f2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/b2/d399ae15224e1d58066e3c8df70ce37de7a656 @@ -0,0 +1,2 @@ +xQA1+xċϡ-kI*5f/z af!^/WJcܤ5Lƛ;+B6HZP|`h>\($sX@75}57K ++= ;g @!4!,\$\ \b/Hs#aQ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/b4/2712cfe99a1a500b2a51fe984e0b8a7702ba11 b/tests-clar/resources/merge-resolve/.gitted/objects/b4/2712cfe99a1a500b2a51fe984e0b8a7702ba11 new file mode 100644 index 000000000..2820b46cc --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/b4/2712cfe99a1a500b2a51fe984e0b8a7702ba11 @@ -0,0 +1,5 @@ +xA + {B{M1 ߯>P3F֎7E02 X0̒,)$;:ܷ(: \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/b6/f610aef53bd343e6c96227de874c66f00ee8e8 b/tests-clar/resources/merge-resolve/.gitted/objects/b6/f610aef53bd343e6c96227de874c66f00ee8e8 new file mode 100644 index 0000000000000000000000000000000000000000..fb102f15dc5a37b8cdedca9064e37463ec832a2e GIT binary patch literal 162 zcmV;T0A2rh0iBLZ4gw(%L|t^KaPNA+>svYC+{40y?<|1Q3(XvxEQB QSll$CrO~YT09BApVed#rm;e9( literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/b7/a2576f9fc20024ac9ef17cb134acbd1ac73127 b/tests-clar/resources/merge-resolve/.gitted/objects/b7/a2576f9fc20024ac9ef17cb134acbd1ac73127 new file mode 100644 index 0000000000000000000000000000000000000000..22f2d137d4d55d218d30aa0f04ca3aece24a4c96 GIT binary patch literal 320 zcmV-G0l)ru0V^p=O;s?quw*baFfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nPt zDo)Nw%u9!uo>Y{Wmz)9CusX+O(F>PJYrP$JXRm2DwVTVdrW;cOl5+&_t!CJCdD+*+ z?3NvCSb21-(?TD?H00-{|BDN`YPmhXB}ZCqCrsS#O%=Sdv~h S@x$s@7oOP6iv9He@g{00M=S%pzSw1BS`vf6i_a2;uHwRXCH^@H$yXVXrDe zff>WJp5;@PMAp}5?cTKGro$HYE`Iwf2zhe`uc-mA&rCn3v`OD}eRb394F(sOzar!< z7y?@UXmxDcyQ_Dn_2sEn{rV%FFfn3DqYLL z!njBdS%onJv)-Pl9kEk`cT3dTT;VAFue{9e04HDWL{FfcPQQAjK;$5Ep%1PBLsVHH1XTNaA0j~e` z4-``WZskbX%{y7=JXCRVMq*xiYKm@Vo^Dc6VqS6vSi|ZZmqjmJCav{$+?~Cq-PCR_ z)0%Ef4Y`TMC8#9Cq(LG5y$& zWteJBz-m9utKT{yRA8zyPon4P=lXgRS(Z|BDN`V0k4sWo@CqCrsS#O%=Sdv~h@x$s@7oOP6ivg+xyA;@=`73 z-nE3VMxwM%u7#AQOL|w$W1IRNiE_^%qh-SKoU+%(@iQ$%uCMT J0szul5x^+`6>4GG#C{FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nPt zDo)Nw%u9!uo>Y{Wmz)9CusX+O(F>PJYrP$JXRm2DwVTVdrW;cOl5+&_t!CJCdD+*+ z?3NvCSb21-(?TD?H00-{sGnKH|N-zXI~50WN2al z1PW=HP%r22o4+Hb?fOOM_@dq=5_|s#9dlR-HK8aqH@^(S%l99D(q1K>e=fv*f{a1i uuE!bovhPAQlmdeV974GGQ<@FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nPt zDo)Nw%u9!uo>Y{Wmz)9CusX+O(F>PJYrP$JXRm2DwVTVdrW;cOl5+&_t!CJCdD+*+ z?3NvCSb21-(?TD?H00-{e=fv*f{a1i uuE!bovhPAQlmbHq97tg2pZJikXT52fV@Z15#1E@qU3g+MFBSk{8W+=(XEan2DM1{Q6a)q?aoK!B2%shpZwD{u8lvE>4E&vVI F47C%Q7E}NL literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c3/5dee9bcc0e989f3b0c40f68372a9a51b6c4e6a b/tests-clar/resources/merge-resolve/.gitted/objects/c3/5dee9bcc0e989f3b0c40f68372a9a51b6c4e6a new file mode 100644 index 0000000000000000000000000000000000000000..d22b3b23cac60ba521d25c4293898064c0ae1593 GIT binary patch literal 162 zcmV;T0A2rh0i{k`4#FT1^qW&~ftoGLqa?=o;|;t3EKAzN7K5nQ7mYXYZ(f-hD(kv5 zskGj;$}Ckjeo}g3Cd#B78wy${pS;BhvrU#qs^ttb9#lE3FlQ*q$ShVU&&>GO3h2mO-)hA%u~oOEh^?p%u7*7 ZP01{Q2$f`{W&#DdMzzpB!~n^9kr}|f9F710 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c4/efe31e9decccc8b2b4d3df9aac2cdfe2995618 b/tests-clar/resources/merge-resolve/.gitted/objects/c4/efe31e9decccc8b2b4d3df9aac2cdfe2995618 new file mode 100644 index 0000000000000000000000000000000000000000..c7572d5bc5eb9063222d584fc3d15e6d3e8c78ea GIT binary patch literal 538 zcmV+#0_FX90V^p=O;xZkF=a3`FfcPQQ7}l<&CAzK&PdElPt_}_C}GGrcEX!eQtkLn zu4T(-Yaia7b?0m!Ol^{GN@+n(W^!UlYKm@Vo^F0=Q88H4hjZF}o^2eyvkm&Ut8+dP zIb^r>8A4N0YI#v+Nl9uRik`=1zwffW{-AhLUFFt%wJ%OW#eQ}$J;}N#dP*`>1-*CQ1Do%c zw%oXAb-*BaB9Aa5P9wnHyKp7aPwdmfiR_Pm)h)BDTJ_%`{x?iV640q2JHY`0u?5Lm zcnH0ns{BmP)h^)f?1u?iA1BY;nP*vr#|W^s+VS!da*wz6Ef4&9H@1JaOQ^y^GpHUT zWUnUWmt=r7h<7?{3HW5OG>5lz`_!1N)fSSHO;8QSn1Pd$nv;qdIufT1vt`~d__1tC zKA(bApHzNJ)J~`wCYWXNG>uS)7@Ys%r#x@V5Cc%%7Y)f92#7o;%AATDY~f-)G0F39NdH cy3qNTv!nvJwF3Xm@Z;_(XWAtQ0Q_A_2K7t`WdHyG literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c5/0d0f1cb60b8b0fe1615ad20ace557e9d68d7bd b/tests-clar/resources/merge-resolve/.gitted/objects/c5/0d0f1cb60b8b0fe1615ad20ace557e9d68d7bd new file mode 100644 index 000000000..a1d5321e8 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/c5/0d0f1cb60b8b0fe1615ad20ace557e9d68d7bd @@ -0,0 +1 @@ +xKj1D)t4l|>-f 9UV61:̸ !>Z.P0x hhQ+t`1NZe,X[ =vyI_vJ^2$?I7o4{K>V!~|U= \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c5/bbe550b9f09444bdddd3ecf3d97c0b42aa786c b/tests-clar/resources/merge-resolve/.gitted/objects/c5/bbe550b9f09444bdddd3ecf3d97c0b42aa786c new file mode 100644 index 0000000000000000000000000000000000000000..2f2ada732bb550a444b455b69cd88602c3d67f07 GIT binary patch literal 269 zcmV+o0rLKM0V^p=O;s>9GGH(?FfcPQQAjK;$5Ep%1PBLsVHH1XTNaA0j~e` z4-``WZskbX%{y7=JXCRVMq*xiYKm@Vo^Dc6VqS6vSi|ZZmqjmJCav{$+?~Cq-PCR_ z)0%Ef4Y`TMC8,af<EZȳ5%<'.v,;]=2tws-,w8@ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c6/92ecf62007c0ac9fb26e2aa884de2933de15ed b/tests-clar/resources/merge-resolve/.gitted/objects/c6/92ecf62007c0ac9fb26e2aa884de2933de15ed new file mode 100644 index 0000000000000000000000000000000000000000..ae430bd4afba7895c20f6edf0ded1ed7cfc1fac1 GIT binary patch literal 40 wcmb_-c8b@je%D{V@~65^K(h082;^T>t<8 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c8/f06f2e3bb2964174677e91f0abead0e43c9e5d b/tests-clar/resources/merge-resolve/.gitted/objects/c8/f06f2e3bb2964174677e91f0abead0e43c9e5d new file mode 100644 index 0000000000000000000000000000000000000000..5dae4c3acfaa6a68557540b75781f0684061f48d GIT binary patch literal 45 zcmb1a-}BM%t|iLpQ@5E3@i_MjRCl> B5-|V( literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c9/174cef549ec94ecbc43ef03cdc775b4950becb b/tests-clar/resources/merge-resolve/.gitted/objects/c9/174cef549ec94ecbc43ef03cdc775b4950becb new file mode 100644 index 000000000..da8dba244 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/c9/174cef549ec94ecbc43ef03cdc775b4950becb @@ -0,0 +1,2 @@ +xQ +0D)rfnSxfCHx}xfc,˵Y kUb8pu`%|@r3GtB;W]!z'%QiӐdT ?\=d/sYe';^r#l`6m Z7U^e6oVO \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/c9/4b27e41064c521120627e07e2035cca1d24ffa b/tests-clar/resources/merge-resolve/.gitted/objects/c9/4b27e41064c521120627e07e2035cca1d24ffa new file mode 100644 index 0000000000000000000000000000000000000000..fd1ec9fab86ffc33f034346301fe738c72bafa5d GIT binary patch literal 162 zcmV;T0A2rh0i}*h3IZ_@L|x|;xq#B?NvCH(#Emy_FZpzsS&WfP#OoWy8@Q`_1&@kl zU6-cO4!c%GbfVyLoE*gooj0Lp5lap%hRMP>28xu>sE4m|Z#r27&dgmv072p~kPntQ zPl%jj3PzBPSN_@NQuQUhd`Ti}ylK=n! literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ca/b2cf23998b40f1af2d9d9a756dc9e285a8df4b b/tests-clar/resources/merge-resolve/.gitted/objects/ca/b2cf23998b40f1af2d9d9a756dc9e285a8df4b new file mode 100644 index 0000000000000000000000000000000000000000..32ba2aa53a6f19f21a89b0dc13c6e221ea00f81d GIT binary patch literal 40 wcmb7-s7w2Zl(JJfmRniF`=WS>qk5dtT)>G!ul%4q|lT92TiIa-m2w zno3+V*cnJz<>y%Xs?X(>*P<^=Z;yV{2ifQ+o#ZQiZO^?OwQ*=tjEP83fB5oQ1Y literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/cc/3e3009134cb88014129fc8858d1101359e5e2f b/tests-clar/resources/merge-resolve/.gitted/objects/cc/3e3009134cb88014129fc8858d1101359e5e2f new file mode 100644 index 000000000..9a0cb7a0c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/cc/3e3009134cb88014129fc8858d1101359e5e2f @@ -0,0 +1,2 @@ +x] +0})&_H -Fb[6}0L2wPzc*sXb Rt#G$[lvH$kf.ʧLF+ QHD|68Wl.S]uoNOu9Va0^ZF9^# Od \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ce/8860d49e3bea6fd745874a01b7c3e46da8cbc3 b/tests-clar/resources/merge-resolve/.gitted/objects/ce/8860d49e3bea6fd745874a01b7c3e46da8cbc3 new file mode 100644 index 0000000000000000000000000000000000000000..860f9952f115c5613a9ad3706050f35c37da9b38 GIT binary patch literal 48 zcmb3Ghryn$ShVU&&>GO3h2mO-)hA%u~oOEh^?3l^k+` J002O@s4gWp6x09! literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d2/f8637f2eab2507a1e13cbc9df4729ec386627e b/tests-clar/resources/merge-resolve/.gitted/objects/d2/f8637f2eab2507a1e13cbc9df4729ec386627e new file mode 100644 index 0000000000000000000000000000000000000000..558a8513fd0e24e1957965d5b64174e87018989e GIT binary patch literal 268 zcmV+n0rUQN0V^p=O;s>9GGH(?FfcPQQAjK;$5Ep%1PBLsVHH1XTNaA0j~e` z4-``WZskbX%{y7=JXCRVMq*xiYKm@Vo^Dc6VqS6vSi|ZZmqjmJCav{$+?~Cq-PCR_ z)0%Ef4Y`TMC8AVK6i>Ff%bxNXyJgHPkDqC}H@zm8W$@&6^UR-xF m%!g?*k|HCpBG0)$#6{!0@7m-&oU~jg=u2Z`lK}wRQy>;UUn6<| literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d3/7ad72a2052685fc6201c2af90103ad42d2079b b/tests-clar/resources/merge-resolve/.gitted/objects/d3/7ad72a2052685fc6201c2af90103ad42d2079b new file mode 100644 index 0000000000000000000000000000000000000000..b2f39bff413f61faf64377a96e8132790ec9911e GIT binary patch literal 233 zcmV5H)Aj~FfcPQQAjK;$5Ep%1PBLsVHH1XTNaA0j~e` z4-``WZskbX%{y7=JXCRVMq*xiYKm@Vo^Dc6VqS6vSi|ZZmqjmJCav{$+?~Cq-PCR_ z)0%Ef4Y`TMC8L(MnP87o`X?VSG5BY&Jp}-?)eH9k literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d5/a61b0b4992a4f0caa887fa08b52431e727bb6f b/tests-clar/resources/merge-resolve/.gitted/objects/d5/a61b0b4992a4f0caa887fa08b52431e727bb6f new file mode 100644 index 0000000000000000000000000000000000000000..a7921de43c86dc803ee6c2958286aec2d7c0c8d0 GIT binary patch literal 81 zcmV-X0IvUd0V^p=O;s>AVK6i>Ff%bxNXyJgHPkDqC}H3f-z_?I+PWo|rhaLyU0&Be nZS(OvNQ#WWitf$|=P_Y;_MrO6^;FqBg$Y{Wmz)9CusX+O(F>PJYrP$JXRm2DwVTVdrW;cOl5+&_t!CJCdD+*+ z?3NvCSb21-(?TD?H00-{yi7R zYKl^G^UE;2bN}%t?N##m=R({k$QZQkdYo}D`z};NDbUN{5CFUF#D{!6>rK-fOVaBm RepvnL!V{Z$u>dpcn{GXBs5Jlp literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d5/ec1152fe25e9fec00189eb00b3db71db24c218 b/tests-clar/resources/merge-resolve/.gitted/objects/d5/ec1152fe25e9fec00189eb00b3db71db24c218 new file mode 100644 index 0000000000000000000000000000000000000000..0d2534bc9be203e229c6ed85d5330c2480e8ac0b GIT binary patch literal 24 gcmbqhTS#F!Zm<7~gOe4TPyl^GbPwdmfiR_Pm)h)BDTJ_%`{x?iVl5SpVImlLo_mHfG z2a<}E0PES=GuVwvq)RNKI|ZHg?9#wv1lU^bczFrA$6NcB2Y$U9+dtbSRAHeRRF4s| ztx5SM8DI_Koeo<9K3Ocy;Vs=hHD+tIg`{K?RD&@#cc!G~q(Z|7?oczu*`8*FZm0FK zL_@c(e0}ADQOi`Q879Egg77OifD=jA d=D#q1a_;<9WH2-^Ff%bx$V)9}_!{7E_Uy~+%BrwG(Q9&Y>W!w&{saIG G+YnXBv=vzZ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d6/cf6c7741b3316826af1314042550c97ded1d50 b/tests-clar/resources/merge-resolve/.gitted/objects/d6/cf6c7741b3316826af1314042550c97ded1d50 new file mode 100644 index 000000000..8f9ae1fc6 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/d6/cf6c7741b3316826af1314042550c97ded1d50 @@ -0,0 +1,2 @@ +xQ +1 D)r%i@oje[7̤ZʽMSLBNlm B~>-uY8ꠟt֯]Qa͠3f]>bl(A] \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/d8/74671ef5b20184836cb983bb273e5280384d0b b/tests-clar/resources/merge-resolve/.gitted/objects/d8/74671ef5b20184836cb983bb273e5280384d0b new file mode 100644 index 0000000000000000000000000000000000000000..1d8037895d1381f172b57a4d583d94675912a95c GIT binary patch literal 162 zcmV;T0A2rh0i}*h3IZ_@L|x|;xxh&0-wh&eynz?!Nm^#WF%qL*-%-4QyQ=q~s9cw2 z?%I04=}kmK305435XB&k4CIj|#DqWw!I*4D6H`$)ZgTA!$Y#NawxqLT%Z^hdj)gM^ zqyQ%3$RT^hk3Q9=kLAU!=+jh}d%fzNtn`x(@)f_f&2`yp8VJOMSELH%bw9K4T1tSHG-29Zxw9M2Lh0HvKoYb@uO)dZ- GSq*CoG8G&E literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/da/178208145ef585a1bd5ca5f4c9785d738df2cf b/tests-clar/resources/merge-resolve/.gitted/objects/da/178208145ef585a1bd5ca5f4c9785d738df2cf new file mode 100644 index 0000000000000000000000000000000000000000..6292118e04480b8dca7e237cc3539b7fc92704d9 GIT binary patch literal 41 zcmV+^0M`F_0ZYosPf{>4X9&s2ELKR%%t=)M(s`-n3YmEd`N<{uW_nxz%E=2MbzKrP literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/db/6261a7c65c7fd678520c9bb6f2c47582ab9ed5 b/tests-clar/resources/merge-resolve/.gitted/objects/db/6261a7c65c7fd678520c9bb6f2c47582ab9ed5 new file mode 100644 index 0000000000000000000000000000000000000000..b82e7fcafe919ebc819e724da40b51811ee2e77f GIT binary patch literal 624 zcmV-$0+0Q80V^p=O;s>7FfnH^G%zqTF;Or`)XmG+P0mQnOHb7+sVHH{ICjFDQ&R2t zO|E6jXKNqcoptAIA53kMZc%D^QD#X=YMyRpo^F0=Q88H0rpq(ei7NTYMzH1C^nT}g zT>E@k7)(#HZc1rEPG)jqNoop6Q%Oc@CRCe#m=GiTwFaSCvC}7RRXi#BH$ZIDIPHctgGE4+IFfTC|ViU-Dx~VCdm=^Q4>-V)w87MTf zPVYPY^I2}2znBHoVoW2zKD=-x(ogKu!-?#Vf7LCst6KHnApSQ@N0M${YB|VOg!hoF zg$I&~lmP45*)!OUN~B9HqB{kh_UzKYV+7b*?Ra?!xyM`kmIr>l8{0qIB~)Rd8B~uE zvaLz^B^h81;++m#0zO$R&EYNGJ~d`*wS}Z)6I6pSHg~3^=A=Ty2kuZa#o3-_g>I+y zvP46-u6%vvf>Fyari$u=~@NRF7|~f`q0XIvsi&YJw?oZkVyliS^HC`PiE_6LU@f*<0K4 zrHdd;Ku;!c7a%3H%Z0O|UOc&}RJPU7=4IKpcTu0VzyjZtIA0{I6slU}zI-!bQPt(d zOoQql3#DM`%uE*)XYk}|s9Tb+YlNIRZu~0W)@;yp@Riy2rmhHGALkC00I2)TQS}yQ zrljf`f}?+ny3qNTv!nvJwF3Xm@Z;_(XWAu*RTEhCw)rp2pPV~?<>V5cJIfDRxV5$4 KX9oay(2y@gz%(=f literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/dd/9a570c3400e6e07bc4d7651d6e20b08926b3d9 b/tests-clar/resources/merge-resolve/.gitted/objects/dd/9a570c3400e6e07bc4d7651d6e20b08926b3d9 new file mode 100644 index 0000000000000000000000000000000000000000..8fd60cbe8f3786729c2cb298f759694f2b533c1d GIT binary patch literal 36 ucmV+<0Nej~0ZYosPf{>4VkpVTEan2Dl*}Uiw9K4TBfXM}5-tFg2nnPqw-2BI literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/de/872ee3618b894992e9d1e18ba2ebe256a112f9 b/tests-clar/resources/merge-resolve/.gitted/objects/de/872ee3618b894992e9d1e18ba2ebe256a112f9 new file mode 100644 index 000000000..04dda4a75 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/de/872ee3618b894992e9d1e18ba2ebe256a112f9 @@ -0,0 +1 @@ +x퐱 S3ŏlKAB4Wb T5:8Sc ԻP`KIˆO3Z&ؐ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/df/e3f22baa1f6fce5447901c3086bae368de6bdd b/tests-clar/resources/merge-resolve/.gitted/objects/df/e3f22baa1f6fce5447901c3086bae368de6bdd new file mode 100644 index 0000000000000000000000000000000000000000..e135694400ea648ddc37f5f9aaab082ab2c75097 GIT binary patch literal 40 ycmV+@0N4L`0ZYosPf{>4V<^eUELH%bqSV~{veXoX%shppqQt!93@!l1nG1b@;uBy1 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e0/67f9361140f19391472df8a82d6610813c73b7 b/tests-clar/resources/merge-resolve/.gitted/objects/e0/67f9361140f19391472df8a82d6610813c73b7 new file mode 100644 index 0000000000000000000000000000000000000000..955431dd7f86a53df75f5e724b277f513956f5a7 GIT binary patch literal 53 zcmV-50LuS(0V^p=O;s>9V=y!@Ff%bxNXyJg)hnqeVff>doSQ28@=@YXHQqg+&*Yt& L{)z(tOS2K(E*BT$ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e1/129b3cfb5898e0fbd606e0cb80b2755e50d161 b/tests-clar/resources/merge-resolve/.gitted/objects/e1/129b3cfb5898e0fbd606e0cb80b2755e50d161 new file mode 100644 index 0000000000000000000000000000000000000000..751f1dd3339cf62eb47d7ecdec90c61467ef6a25 GIT binary patch literal 92 zcmV-i0HgnS0V^p=O;xZoWH2-^Ff%bxNK8pdP0`KF(@n}R$Ma%9vt%$dFfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRQEF~} z8N@N>V6~Fl*LVbFZYx^I$i^|{p7qK@i+nF)szq}6{l}lQSIOs}3vr(yW6-wiamKyu zyO literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e2/c6abbd55fed5ac71a5f2751e29b4a34726a595 b/tests-clar/resources/merge-resolve/.gitted/objects/e2/c6abbd55fed5ac71a5f2751e29b4a34726a595 new file mode 100644 index 000000000..7b84ce966 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/e2/c6abbd55fed5ac71a5f2751e29b4a34726a595 @@ -0,0 +1 @@ +x+)JMU067f040031QH,-M-JOMLI+(aH:,:C: o>ZC'g$楧f&%%g5qYeZokM2ԐX\ZDPC~^ZNfrIf^:XZHي1O(_,' jvn~JfZ&5%\N,5[e2 I{| 2mg˾15ӿ,\})TC)0Dvz֛9MՅ'6b \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e3/1e7ad3ed298f24e383c4950f4671993ec078e4 b/tests-clar/resources/merge-resolve/.gitted/objects/e3/1e7ad3ed298f24e383c4950f4671993ec078e4 new file mode 100644 index 0000000000000000000000000000000000000000..a28ded3fba14e82d26b34749d3a0eaf2ebee1bc8 GIT binary patch literal 210 zcmV;@04@J`0V^p=O;s>5H)Aj~FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRQEF~} z8HQu-KmMe>N>Q@(@ M*vyLs00YTyo6fjkXaE2J literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e3/76fbdd06ebf021c92724da9f26f44212734e3e b/tests-clar/resources/merge-resolve/.gitted/objects/e3/76fbdd06ebf021c92724da9f26f44212734e3e new file mode 100644 index 000000000..8da234114 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/e3/76fbdd06ebf021c92724da9f26f44212734e3e @@ -0,0 +1,3 @@ +xA@E]s +`@ uH)M=Scz:ʊ(N+6ޛDFe𭭘Yg$+G&F +pG 4mQ\85#FC~QERu);c6'j \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e4/9f917b448d1340b31d76e54ba388268fd4c922 b/tests-clar/resources/merge-resolve/.gitted/objects/e4/9f917b448d1340b31d76e54ba388268fd4c922 new file mode 100644 index 0000000000000000000000000000000000000000..870c3e732127964210a7f5f278df26e3cb8f5010 GIT binary patch literal 36 scmbɗEc9%bh37z~5)`i{mMxT|_EsZ?sU zE<+lp4x=+m4#j!mloFZ@7A700P-bEk0XR<@v$u%i5j(F#dKG;kvXMwrbjD@?#{sP( zUy@h@=eD;&&t>8mSo8%# E0I#nTssI20 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e9/ad6ec3e38364a3d07feda7c4197d4d845c53b5 b/tests-clar/resources/merge-resolve/.gitted/objects/e9/ad6ec3e38364a3d07feda7c4197d4d845c53b5 new file mode 100644 index 0000000000000000000000000000000000000000..da4a5edd1879fd8a04095cbe6861992870e543fe GIT binary patch literal 36 scmb4Ghi?@FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nOy zF#rOEr2LW$-IUCtVumHs(%UZVvr+n;>SS`*+Nn?U#2Iy{fyo((dFc=rBo!s*C1-#Q zU7h2y=!MIqwcd`qv)8nn+RbHJ(~YSC$;pEERx@n6yzJ{@cFT@6tUS8aX`zo`8uIhf zax#-kGV{{GX8U#IC8%niTDe;Ax_n!*_r+}w?g>B~oRSs~4i1LPRf~83li~5)$yp&3 zxHIhb>KF0Tph_}}7!=dxG?^+i@;9CHNxmR9b6eG&$A(b5(lVi;(zSLj-(r)gvP-Iy zq}-z|&*WW?+z(Y#l$x7ghT-G;k3VUzlFvUE;yyvfpl#RVjC8-%)vqo*v6&YO051!-Ob*V-0{{R3 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/eb/c09d0137cfb0c26697aed0109fb943ad906f3f b/tests-clar/resources/merge-resolve/.gitted/objects/eb/c09d0137cfb0c26697aed0109fb943ad906f3f new file mode 100644 index 0000000000000000000000000000000000000000..83b489d3af2d92dec412f70ec7f4dcc9f56e8186 GIT binary patch literal 166 zcmV;X09pTd0i}-J4Z<)GgL%#rw*csxeVFMPpUM{o}ZBQEo;}Z}Y@MimyEpwTs zv4Xa7Qx_3H3NG!5xJw*u?j4cqaxmI4QtynmIwi?L-D#1z0(%UZ4aR817}t=FoP6|s zt9j0Zx<@ap=uwBVz&Sl>NpKm;w3ZnT($bGQ$rt?Gj>~j}&Nz*GAH0PvdPLRIcDBl& UGfH0LTF3bcdAx~w15FfCVrz#@_5c6? literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ec/67e5a86adff465359f1c8f995e12dbdfa08d8a b/tests-clar/resources/merge-resolve/.gitted/objects/ec/67e5a86adff465359f1c8f995e12dbdfa08d8a new file mode 100644 index 0000000000000000000000000000000000000000..8490346e1a44c34a5cc8749097072053d727e94f GIT binary patch literal 166 zcmV;X09pTd0i}*XuEH=3ME^Rc@C86l(zuC)5F2j51zg9Wf6)eoAg)hA+<@K8d(vp6 zF3W!hH;jM1sRCiLMVz1~_R%q=Atv=D*r*zqHSwT15i+GIDtM?&maZxfw znu0APh0#q&Duy3@t_{xl$t}ZWuFJiyaL|pu(@8(#+xAkIBUm47ipdTLI}C_squbf8 UKhBt`_8Da6^{Uyt06KtB`Og|r)c^nh literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ed/9523e62e453e50dd9be1606af19399b96e397a b/tests-clar/resources/merge-resolve/.gitted/objects/ed/9523e62e453e50dd9be1606af19399b96e397a new file mode 100644 index 0000000000000000000000000000000000000000..7853e235cb6cc2e4aacfc92f61d976c1b13afbfe GIT binary patch literal 87 zcmV-d0I2_X0ZYosPf{>3wqz*D$ShVU&&>GO3h2mO-)hA%u^`INX;xN=1R;< tQAkb6EP)8-mjZ>jG(dtm`8o=jB?>^zsM4BTTx1wIs)fWz001s1n?-`eB#{6B literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ee/1d6f164893c1866a323f072eeed36b855656be b/tests-clar/resources/merge-resolve/.gitted/objects/ee/1d6f164893c1866a323f072eeed36b855656be new file mode 100644 index 0000000000000000000000000000000000000000..87d808007f0f50037fc92a0ba5c11d7430530327 GIT binary patch literal 291 zcmV+;0o?w00V^p=O;s>9He@g~FfcPQQAo)w(ls<-@D%3Kcpp~vbJ;QhAB%GPx4+`2 zJDC^&0a$?x0 z`)=tV*$IU5=FVw$Xenhg?wkpnVU`-|9!pk?~17_=W$Hj zWxfikAT2W|Ro9R~&i{kvx@Wz-neXRqd%x`T$2Z0LGm%voG2Bd^K1aEhW7{rEHofQj zQ;uKuQvU&QCD;gK1|!A0f!cMtN4D-|X370_LRxDRJ2#R76NXve4Sxyd%I#csKwxT; pyUxF7UsqNlDKKR?*O72#p7pEz>#pryjN1=C$z5^!FaVUJit5r)lRN+b literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ee/3fa1b8c00aff7fe02065fdb50864bb0d932ccf b/tests-clar/resources/merge-resolve/.gitted/objects/ee/3fa1b8c00aff7fe02065fdb50864bb0d932ccf new file mode 100644 index 0000000000000000000000000000000000000000..974b72dfd16aba70c9dd263a606d7c89f6f8d542 GIT binary patch literal 64 zcmV-G0Kflu0ZYosPf{>4F=r^r$ShV!%gjkt0Mf}BiFxU%DGHf+3b~2JC85H)Aj~FfcPQQAjK;$5Ep%1PBLsVHG!ZFT%(F6jM7 z_U^a6+5eCKdV1*DKd9p5jKsY3)D+#!Jl&+C#JuDTum-;kKJzMH^rtyokpH?VX3;YC zluu%q8gdhhOHzx#8dm4HEPCNGX|1>8?(8+~rgn3g)^x)(=^5eiw>y=j_bNqXJH5365Ycw#dz7683sbmAR6dtv|p literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ef/58fdd8086c243bdc81f99e379acacfd21d32d6 b/tests-clar/resources/merge-resolve/.gitted/objects/ef/58fdd8086c243bdc81f99e379acacfd21d32d6 new file mode 100644 index 000000000..55f79e066 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/ef/58fdd8086c243bdc81f99e379acacfd21d32d6 @@ -0,0 +1,2 @@ +x 0О:JBݟOV +y55jq!4{:p; \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ef/c499524cf105d5264ac7fc54e07e95764e8075 b/tests-clar/resources/merge-resolve/.gitted/objects/ef/c499524cf105d5264ac7fc54e07e95764e8075 new file mode 100644 index 0000000000000000000000000000000000000000..bc9350bc0ae4db2b21c363fba25efd2112002d92 GIT binary patch literal 32 ocmb#%dHz)aQ|tRo0kXhC#vbaZ}yyT}ujqZm3Y=++B%$EEZu~wgp|->3lVI>(Gr4_Tbi8u90;O~R0V}V0fNWold~r)jnML^ Oj`-L4^5O@<{^3(s5>KW8 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f0/053b8060bb3f0be5cbcc3147a07ece26bf097e b/tests-clar/resources/merge-resolve/.gitted/objects/f0/053b8060bb3f0be5cbcc3147a07ece26bf097e new file mode 100644 index 0000000000000000000000000000000000000000..c63d37fb0c17e54194d10b7b63f254ad28294dca GIT binary patch literal 163 zcmV;U09^lg0i}*n4#FT1ME&LzT%cxwLTO@*Ki{8eCJ#%_ zYm<5$cdatZNd+QJQ=AQ18YHORC%UXs3b2-$@j9!19$pKC;kqQW>iifPqmC&^<(_UAFO` RH=@<`xrXa7i#PWmP;1?^OtSz0 literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f0/ce2b8e4986084d9b308fb72709e414c23eb5e6 b/tests-clar/resources/merge-resolve/.gitted/objects/f0/ce2b8e4986084d9b308fb72709e414c23eb5e6 new file mode 100644 index 0000000000000000000000000000000000000000..e78c19f1a7fc0d2c60a6f7ec2db9068059635032 GIT binary patch literal 125 zcmV-@0D}K`0qu}W4gx_4L|t$=Ne&I7OQ(?<^m}NE@ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f2/0c9063fa0bda9a397c96947a7b687305c49753 b/tests-clar/resources/merge-resolve/.gitted/objects/f2/0c9063fa0bda9a397c96947a7b687305c49753 new file mode 100644 index 0000000000000000000000000000000000000000..34d9aed2078aaf12eecf75dd49070222816386c5 GIT binary patch literal 29 lcmb4X9&s2ELKR%%t=)M(s`-n3YmEd`N<{uCVE@|%EJpEb4d~G literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f3/293571dcd708b6a3faf03818cd2844d000e198 b/tests-clar/resources/merge-resolve/.gitted/objects/f3/293571dcd708b6a3faf03818cd2844d000e198 new file mode 100644 index 000000000..f748743b8 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/f3/293571dcd708b6a3faf03818cd2844d000e198 @@ -0,0 +1 @@ +xKj0)dZ!\@nI,3{XZ?F/\E12zc"#X1][_G&c+9XWKžiUtgS*O۹)u|oXp*" pӤtũ`9zKO\ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f3/f1164b68b57b1995b658a828320e6df3081fae b/tests-clar/resources/merge-resolve/.gitted/objects/f3/f1164b68b57b1995b658a828320e6df3081fae new file mode 100644 index 0000000000000000000000000000000000000000..5f0b4e424b070951dcb5fe1350d396c9ad772126 GIT binary patch literal 310 zcmV-60m=S&0V^p=O;s>4Fkvt>FfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chbt=$r*`x=@1P`MTvRI8DI^ob6gg^aGA8$+i`dHns!sWxlC)i zF*P9BAb4*z!=}s2zAk3B>{!Ffqg$O8`Us{WKQApOGr1%)FCA>QUq@bos^+Pcs|Byi zwZ`ve(-wq1`i?q%PFYsgE?1!^!g02>|Q z{BO@DlZN};akrHg$wVG6+TEv#rqbLLta5o(*pm7ER*#$>sEdE>+kK2D=BP88N=t~D zzYf^z1X?EcwqG?9IT+kz{qeK#G^ol_U~qv$4{YR#5BYl5o2EIIq}NUSu=>@7CpPn9 I0c?$+eO|GbjQ{`u literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f4/15caf3fcad16304cb424b67f0ee6b12dc03aae b/tests-clar/resources/merge-resolve/.gitted/objects/f4/15caf3fcad16304cb424b67f0ee6b12dc03aae new file mode 100644 index 0000000000000000000000000000000000000000..21ce1a0fc8e574dba18fe5844e053a5d8ba1f42a GIT binary patch literal 320 zcmV-G0l)ru0V^p=O;s?quw*baFfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nPt zDo)Nw%u9!uo>Y{Wmz)9CusX+O(F>PJYrP$JXRm2DwVTVdrW;cOl5+&_t!CJCdD+*+ z?3NvCSb21-(?TD?H00-{WH4yjTF=BcAs?_@;vZ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f4/8097eb340dc5a7cae55aabcf1faf4548aa821f b/tests-clar/resources/merge-resolve/.gitted/objects/f4/8097eb340dc5a7cae55aabcf1faf4548aa821f new file mode 100644 index 0000000000000000000000000000000000000000..5a4a9a54ff8c314cd2ad57c89720e64ccdcf51d4 GIT binary patch literal 165 zcmV;W09yZe0i}-J2?8+?gndpGY2aipx%`2MFLq!9o6Uw3%td0v_Kji(zRi3CGefnM zYnN*AyWW^31ZREZq?GkQDS|h_dYv&?=ZMHBgUZk>?$~(ik|RM#Fl$FS0x4^QLmmJ^ zj$zT50@$pxz-M1;ljropmgHrv&D0lEPxnvobCK) TjWBrYlbT|~jaKmnl08t_mX=cO literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f5/504f36e6f4eb797a56fc5bac6c6c7f32969bf2 b/tests-clar/resources/merge-resolve/.gitted/objects/f5/504f36e6f4eb797a56fc5bac6c6c7f32969bf2 new file mode 100644 index 0000000000000000000000000000000000000000..2aa0c3b9ac075224b59d6b1e498ac5798182e253 GIT binary patch literal 42 ycmbXs^_G$iz?`#c>w^1pW?r literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f5/f9dd5886a6ee20272be0aafc790cba43b31931 b/tests-clar/resources/merge-resolve/.gitted/objects/f5/f9dd5886a6ee20272be0aafc790cba43b31931 new file mode 100644 index 0000000000000000000000000000000000000000..17ad5063d7cc04ca26dea94be689a6d5446dc2d3 GIT binary patch literal 244 zcmV9Gh{F{FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~TNenDnx z3Ru;N5BYl5o2EIIq}NUSu=>@7CpPn9p{j~fbMwm}PDXM;jCICx`6It#&Gav~#{~=5 uWJPUX3fGXAn2X`Z`;R|quaeI{7vera#-MH29wPY|fFfcPQQAkWlNlnqs%+t+HEG|hc(krPbVNkZ=lsq}( ztss|o{^xvCt2f<+Chaigr6u{fsYU6jiAg!BV8!q37w$N~^}qgsLh9eG94WhbC+nPt zDo)Nw%u9!uo>Y{Wmz)9CusX+O(F>PJYrP$JXRm2DwVTVdrW;cOl5+&_t!CJCdD+*+ z?3NvCSb21-(?TD?H00-{3R=>LN#AaSBR8>)GUSckWlkY$Nq`gW$|6GXs1Q~<2U5_*F PW#2{BfYV$6R3ehVI5CG+ literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/f7/c332bd4d4d4b777366cae4d24d1687477576bf b/tests-clar/resources/merge-resolve/.gitted/objects/f7/c332bd4d4d4b777366cae4d24d1687477576bf new file mode 100644 index 0000000000000000000000000000000000000000..b36bceabf726a44d0d0d4a49070f3f812b52f583 GIT binary patch literal 156 zcmV;N0Av4n0i}-34T2#ML_Jf*HlSHpSs*dSiyhbiKTAFjh(V0)`)TaJ+su2(WO8rq zI>8Wc<`4m=wcE2x+B4e7jFQA!&!ut@Lt0C*jG?M~9CDkG8C}hU-jfj7BGvd@*mJVF za;_0gLYA!Jb1r?rxxC^ia9MhL^cx&xrJrf1x}xwUQv kv@`O;$Kșybh2癈sLA ?R\˷ץ(~Yïb-'Yǎp=Njq˟m[zO+ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fa/c03f2c5139618d87d53614c153823bf1f31396 b/tests-clar/resources/merge-resolve/.gitted/objects/fa/c03f2c5139618d87d53614c153823bf1f31396 new file mode 100644 index 0000000000000000000000000000000000000000..30e07e5b71907affcaa1fe169114c2091179b9f9 GIT binary patch literal 76 zcmV-S0JHyi0ZYosPf{>4F=Z&p$ShV!%gjkt0Mf}BiFxU%DGHf+3b~2JC8`5|TmSkbE%WNtM?olhxoR=Q;oZ0!L$zf_1L1 zwVPrJinUWD=+)*@o_Yw-ci3{MpqXiz%< literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fb/738a106cfd097a4acb96ce132ecb1ad6c46b03 b/tests-clar/resources/merge-resolve/.gitted/objects/fb/738a106cfd097a4acb96ce132ecb1ad6c46b03 new file mode 100644 index 0000000000000000000000000000000000000000..4f1e7268818a62a5d3fdf8ec89d1ec7a62624e79 GIT binary patch literal 264 zcmV+j0r&oR0V^p=O;s>9vt%$dFfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRQEF~} z8N@N>V72F-g&m%>mNk6yst3OvMM@8`J(`q{sTRrM_aA@KUL~J@F2sF;j6vJ3#~Jss z?_z2|a(Ik&#&Y>1zhcewFSo}93)f^tZC?u2PznqUaNvNQa^ge2p7o|_jwR`J6F;ne Ob>WH4yjTEmHI#L$M0@uD literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fc/4c636d6515e9e261f9260dbcf3cc6eca97ea08 b/tests-clar/resources/merge-resolve/.gitted/objects/fc/4c636d6515e9e261f9260dbcf3cc6eca97ea08 new file mode 100644 index 0000000000000000000000000000000000000000..be8a810cd868bbbd5bcf1e52b507985151ed663f GIT binary patch literal 29 lcmbJ%v0V^p=O;xb8G+{6_FfcPQQ7}l<&CAzK&PdElPt_}_C}GGrcEX!eQtkLn zu4T(-Yaia7b?0m!Ol^{GQEGWnW=TnEo^EEIZhmP|F<8%sbJ~5LZ5+O{4f?mMb3PF{ zWViJhOiwbZo|25zOsFpXFd;_vYYjrPVy92ss(4zic+p!!s4l}qpsu{c+|(49J-VqW znI#Y|k`ae5=)Lb$IDB|J>J^4Jn-w? z*#6lrp$ZGlpn8muZB5EA$pC8*?{wG_@X2Cn4sYr9sWDrtEhHtIpc;%Z11BXlClxbv zBu*P<%e-IkW7(8^J_V^hsr;6xoiH=7`4!0&xM$52XM36zx}Da`5)IwD^7WMqMlDmJ zW|&~QBQYffBaW2HCvDYQ#jV`^is4ONz-*=@d$Asv3D{f#Hv{g58CP}L4{X@|X-lfd zw^czxQxBaEy$vk^=vaNJ3psPGU;0P7weA literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fd/57d2d6770fad8e9959124793a17f441b571e66 b/tests-clar/resources/merge-resolve/.gitted/objects/fd/57d2d6770fad8e9959124793a17f441b571e66 new file mode 100644 index 0000000000000000000000000000000000000000..21e6b2c558d523a599df3883b7c13b0080096328 GIT binary patch literal 279 zcmV+y0qFjC0V^p=O;s>9H(@X|FfcPQQAjK;$5Ep%1PBLsVHGc5;`oqI?hAM z{rdDef8NUpvTr_GLlq}yB<7{3rs!to=_VB=<|Su>F;6I8oGd50*9~fRUTV2+ zVqS`FN@iMGYEf!l30T8_&kGfq%~IDBci(!&l+gC0V)kj6SBp|}^UE+?fB*3(?N##m z=R({k$QZQkdYo}D`!3W5Bn?QekFm~JE`Q`#teO7h_PAi-nyjepOQ9M{fk6TeA+S?U de8|_c-ZagzB)x9pht;nxJh7P<3jkUVmYXeUg!BLa literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fd/89f8cffb663ac89095a0f9764902e93ceaca6a b/tests-clar/resources/merge-resolve/.gitted/objects/fd/89f8cffb663ac89095a0f9764902e93ceaca6a new file mode 100644 index 000000000..2f9d83b26 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/fd/89f8cffb663ac89095a0f9764902e93ceaca6a @@ -0,0 +1,2 @@ +xK!D]s +.{`cx/ɸ`0 oURy|Y`dPA!4C2d=x#e`BgrubLffG@՗-}KԲUy=];)r0 R$(%o=׶OPw \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/fe/5407fc50a53aecb41d1a6e9ea7b612e581af87 b/tests-clar/resources/merge-resolve/.gitted/objects/fe/5407fc50a53aecb41d1a6e9ea7b612e581af87 new file mode 100644 index 0000000000000000000000000000000000000000..4ce7d2297be2cd33aee824f46f5a127f4c56ca98 GIT binary patch literal 48 zcmV-00MGw;0ZYosPf{>8V(`sR$xO>kO;O0qQ&2A{$}G!F%+WP8)J-Z%%uCKt=K=r< GkPO-w^A&6W literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/ff/49d07869831ad761bbdaea026086f8789bcb00 b/tests-clar/resources/merge-resolve/.gitted/objects/ff/49d07869831ad761bbdaea026086f8789bcb00 new file mode 100644 index 0000000000000000000000000000000000000000..eada39b77e4dc3894bb405dbb2c7d93d0d6ab6a7 GIT binary patch literal 24 gcmb Date: Tue, 30 Apr 2013 14:56:41 -0500 Subject: [PATCH 115/134] renames! --- include/git2/index.h | 53 ++++ include/git2/merge.h | 13 + src/diff.h | 12 + src/diff_tform.c | 18 +- src/index.c | 218 ++++++++++++++ src/index.h | 1 + src/merge.c | 485 +++++++++++++++++++++++++++++- tests-clar/index/names.c | 83 +++++ tests-clar/merge/merge_helpers.c | 87 +++++- tests-clar/merge/trees/renames.c | 253 ++++++++++++++++ tests-clar/merge/trees/treediff.c | 275 +++++++++++++++++ 11 files changed, 1487 insertions(+), 11 deletions(-) create mode 100644 tests-clar/index/names.c create mode 100644 tests-clar/merge/trees/renames.c diff --git a/include/git2/index.h b/include/git2/index.h index fcfe4be3d..01e3d2c29 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -84,6 +84,12 @@ typedef struct git_index_entry { char *path; } git_index_entry; +typedef struct git_index_name_entry { + char *ancestor; + char *ours; + char *theirs; +} git_index_name_entry; + /** Representation of a resolve undo entry in the index. */ typedef struct git_index_reuc_entry { unsigned int mode[3]; @@ -478,6 +484,53 @@ GIT_EXTERN(int) git_index_has_conflicts(const git_index *index); /**@}*/ +/** @name Conflict Name entry functions + * + * These functions work on rename conflict entries. + */ +/**@{*/ + +/** + * Get the count of filename conflict entries currently in the index. + * + * @param index an existing index object + * @return integer of count of current filename conflict entries + */ +GIT_EXTERN(unsigned int) git_index_name_entrycount(git_index *index); + +/** + * Get a filename conflict entry from the index. + * + * The returned entry is read-only and should not be modified + * or freed by the caller. + * + * @param index an existing index object + * @param n the position of the entry + * @return a pointer to the filename conflict entry; NULL if out of bounds + */ +GIT_EXTERN(const git_index_name_entry *) git_index_name_get_byindex( + git_index *index, size_t n); + +/** + * Record the filenames involved in a rename conflict. + * + * @param index an existing index object + * @param ancestor the path of the file as it existed in the ancestor + * @param ours the path of the file as it existed in our tree + * @param theirs the path of the file as it existed in their tree + */ +GIT_EXTERN(int) git_index_name_add(git_index *index, + const char *ancestor, const char *ours, const char *theirs); + +/** + * Remove all filename conflict entries. + * + * @param index an existing index object + * @return 0 or an error code + */ +GIT_EXTERN(void) git_index_name_clear(git_index *index); +/**@}*/ + /** @name Resolve Undo (REUC) index entry manipulation. * * These functions work on the Resolve Undo index extension and contains diff --git a/include/git2/merge.h b/include/git2/merge.h index 43a61f0e4..8ca90b95f 100644 --- a/include/git2/merge.h +++ b/include/git2/merge.h @@ -27,6 +27,8 @@ GIT_BEGIN_DECL * passed in via the `flags` value in the `git_diff_tree_many_options`. */ typedef enum { + /** Detect renames */ + GIT_MERGE_TREE_FIND_RENAMES = (1 << 0), } git_merge_tree_flags; /** @@ -44,6 +46,17 @@ typedef struct { unsigned int version; git_merge_tree_flags flags; + /** Similarity to consider a file renamed (default 50) */ + unsigned int rename_threshold; + + /** Maximum similarity sources to examine (overrides the + * `merge.renameLimit` config) (default 200) + */ + unsigned int target_limit; + + /** Pluggable similarity metric; pass NULL to use internal metric */ + git_diff_similarity_metric *metric; + /** Flags for automerging content. */ git_merge_automerge_flags automerge_flags; } git_merge_tree_opts; diff --git a/src/diff.h b/src/diff.h index 8e3cbcd46..48e20d1e3 100644 --- a/src/diff.h +++ b/src/diff.h @@ -74,5 +74,17 @@ extern int git_diff__from_iterators( git_iterator *new_iter, const git_diff_options *opts); +int git_diff_find_similar__hashsig_for_file( + void **out, const git_diff_file *f, const char *path, void *p); + +int git_diff_find_similar__hashsig_for_buf( + void **out, const git_diff_file *f, const char *buf, size_t len, void *p); + +void git_diff_find_similar__hashsig_free(void *sig, void *payload); + +int git_diff_find_similar__calc_similarity( + int *score, void *siga, void *sigb, void *payload); + + #endif diff --git a/src/diff_tform.c b/src/diff_tform.c index 5c1a86cb9..201a0e896 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -170,7 +170,7 @@ int git_diff_merge( return error; } -static int find_similar__hashsig_for_file( +int git_diff_find_similar__hashsig_for_file( void **out, const git_diff_file *f, const char *path, void *p) { git_hashsig_option_t opt = (git_hashsig_option_t)p; @@ -187,12 +187,12 @@ static int find_similar__hashsig_for_file( return error; } -static int find_similar__hashsig_for_buf( +int git_diff_find_similar__hashsig_for_buf( void **out, const git_diff_file *f, const char *buf, size_t len, void *p) { git_hashsig_option_t opt = (git_hashsig_option_t)p; int error = 0; - + GIT_UNUSED(f); error = git_hashsig_create((git_hashsig **)out, buf, len, opt); @@ -204,13 +204,13 @@ static int find_similar__hashsig_for_buf( return error; } -static void find_similar__hashsig_free(void *sig, void *payload) +void git_diff_find_similar__hashsig_free(void *sig, void *payload) { GIT_UNUSED(payload); git_hashsig_free(sig); } -static int find_similar__calc_similarity( +int git_diff_find_similar__calc_similarity( int *score, void *siga, void *sigb, void *payload) { GIT_UNUSED(payload); @@ -291,10 +291,10 @@ static int normalize_find_opts( opts->metric = git__malloc(sizeof(git_diff_similarity_metric)); GITERR_CHECK_ALLOC(opts->metric); - opts->metric->file_signature = find_similar__hashsig_for_file; - opts->metric->buffer_signature = find_similar__hashsig_for_buf; - opts->metric->free_signature = find_similar__hashsig_free; - opts->metric->similarity = find_similar__calc_similarity; + opts->metric->file_signature = git_diff_find_similar__hashsig_for_file; + opts->metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; + opts->metric->free_signature = git_diff_find_similar__hashsig_free; + opts->metric->similarity = git_diff_find_similar__calc_similarity; if (opts->flags & GIT_DIFF_FIND_IGNORE_WHITESPACE) opts->metric->payload = (void *)GIT_HASHSIG_IGNORE_WHITESPACE; diff --git a/src/index.c b/src/index.c index fe3a2104b..656fb5bc5 100644 --- a/src/index.c +++ b/src/index.c @@ -35,6 +35,7 @@ static const unsigned int INDEX_VERSION_NUMBER_EXT = 3; static const unsigned int INDEX_HEADER_SIG = 0x44495243; static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'}; static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'}; +static const char INDEX_EXT_CONFLICT_NAME_SIG[] = {'N', 'A', 'M', 'E'}; #define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx))) @@ -187,6 +188,46 @@ static int index_icmp(const void *a, const void *b) return diff; } +static int conflict_name_cmp(const void *a, const void *b) +{ + const git_index_name_entry *name_a = a; + const git_index_name_entry *name_b = b; + + if (name_a->ancestor && !name_b->ancestor) + return 1; + + if (!name_a->ancestor && name_b->ancestor) + return -1; + + if (name_a->ancestor) + return strcmp(name_a->ancestor, name_b->ancestor); + + if (!name_a->ours || !name_b->ours) + return 0; + + return strcmp(name_a->ours, name_b->ours); +} + +static int conflict_name_icmp(const void *a, const void *b) +{ + const git_index_name_entry *name_a = a; + const git_index_name_entry *name_b = b; + + if (name_a->ancestor && !name_b->ancestor) + return 1; + + if (!name_a->ancestor && name_b->ancestor) + return -1; + + if (name_a->ancestor) + return strcasecmp(name_a->ancestor, name_b->ancestor); + + if (!name_a->ours || !name_b->ours) + return 0; + + return strcasecmp(name_a->ours, name_b->ours); +} + static int reuc_srch(const void *key, const void *array_member) { const git_index_reuc_entry *reuc = array_member; @@ -278,6 +319,7 @@ int git_index_open(git_index **index_out, const char *index_path) } if (git_vector_init(&index->entries, 32, index_cmp) < 0 || + git_vector_init(&index->names, 32, conflict_name_cmp) < 0 || git_vector_init(&index->reuc, 32, reuc_cmp) < 0) return -1; @@ -331,6 +373,8 @@ void git_index_clear(git_index *index) git_index_reuc_clear(index); + git_index_name_clear(index); + git_futils_filestamp_set(&index->stamp, NULL); git_tree_cache_free(index->tree); @@ -1042,6 +1086,72 @@ int git_index_has_conflicts(const git_index *index) return 0; } +unsigned int git_index_name_entrycount(git_index *index) +{ + assert(index); + return (unsigned int)index->names.length; +} + +const git_index_name_entry *git_index_name_get_byindex( + git_index *index, size_t n) +{ + assert(index); + + git_vector_sort(&index->names); + return git_vector_get(&index->names, n); +} + +int git_index_name_add(git_index *index, + const char *ancestor, const char *ours, const char *theirs) +{ + git_index_name_entry *conflict_name; + + assert ((ancestor && ours) || (ancestor && theirs) || (ours && theirs)); + + conflict_name = git__calloc(1, sizeof(git_index_name_entry)); + GITERR_CHECK_ALLOC(conflict_name); + + if (ancestor) { + conflict_name->ancestor = git__strdup(ancestor); + GITERR_CHECK_ALLOC(conflict_name->ancestor); + } + + if (ours) { + conflict_name->ours = git__strdup(ours); + GITERR_CHECK_ALLOC(conflict_name->ours); + } + + if (theirs) { + conflict_name->theirs = git__strdup(theirs); + GITERR_CHECK_ALLOC(conflict_name->theirs); + } + + return git_vector_insert(&index->names, conflict_name); +} + +void git_index_name_clear(git_index *index) +{ + size_t i; + git_index_name_entry *conflict_name; + + assert(index); + + git_vector_foreach(&index->names, i, conflict_name) { + if (conflict_name->ancestor) + git__free(conflict_name->ancestor); + + if (conflict_name->ours) + git__free(conflict_name->ours); + + if (conflict_name->theirs) + git__free(conflict_name->theirs); + + git__free(conflict_name); + } + + git_vector_clear(&index->names); +} + unsigned int git_index_reuc_entrycount(git_index *index) { assert(index); @@ -1228,6 +1338,52 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) return 0; } + +static int read_conflict_names(git_index *index, const char *buffer, size_t size) +{ + size_t len; + + /* This gets called multiple times, the vector might already be initialized */ + if (index->names._alloc_size == 0 && + git_vector_init(&index->names, 16, conflict_name_cmp) < 0) + return -1; + +#define read_conflict_name(ptr) \ + len = strlen(buffer) + 1; \ + if (size < len) \ + return index_error_invalid("reading conflict name entries"); \ + \ + if (len == 1) \ + ptr = NULL; \ + else { \ + ptr = git__malloc(len); \ + GITERR_CHECK_ALLOC(ptr); \ + memcpy(ptr, buffer, len); \ + } \ + \ + buffer += len; \ + size -= len; + + while (size) { + git_index_name_entry *conflict_name = git__calloc(1, sizeof(git_index_name_entry)); + GITERR_CHECK_ALLOC(conflict_name); + + read_conflict_name(conflict_name->ancestor); + read_conflict_name(conflict_name->ours); + read_conflict_name(conflict_name->theirs); + + if (git_vector_insert(&index->names, conflict_name) < 0) + return -1; + } + +#undef read_conflict_name + + /* entries are guaranteed to be sorted on-disk */ + index->names.sorted = 1; + + return 0; +} + static size_t read_entry(git_index_entry *dest, const void *buffer, size_t buffer_size) { size_t path_length, entry_size; @@ -1332,6 +1488,9 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer } else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) { if (read_reuc(index, buffer + 8, dest.extension_size) < 0) return 0; + } else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) { + if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0) + return 0; } /* else, unsupported extension. We cannot parse this, but we can skip * it by returning `total_size */ @@ -1545,6 +1704,61 @@ static int write_extension(git_filebuf *file, struct index_extension *header, gi return error; } +static int create_name_extension_data(git_buf *name_buf, git_index_name_entry *conflict_name) +{ + int error = 0; + + if (conflict_name->ancestor == NULL) + error = git_buf_put(name_buf, "\0", 1); + else + error = git_buf_put(name_buf, conflict_name->ancestor, strlen(conflict_name->ancestor) + 1); + + if (error != 0) + goto on_error; + + if (conflict_name->ours == NULL) + error = git_buf_put(name_buf, "\0", 1); + else + error = git_buf_put(name_buf, conflict_name->ours, strlen(conflict_name->ours) + 1); + + if (error != 0) + goto on_error; + + if (conflict_name->theirs == NULL) + error = git_buf_put(name_buf, "\0", 1); + else + error = git_buf_put(name_buf, conflict_name->theirs, strlen(conflict_name->theirs) + 1); + +on_error: + return error; +} + +static int write_name_extension(git_index *index, git_filebuf *file) +{ + git_buf name_buf = GIT_BUF_INIT; + git_vector *out = &index->names; + git_index_name_entry *conflict_name; + struct index_extension extension; + size_t i; + int error = 0; + + git_vector_foreach(out, i, conflict_name) { + if ((error = create_name_extension_data(&name_buf, conflict_name)) < 0) + goto done; + } + + memset(&extension, 0x0, sizeof(struct index_extension)); + memcpy(&extension.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4); + extension.extension_size = (uint32_t)name_buf.size; + + error = write_extension(file, &extension, &name_buf); + + git_buf_free(&name_buf); + +done: + return error; +} + static int create_reuc_extension_data(git_buf *reuc_buf, git_index_reuc_entry *reuc) { int i; @@ -1615,6 +1829,10 @@ static int write_index(git_index *index, git_filebuf *file) /* TODO: write tree cache extension */ + /* write the rename conflict extension */ + if (index->names.length > 0 && write_name_extension(index, file) < 0) + return -1; + /* write the reuc extension */ if (index->reuc.length > 0 && write_reuc_extension(index, file) < 0) return -1; diff --git a/src/index.h b/src/index.h index 9498907b6..2ad401741 100644 --- a/src/index.h +++ b/src/index.h @@ -33,6 +33,7 @@ struct git_index { git_tree_cache *tree; + git_vector names; git_vector reuc; git_vector_cmp entries_cmp_path; diff --git a/src/merge.c b/src/merge.c index 8df156abe..681f302f4 100644 --- a/src/merge.c +++ b/src/merge.c @@ -23,6 +23,7 @@ #include "merge_file.h" #include "blob.h" #include "hashsig.h" +#include "oid.h" #include "git2/types.h" #include "git2/repository.h" @@ -640,6 +641,440 @@ done: return error; } +/* Rename detection and coalescing */ + +struct merge_diff_similarity { + unsigned char similarity; + size_t other_idx; +}; + +static int index_entry_similarity_exact( + git_repository *repo, + git_index_entry *a, + size_t a_idx, + git_index_entry *b, + size_t b_idx, + void **cache, + const git_merge_tree_opts *opts) +{ + GIT_UNUSED(repo); + GIT_UNUSED(a_idx); + GIT_UNUSED(b_idx); + GIT_UNUSED(cache); + GIT_UNUSED(opts); + + if (git_oid__cmp(&a->oid, &b->oid) == 0) + return 100; + + return 0; +} + +static int index_entry_similarity_calc( + void **out, + git_repository *repo, + git_index_entry *entry, + const git_merge_tree_opts *opts) +{ + git_blob *blob; + git_diff_file diff_file = {{{0}}}; + int error; + + *out = NULL; + + if ((error = git_blob_lookup(&blob, repo, &entry->oid)) < 0) + return error; + + git_oid_cpy(&diff_file.oid, &entry->oid); + diff_file.path = entry->path; + diff_file.size = entry->file_size; + diff_file.mode = entry->mode; + diff_file.flags = 0; + + error = opts->metric->buffer_signature(out, &diff_file, + git_blob_rawcontent(blob), git_blob_rawsize(blob), + opts->metric->payload); + + git_blob_free(blob); + + return error; +} + +static int index_entry_similarity_inexact( + git_repository *repo, + git_index_entry *a, + size_t a_idx, + git_index_entry *b, + size_t b_idx, + void **cache, + const git_merge_tree_opts *opts) +{ + int score = 0; + int error = 0; + + if (GIT_MODE_TYPE(a->mode) != GIT_MODE_TYPE(b->mode)) + return 0; + + /* update signature cache if needed */ + if (!cache[a_idx] && (error = index_entry_similarity_calc(&cache[a_idx], repo, a, opts)) < 0) + return error; + if (!cache[b_idx] && (error = index_entry_similarity_calc(&cache[b_idx], repo, b, opts)) < 0) + return error; + + /* some metrics may not wish to process this file (too big / too small) */ + if (!cache[a_idx] || !cache[b_idx]) + return 0; + + /* compare signatures */ + if (opts->metric->similarity( + &score, cache[a_idx], cache[b_idx], opts->metric->payload) < 0) + return -1; + + /* clip score */ + if (score < 0) + score = 0; + else if (score > 100) + score = 100; + + return score; +} + +static int merge_diff_mark_similarity( + git_repository *repo, + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + struct merge_diff_similarity *similarity_theirs, + int (*similarity_fn)(git_repository *, git_index_entry *, size_t, git_index_entry *, size_t, void **, const git_merge_tree_opts *), + void **cache, + const git_merge_tree_opts *opts) +{ + size_t i, j; + git_merge_diff *conflict_src, *conflict_tgt; + int similarity; + + git_vector_foreach(&diff_list->conflicts, i, conflict_src) { + /* Items can be the source of a rename iff they have an item in the + * ancestor slot and lack an item in the ours or theirs slot. */ + if (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->ancestor_entry) || + (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry) && + GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry))) + continue; + + git_vector_foreach(&diff_list->conflicts, j, conflict_tgt) { + size_t our_idx = diff_list->conflicts.length + j; + size_t their_idx = (diff_list->conflicts.length * 2) + j; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->ancestor_entry)) + continue; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->our_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->our_entry)) { + similarity = similarity_fn(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->our_entry, our_idx, cache, opts); + + if (similarity == GIT_EBUFS) + continue; + else if (similarity < 0) + return similarity; + + if (similarity > similarity_ours[i].similarity && + similarity > similarity_ours[j].similarity) { + /* Clear previous best similarity */ + if (similarity_ours[i].similarity > 0) + similarity_ours[similarity_ours[i].other_idx].similarity = 0; + + if (similarity_ours[j].similarity > 0) + similarity_ours[similarity_ours[j].other_idx].similarity = 0; + + similarity_ours[i].similarity = similarity; + similarity_ours[i].other_idx = j; + + similarity_ours[j].similarity = similarity; + similarity_ours[j].other_idx = i; + } + } + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_tgt->their_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict_src->their_entry)) { + similarity = similarity_fn(repo, &conflict_src->ancestor_entry, i, &conflict_tgt->their_entry, their_idx, cache, opts); + + if (similarity > similarity_theirs[i].similarity && + similarity > similarity_theirs[j].similarity) { + /* Clear previous best similarity */ + if (similarity_theirs[i].similarity > 0) + similarity_theirs[similarity_theirs[i].other_idx].similarity = 0; + + if (similarity_theirs[j].similarity > 0) + similarity_theirs[similarity_theirs[j].other_idx].similarity = 0; + + similarity_theirs[i].similarity = similarity; + similarity_theirs[i].other_idx = j; + + similarity_theirs[j].similarity = similarity; + similarity_theirs[j].other_idx = i; + } + } + } + } + + return 0; +} + +/* + * Rename conflicts: + * + * Ancestor Ours Theirs + * + * 0a A A A No rename + * b A A* A No rename (ours was rewritten) + * c A A A* No rename (theirs rewritten) + * 1a A A B[A] Rename or rename/edit + * b A B[A] A (automergeable) + * 2 A B[A] B[A] Both renamed (automergeable) + * 3a A B[A] Rename/delete + * b A B[A] (same) + * 4a A B[A] B Rename/add [B~ours B~theirs] + * b A B B[A] (same) + * 5 A B[A] C[A] Both renamed ("1 -> 2") + * 6 A C[A] Both renamed ("2 -> 1") + * B C[B] [C~ours C~theirs] (automergeable) + */ +static void merge_diff_mark_rename_conflict( + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + bool ours_renamed, + size_t ours_source_idx, + struct merge_diff_similarity *similarity_theirs, + bool theirs_renamed, + size_t theirs_source_idx, + git_merge_diff *target, + const git_merge_tree_opts *opts) +{ + git_merge_diff *ours_source = NULL, *theirs_source = NULL; + + if (ours_renamed) + ours_source = diff_list->conflicts.contents[ours_source_idx]; + + if (theirs_renamed) + theirs_source = diff_list->conflicts.contents[theirs_source_idx]; + + /* Detect 2->1 conflicts */ + if (ours_renamed && theirs_renamed) { + /* Both renamed to the same target name. */ + if (ours_source_idx == theirs_source_idx) + ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED; + else { + ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; + theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1; + } + } else if (ours_renamed) { + /* If our source was also renamed in theirs, this is a 1->2 */ + if (similarity_theirs[ours_source_idx].similarity >= opts->rename_threshold) + ours_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; + + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry)) { + ours_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; + target->type = GIT_MERGE_DIFF_RENAMED_ADDED; + } + + else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(ours_source->their_entry)) + ours_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; + + else if (ours_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) + ours_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; + } else if (theirs_renamed) { + /* If their source was also renamed in ours, this is a 1->2 */ + if (similarity_ours[theirs_source_idx].similarity >= opts->rename_threshold) + theirs_source->type = GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2; + + else if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry)) { + theirs_source->type = GIT_MERGE_DIFF_RENAMED_ADDED; + target->type = GIT_MERGE_DIFF_RENAMED_ADDED; + } + + else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(theirs_source->our_entry)) + theirs_source->type = GIT_MERGE_DIFF_RENAMED_DELETED; + + else if (theirs_source->type == GIT_MERGE_DIFF_MODIFIED_DELETED) + theirs_source->type = GIT_MERGE_DIFF_RENAMED_MODIFIED; + } +} + +GIT_INLINE(void) merge_diff_coalesce_rename( + git_index_entry *source_entry, + git_delta_t *source_status, + git_index_entry *target_entry, + git_delta_t *target_status) +{ + /* Coalesce the rename target into the rename source. */ + memcpy(source_entry, target_entry, sizeof(git_index_entry)); + *source_status = GIT_DELTA_RENAMED; + + memset(target_entry, 0x0, sizeof(git_index_entry)); + *target_status = GIT_DELTA_UNMODIFIED; +} + +static void merge_diff_list_coalesce_renames( + git_merge_diff_list *diff_list, + struct merge_diff_similarity *similarity_ours, + struct merge_diff_similarity *similarity_theirs, + const git_merge_tree_opts *opts) +{ + size_t i; + bool ours_renamed = 0, theirs_renamed = 0; + size_t ours_source_idx = 0, theirs_source_idx = 0; + git_merge_diff *ours_source, *theirs_source, *target; + + for (i = 0; i < diff_list->conflicts.length; i++) { + target = diff_list->conflicts.contents[i]; + + ours_renamed = 0; + theirs_renamed = 0; + + if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->our_entry) && + similarity_ours[i].similarity >= opts->rename_threshold) { + ours_source_idx = similarity_ours[i].other_idx; + + ours_source = diff_list->conflicts.contents[ours_source_idx]; + + merge_diff_coalesce_rename( + &ours_source->our_entry, + &ours_source->our_status, + &target->our_entry, + &target->our_status); + + similarity_ours[ours_source_idx].similarity = 0; + similarity_ours[i].similarity = 0; + + ours_renamed = 1; + } + + /* insufficient to determine direction */ + if (GIT_MERGE_INDEX_ENTRY_EXISTS(target->their_entry) && + similarity_theirs[i].similarity >= opts->rename_threshold) { + theirs_source_idx = similarity_theirs[i].other_idx; + + theirs_source = diff_list->conflicts.contents[theirs_source_idx]; + + merge_diff_coalesce_rename( + &theirs_source->their_entry, + &theirs_source->their_status, + &target->their_entry, + &target->their_status); + + similarity_theirs[theirs_source_idx].similarity = 0; + similarity_theirs[i].similarity = 0; + + theirs_renamed = 1; + } + + merge_diff_mark_rename_conflict(diff_list, + similarity_ours, ours_renamed, ours_source_idx, + similarity_theirs, theirs_renamed, theirs_source_idx, + target, opts); + } +} + +static int merge_diff_empty(const git_vector *conflicts, size_t idx) +{ + git_merge_diff *conflict = conflicts->contents[idx]; + + return (!GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry) && + !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)); +} + +static void merge_diff_list_count_candidates( + git_merge_diff_list *diff_list, + size_t *src_count, + size_t *tgt_count) +{ + git_merge_diff *entry; + size_t i; + + *src_count = 0; + *tgt_count = 0; + + git_vector_foreach(&diff_list->conflicts, i, entry) { + if (GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry) && + (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->our_entry) || + !GIT_MERGE_INDEX_ENTRY_EXISTS(entry->their_entry))) + src_count++; + else if (!GIT_MERGE_INDEX_ENTRY_EXISTS(entry->ancestor_entry)) + tgt_count++; + } +} + +int git_merge_diff_list__find_renames( + git_repository *repo, + git_merge_diff_list *diff_list, + const git_merge_tree_opts *opts) +{ + struct merge_diff_similarity *similarity_ours, *similarity_theirs; + void **cache = NULL; + size_t cache_size = 0; + size_t src_count, tgt_count, i; + int error = 0; + + assert(diff_list && opts); + + if ((opts->flags & GIT_MERGE_TREE_FIND_RENAMES) == 0) + return 0; + + similarity_ours = git__calloc(diff_list->conflicts.length, + sizeof(struct merge_diff_similarity)); + GITERR_CHECK_ALLOC(similarity_ours); + + similarity_theirs = git__calloc(diff_list->conflicts.length, + sizeof(struct merge_diff_similarity)); + GITERR_CHECK_ALLOC(similarity_theirs); + + /* Calculate similarity between items that were deleted from the ancestor + * and added in the other branch. + */ + if ((error = merge_diff_mark_similarity(repo, diff_list, similarity_ours, + similarity_theirs, index_entry_similarity_exact, NULL, opts)) < 0) + goto done; + + if (diff_list->conflicts.length <= opts->target_limit) { + cache_size = diff_list->conflicts.length * 3; + cache = git__calloc(cache_size, sizeof(void *)); + GITERR_CHECK_ALLOC(cache); + + merge_diff_list_count_candidates(diff_list, &src_count, &tgt_count); + + if (src_count > opts->target_limit || tgt_count > opts->target_limit) { + /* TODO: report! */ + } else { + if ((error = merge_diff_mark_similarity( + repo, diff_list, similarity_ours, similarity_theirs, + index_entry_similarity_inexact, cache, opts)) < 0) + goto done; + } + } + + /* For entries that are appropriately similar, merge the new name's entry + * into the old name. + */ + merge_diff_list_coalesce_renames(diff_list, similarity_ours, similarity_theirs, opts); + + /* And remove any entries that were merged and are now empty. */ + git_vector_remove_matching(&diff_list->conflicts, merge_diff_empty); + +done: + if (cache != NULL) { + for (i = 0; i < cache_size; ++i) { + if (cache[i] != NULL) + opts->metric->free_signature(cache[i], opts->metric->payload); + } + + git__free(cache); + } + + git__free(similarity_ours); + git__free(similarity_theirs); + + return error; +} + /* Directory/file conflict handling */ GIT_INLINE(const char *) merge_diff_path( @@ -951,6 +1386,43 @@ static int merge_tree_normalize_opts( else { git_merge_tree_opts init = GIT_MERGE_TREE_OPTS_INIT; memcpy(opts, &init, sizeof(init)); + + opts->flags = GIT_MERGE_TREE_FIND_RENAMES; + opts->rename_threshold = GIT_MERGE_TREE_RENAME_THRESHOLD; + } + + if (!opts->target_limit) { + int32_t limit = 0; + + opts->target_limit = GIT_MERGE_TREE_TARGET_LIMIT; + + if (git_config_get_int32(&limit, cfg, "merge.renameLimit") < 0) { + giterr_clear(); + + if (git_config_get_int32(&limit, cfg, "diff.renameLimit") < 0) + giterr_clear(); + } + + if (limit > 0) + opts->target_limit = limit; + } + + /* assign the internal metric with whitespace flag as payload */ + if (!opts->metric) { + opts->metric = git__malloc(sizeof(git_diff_similarity_metric)); + GITERR_CHECK_ALLOC(opts->metric); + + opts->metric->file_signature = git_diff_find_similar__hashsig_for_file; + opts->metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; + opts->metric->free_signature = git_diff_find_similar__hashsig_free; + opts->metric->similarity = git_diff_find_similar__calc_similarity; + + if (opts->flags & GIT_DIFF_FIND_IGNORE_WHITESPACE) + opts->metric->payload = (void *)GIT_HASHSIG_IGNORE_WHITESPACE; + else if (opts->flags & GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE) + opts->metric->payload = (void *)GIT_HASHSIG_NORMAL; + else + opts->metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; } return 0; @@ -1035,6 +1507,12 @@ int index_from_diff_list(git_index **out, git_merge_diff_list *diff_list) their_path = GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry) ? conflict->their_entry.path : NULL; + + if ((our_path && strcmp(ancestor_path, our_path) != 0) || + (their_path && strcmp(ancestor_path, their_path) != 0)) { + if ((error = git_index_name_add(index, ancestor_path, our_path, their_path)) < 0) + goto on_error; + } } /* Add each entry in the resolved conflict to the REUC independently, since @@ -1099,7 +1577,8 @@ int git_merge_trees( diff_list = git_merge_diff_list__alloc(repo); GITERR_CHECK_ALLOC(diff_list); - if ((error = git_merge_diff_list__find_differences(diff_list, ancestor_tree, our_tree, their_tree)) < 0) + if ((error = git_merge_diff_list__find_differences(diff_list, ancestor_tree, our_tree, their_tree)) < 0 || + (error = git_merge_diff_list__find_renames(repo, diff_list, &opts)) < 0) goto done; memcpy(&changes, &diff_list->conflicts, sizeof(git_vector)); @@ -1115,6 +1594,9 @@ int git_merge_trees( git_vector_insert(&diff_list->conflicts, conflict); } + if (!given_opts || !given_opts->metric) + git__free(opts.metric); + error = index_from_diff_list(out, diff_list); done: @@ -1134,3 +1616,4 @@ void git_merge_diff_list__free(git_merge_diff_list *diff_list) git_pool_clear(&diff_list->pool); git__free(diff_list); } + diff --git a/tests-clar/index/names.c b/tests-clar/index/names.c new file mode 100644 index 000000000..ffc984249 --- /dev/null +++ b/tests-clar/index/names.c @@ -0,0 +1,83 @@ +#include "clar_libgit2.h" +#include "index.h" +#include "git2/repository.h" +#include "../reset/reset_helpers.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_names__initialize(void) +{ + repo = cl_git_sandbox_init("mergedrepo"); + git_repository_index(&repo_index, repo); +} + +void test_index_names__cleanup(void) +{ + git_index_free(repo_index); + repo_index = NULL; + + cl_git_sandbox_cleanup(); +} + +void test_index_names__add(void) +{ + const git_index_name_entry *conflict_name; + + cl_git_pass(git_index_name_add(repo_index, "ancestor", "ours", "theirs")); + cl_git_pass(git_index_name_add(repo_index, "ancestor2", "ours2", NULL)); + cl_git_pass(git_index_name_add(repo_index, "ancestor3", NULL, "theirs3")); + + cl_assert(git_index_name_entrycount(repo_index) == 3); + + conflict_name = git_index_name_get_byindex(repo_index, 0); + cl_assert(strcmp(conflict_name->ancestor, "ancestor") == 0); + cl_assert(strcmp(conflict_name->ours, "ours") == 0); + cl_assert(strcmp(conflict_name->theirs, "theirs") == 0); + + conflict_name = git_index_name_get_byindex(repo_index, 1); + cl_assert(strcmp(conflict_name->ancestor, "ancestor2") == 0); + cl_assert(strcmp(conflict_name->ours, "ours2") == 0); + cl_assert(conflict_name->theirs == NULL); + + conflict_name = git_index_name_get_byindex(repo_index, 2); + cl_assert(strcmp(conflict_name->ancestor, "ancestor3") == 0); + cl_assert(conflict_name->ours == NULL); + cl_assert(strcmp(conflict_name->theirs, "theirs3") == 0); +} + +void test_index_names__roundtrip(void) +{ + const git_index_name_entry *conflict_name; + + cl_git_pass(git_index_name_add(repo_index, "ancestor", "ours", "theirs")); + cl_git_pass(git_index_name_add(repo_index, "ancestor2", "ours2", NULL)); + cl_git_pass(git_index_name_add(repo_index, "ancestor3", NULL, "theirs3")); + + cl_git_pass(git_index_write(repo_index)); + git_index_clear(repo_index); + cl_assert(git_index_name_entrycount(repo_index) == 0); + + cl_git_pass(git_index_read(repo_index)); + cl_assert(git_index_name_entrycount(repo_index) == 3); + + conflict_name = git_index_name_get_byindex(repo_index, 0); + cl_assert(strcmp(conflict_name->ancestor, "ancestor") == 0); + cl_assert(strcmp(conflict_name->ours, "ours") == 0); + cl_assert(strcmp(conflict_name->theirs, "theirs") == 0); + + conflict_name = git_index_name_get_byindex(repo_index, 1); + cl_assert(strcmp(conflict_name->ancestor, "ancestor2") == 0); + cl_assert(strcmp(conflict_name->ours, "ours2") == 0); + cl_assert(conflict_name->theirs == NULL); + + conflict_name = git_index_name_get_byindex(repo_index, 2); + cl_assert(strcmp(conflict_name->ancestor, "ancestor3") == 0); + cl_assert(conflict_name->ours == NULL); + cl_assert(strcmp(conflict_name->theirs, "theirs3") == 0); + +} diff --git a/tests-clar/merge/merge_helpers.c b/tests-clar/merge/merge_helpers.c index b10e9ec32..7cb1e53da 100644 --- a/tests-clar/merge/merge_helpers.c +++ b/tests-clar/merge/merge_helpers.c @@ -51,10 +51,62 @@ int merge_trees_from_branches( return 0; } +static void dump_index_entries(git_vector *index_entries) +{ + size_t i; + const git_index_entry *index_entry; + + printf ("\nINDEX [%d]:\n", (int)index_entries->length); + for (i = 0; i < index_entries->length; i++) { + index_entry = index_entries->contents[i]; + + printf("%o ", index_entry->mode); + printf("%s ", git_oid_allocfmt(&index_entry->oid)); + printf("%d ", git_index_entry_stage(index_entry)); + printf("%s ", index_entry->path); + printf("\n"); + } + printf("\n"); +} + +static void dump_names(git_index *index) +{ + size_t i; + const git_index_name_entry *conflict_name; + + for (i = 0; i < git_index_name_entrycount(index); i++) { + conflict_name = git_index_name_get_byindex(index, i); + + printf("%s %s %s\n", conflict_name->ancestor, conflict_name->ours, conflict_name->theirs); + } + printf("\n"); +} + +static void dump_reuc(git_index *index) +{ + size_t i; + const git_index_reuc_entry *reuc; + + printf ("\nREUC:\n"); + for (i = 0; i < git_index_reuc_entrycount(index); i++) { + reuc = git_index_reuc_get_byindex(index, i); + + printf("%s ", reuc->path); + printf("%o ", reuc->mode[0]); + printf("%s\n", git_oid_allocfmt(&reuc->oid[0])); + printf(" %o ", reuc->mode[1]); + printf(" %s\n", git_oid_allocfmt(&reuc->oid[1])); + printf(" %o ", reuc->mode[2]); + printf(" %s ", git_oid_allocfmt(&reuc->oid[2])); + printf("\n"); + } + printf("\n"); +} + static int index_entry_eq_merge_index_entry(const struct merge_index_entry *expected, const git_index_entry *actual) { git_oid expected_oid; - bool test_oid; + bool test_oid; if (strlen(expected->oid_str) != 0) { cl_git_pass(git_oid_fromstr(&expected_oid, expected->oid_str)); @@ -84,6 +136,16 @@ static int name_entry_eq(const char *expected, const char *actual) return (strcmp(expected, actual) == 0) ? 1 : 0; } +static int name_entry_eq_merge_name_entry(const struct merge_name_entry *expected, const git_index_name_entry *actual) +{ + if (name_entry_eq(expected->ancestor_path, actual->ancestor) == 0 || + name_entry_eq(expected->our_path, actual->ours) == 0 || + name_entry_eq(expected->their_path, actual->theirs) == 0) + return 0; + + return 1; +} + static int index_conflict_data_eq_merge_diff(const struct merge_index_conflict_data *expected, git_merge_diff *actual) { if (!index_entry_eq_merge_index_entry((const struct merge_index_entry *)&expected->ancestor, &actual->ancestor_entry) || @@ -139,6 +201,29 @@ int merge_test_index(git_index *index, const struct merge_index_entry expected[] return 1; } +int merge_test_names(git_index *index, const struct merge_name_entry expected[], size_t expected_len) +{ + size_t i; + const git_index_name_entry *name_entry; + + /* + dump_names(index); + */ + + if (git_index_name_entrycount(index) != expected_len) + return 0; + + for (i = 0; i < expected_len; i++) { + if ((name_entry = git_index_name_get_byindex(index, i)) == NULL) + return 0; + + if (! name_entry_eq_merge_name_entry(&expected[i], name_entry)) + return 0; + } + + return 1; +} + int merge_test_reuc(git_index *index, const struct merge_reuc_entry expected[], size_t expected_len) { size_t i; diff --git a/tests-clar/merge/trees/renames.c b/tests-clar/merge/trees/renames.c new file mode 100644 index 000000000..dc0564bc4 --- /dev/null +++ b/tests-clar/merge/trees/renames.c @@ -0,0 +1,253 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "buffer.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "fileops.h" + +static git_repository *repo; + +#define TEST_REPO_PATH "merge-resolve" + +#define BRANCH_RENAME_OURS "rename_conflict_ours" +#define BRANCH_RENAME_THEIRS "rename_conflict_theirs" + +// Fixture setup and teardown +void test_merge_trees_renames__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_trees_renames__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_merge_trees_renames__index(void) +{ + git_index *index; + git_merge_tree_opts *opts = NULL; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e", 0, "0a-no-change.txt" }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 1, "0b-rewritten-in-ours.txt" }, + { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 2, "0b-rewritten-in-ours.txt" }, + { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 3, "0b-rewritten-in-ours.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 1, "0c-rewritten-in-theirs.txt" }, + { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 2, "0c-rewritten-in-theirs.txt" }, + { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 3, "0c-rewritten-in-theirs.txt" }, + { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 0, "1a-newname-in-ours-edited-in-theirs.txt" }, + { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt" }, + { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 0, "1b-newname-in-theirs-edited-in-ours.txt" }, + { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt" }, + { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, + { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 2, "3a-newname-in-ours-deleted-in-theirs.txt" }, + { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 1, "3a-renamed-in-ours-deleted-in-theirs.txt" }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 3, "3b-newname-in-theirs-deleted-in-ours.txt" }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 1, "3b-renamed-in-theirs-deleted-in-ours.txt" }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 2, "4a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 3, "4a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 1, "4a-renamed-in-ours-added-in-theirs.txt" }, + { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 2, "4b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 3, "4b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 1, "4b-renamed-in-theirs-added-in-ours.txt" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 2, "5a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "98ba4205fcf31f5dd93c916d35fe3f3b3d0e6714", 3, "5a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 1, "5a-renamed-in-ours-added-in-theirs.txt" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 3, "5a-renamed-in-ours-added-in-theirs.txt" }, + { 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced", 2, "5b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 3, "5b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 1, "5b-renamed-in-theirs-added-in-ours.txt" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 2, "5b-renamed-in-theirs-added-in-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 2, "6-both-renamed-1-to-2-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 3, "6-both-renamed-1-to-2-theirs.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 1, "6-both-renamed-1-to-2.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 1, "7-both-renamed-side-1.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 3, "7-both-renamed-side-1.txt" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 1, "7-both-renamed-side-2.txt" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 2, "7-both-renamed-side-2.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 2, "7-both-renamed.txt" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" }, + }; + + struct merge_name_entry merge_name_entries[] = { + { + "3a-renamed-in-ours-deleted-in-theirs.txt", + "3a-newname-in-ours-deleted-in-theirs.txt", + "" + }, + + { + "3b-renamed-in-theirs-deleted-in-ours.txt", + "", + "3b-newname-in-theirs-deleted-in-ours.txt", + }, + + { + "4a-renamed-in-ours-added-in-theirs.txt", + "4a-newname-in-ours-added-in-theirs.txt", + "", + }, + + { + "4b-renamed-in-theirs-added-in-ours.txt", + "", + "4b-newname-in-theirs-added-in-ours.txt", + }, + + { + "5a-renamed-in-ours-added-in-theirs.txt", + "5a-newname-in-ours-added-in-theirs.txt", + "5a-renamed-in-ours-added-in-theirs.txt", + }, + + { + "5b-renamed-in-theirs-added-in-ours.txt", + "5b-renamed-in-theirs-added-in-ours.txt", + "5b-newname-in-theirs-added-in-ours.txt", + }, + + { + "6-both-renamed-1-to-2.txt", + "6-both-renamed-1-to-2-ours.txt", + "6-both-renamed-1-to-2-theirs.txt", + }, + + { + "7-both-renamed-side-1.txt", + "7-both-renamed.txt", + "7-both-renamed-side-1.txt", + }, + + { + "7-both-renamed-side-2.txt", + "7-both-renamed-side-2.txt", + "7-both-renamed.txt", + }, + }; + + struct merge_reuc_entry merge_reuc_entries[] = { + { "1a-newname-in-ours-edited-in-theirs.txt", + 0, 0100644, 0, + "", + "c3d02eeef75183df7584d8d13ac03053910c1301", + "" }, + + { "1a-newname-in-ours.txt", + 0, 0100644, 0, + "", + "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", + "" }, + + { "1a-renamed-in-ours-edited-in-theirs.txt", + 0100644, 0, 0100644, + "c3d02eeef75183df7584d8d13ac03053910c1301", + "", + "0d872f8e871a30208305978ecbf9e66d864f1638" }, + + { "1a-renamed-in-ours.txt", + 0100644, 0, 0100644, + "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", + "", + "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb" }, + + { "1b-newname-in-theirs-edited-in-ours.txt", + 0, 0, 0100644, + "", + "", + "241a1005cd9b980732741b74385b891142bcba28" }, + + { "1b-newname-in-theirs.txt", + 0, 0, 0100644, + "", + "", + "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136" }, + + { "1b-renamed-in-theirs-edited-in-ours.txt", + 0100644, 0100644, 0, + "241a1005cd9b980732741b74385b891142bcba28", + "ed9523e62e453e50dd9be1606af19399b96e397a", + "" }, + + { "1b-renamed-in-theirs.txt", + 0100644, 0100644, 0, + "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", + "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", + "" }, + + { "2-newname-in-both.txt", + 0, 0100644, 0100644, + "", + "178940b450f238a56c0d75b7955cb57b38191982", + "178940b450f238a56c0d75b7955cb57b38191982" }, + + { "2-renamed-in-both.txt", + 0100644, 0, 0, + "178940b450f238a56c0d75b7955cb57b38191982", + "", + "" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, + BRANCH_RENAME_OURS, BRANCH_RENAME_THEIRS, + opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 41)); + cl_assert(merge_test_names(index, merge_name_entries, 9)); + cl_assert(merge_test_reuc(index, merge_reuc_entries, 10)); + + git_index_free(index); +} + +void test_merge_trees_renames__no_rename_index(void) +{ + git_index *index; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e", 0, "0a-no-change.txt" }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 1, "0b-rewritten-in-ours.txt" }, + { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 2, "0b-rewritten-in-ours.txt" }, + { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 3, "0b-rewritten-in-ours.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 1, "0c-rewritten-in-theirs.txt" }, + { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 2, "0c-rewritten-in-theirs.txt" }, + { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 3, "0c-rewritten-in-theirs.txt" }, + { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-newname-in-ours-edited-in-theirs.txt" }, + { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt" }, + { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 1, "1a-renamed-in-ours-edited-in-theirs.txt" }, + { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 3, "1a-renamed-in-ours-edited-in-theirs.txt" }, + { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-newname-in-theirs-edited-in-ours.txt" }, + { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt" }, + { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 1, "1b-renamed-in-theirs-edited-in-ours.txt" }, + { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 2, "1b-renamed-in-theirs-edited-in-ours.txt" }, + { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, + { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-newname-in-ours-deleted-in-theirs.txt" }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt" }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 2, "4a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 3, "4a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 2, "4b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 3, "4b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 2, "5a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "98ba4205fcf31f5dd93c916d35fe3f3b3d0e6714", 3, "5a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced", 2, "5b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 3, "5b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-theirs.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 2, "7-both-renamed.txt" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 3, "7-both-renamed.txt" }, + }; + + cl_git_pass(merge_trees_from_branches(&index, repo, + BRANCH_RENAME_OURS, BRANCH_RENAME_THEIRS, + &opts)); + + cl_assert(merge_test_index(index, merge_index_entries, 32)); + + git_index_free(index); +} + diff --git a/tests-clar/merge/trees/treediff.c b/tests-clar/merge/trees/treediff.c index b2554f8be..afd8ac3ca 100644 --- a/tests-clar/merge/trees/treediff.c +++ b/tests-clar/merge/trees/treediff.c @@ -12,11 +12,17 @@ static git_repository *repo; #define TREE_OID_ANCESTOR "0d52e3a556e189ba0948ae56780918011c1b167d" #define TREE_OID_MASTER "1f81433e3161efbf250576c58fede7f6b836f3d3" #define TREE_OID_BRANCH "eea9286df54245fea72c5b557291470eb825f38f" +#define TREE_OID_RENAMES1 "f5f9dd5886a6ee20272be0aafc790cba43b31931" +#define TREE_OID_RENAMES2 "5fbfbdc04b4eca46f54f4853a3c5a1dce28f5165" #define TREE_OID_DF_ANCESTOR "b8a3a806d3950e8c0a03a34f234a92eff0e2c68d" #define TREE_OID_DF_SIDE1 "ee1d6f164893c1866a323f072eeed36b855656be" #define TREE_OID_DF_SIDE2 "6178885b38fe96e825ac0f492c0a941f288b37f6" +#define TREE_OID_RENAME_CONFLICT_ANCESTOR "476dbb3e207313d1d8aaa120c6ad204bf1295e53" +#define TREE_OID_RENAME_CONFLICT_OURS "c4efe31e9decccc8b2b4d3df9aac2cdfe2995618" +#define TREE_OID_RENAME_CONFLICT_THEIRS "9e7f4359c469f309b6057febf4c6e80742cbed5b" + void test_merge_trees_treediff__initialize(void) { repo = cl_git_sandbox_init(TEST_REPO_PATH); @@ -46,6 +52,20 @@ static void test_find_differences( git_tree *ancestor_tree, *ours_tree, *theirs_tree; struct treediff_cb_data treediff_cb_data = {0}; + git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; + opts.flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.target_limit = 1000; + opts.rename_threshold = 50; + + opts.metric = git__malloc(sizeof(git_diff_similarity_metric)); + cl_assert(opts.metric != NULL); + + opts.metric->file_signature = git_diff_find_similar__hashsig_for_file; + opts.metric->buffer_signature = git_diff_find_similar__hashsig_for_buf; + opts.metric->free_signature = git_diff_find_similar__hashsig_free; + opts.metric->similarity = git_diff_find_similar__calc_similarity; + opts.metric->payload = (void *)GIT_HASHSIG_SMART_WHITESPACE; + cl_git_pass(git_oid_fromstr(&ancestor_oid, ancestor_oidstr)); cl_git_pass(git_oid_fromstr(&ours_oid, ours_oidstr)); cl_git_pass(git_oid_fromstr(&theirs_oid, theirs_oidstr)); @@ -55,6 +75,7 @@ static void test_find_differences( cl_git_pass(git_tree_lookup(&theirs_tree, repo, &theirs_oid)); cl_git_pass(git_merge_diff_list__find_differences(merge_diff_list, ancestor_tree, ours_tree, theirs_tree)); + cl_git_pass(git_merge_diff_list__find_renames(repo, merge_diff_list, &opts)); /* dump_merge_index(merge_index); @@ -72,6 +93,8 @@ static void test_find_differences( git_tree_free(theirs_tree); git_merge_diff_list__free(merge_diff_list); + + git__free(opts.metric); } void test_merge_trees_treediff__simple(void) @@ -277,3 +300,255 @@ void test_merge_trees_treediff__df_conflicts(void) test_find_differences(TREE_OID_DF_ANCESTOR, TREE_OID_DF_SIDE1, TREE_OID_DF_SIDE2, treediff_conflict_data, 20); } +void test_merge_trees_treediff__strict_renames(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt", GIT_DELTA_ADDED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt", GIT_DELTA_MODIFIED }, + { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt", GIT_DELTA_MODIFIED }, + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt", GIT_DELTA_MODIFIED }, + { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "renamed-in-branch.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "renamed.txt", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "copied.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_NONE, + }, + }; + + test_find_differences(TREE_OID_ANCESTOR, TREE_OID_MASTER, TREE_OID_RENAMES1, treediff_conflict_data, 8); +} + +void test_merge_trees_treediff__rename_conflicts(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt", GIT_DELTA_ADDED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-rewritten-in-ours.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 0, "0b-rewritten-in-ours.txt", GIT_DELTA_MODIFIED }, + { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 0, "0b-rewritten-in-ours.txt", GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_BOTH_MODIFIED, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-rewritten-in-theirs.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 0, "0c-rewritten-in-theirs.txt", GIT_DELTA_MODIFIED }, + { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 0, "0c-rewritten-in-theirs.txt", GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_BOTH_MODIFIED, + }, + + { + { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-renamed-in-ours-edited-in-theirs.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-newname-in-ours-edited-in-theirs.txt", GIT_DELTA_RENAMED }, + { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 0, "1a-renamed-in-ours-edited-in-theirs.txt", GIT_DELTA_MODIFIED }, + GIT_MERGE_DIFF_RENAMED_MODIFIED, + }, + + { + { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt", GIT_DELTA_RENAMED }, + { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-renamed-in-theirs-edited-in-ours.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 0, "1b-renamed-in-theirs-edited-in-ours.txt", GIT_DELTA_MODIFIED }, + { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-newname-in-theirs-edited-in-ours.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_RENAMED_MODIFIED, + }, + + { + { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-renamed-in-both.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt", GIT_DELTA_RENAMED }, + { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_BOTH_RENAMED, + }, + + { + { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-renamed-in-ours-deleted-in-theirs.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-newname-in-ours-deleted-in-theirs.txt", GIT_DELTA_RENAMED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_RENAMED_DELETED, + }, + + { + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-renamed-in-theirs-deleted-in-ours.txt", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_RENAMED_DELETED, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 0, "4a-newname-in-ours-added-in-theirs.txt", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_RENAMED_ADDED, + }, + + { + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-renamed-in-ours-added-in-theirs.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-newname-in-ours-added-in-theirs.txt", GIT_DELTA_RENAMED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + GIT_MERGE_DIFF_RENAMED_ADDED, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 0, "4b-newname-in-theirs-added-in-ours.txt", GIT_DELTA_ADDED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_RENAMED_ADDED, + }, + + { + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-renamed-in-theirs-added-in-ours.txt", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-newname-in-theirs-added-in-ours.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_RENAMED_ADDED, + }, + + { + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-ours.txt", GIT_DELTA_RENAMED }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-theirs.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2, + }, + + { + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed.txt", GIT_DELTA_RENAMED }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1, + }, + + { + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1, + }, + }; + + test_find_differences(TREE_OID_RENAME_CONFLICT_ANCESTOR, + TREE_OID_RENAME_CONFLICT_OURS, TREE_OID_RENAME_CONFLICT_THEIRS, treediff_conflict_data, 18); +} + +void test_merge_trees_treediff__best_renames(void) +{ + struct merge_index_conflict_data treediff_conflict_data[] = { + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt", GIT_DELTA_ADDED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt", GIT_DELTA_MODIFIED }, + { 0100644, "45299c1ca5e07bba1fd90843056fb559f96b1f5a", 0, "renamed-90.txt", GIT_DELTA_RENAMED }, + GIT_MERGE_DIFF_RENAMED_MODIFIED, + }, + + { + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt", GIT_DELTA_MODIFIED }, + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt", GIT_DELTA_MODIFIED }, + { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt",GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_DELETED }, + { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, + GIT_MERGE_DIFF_MODIFIED_DELETED, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "5843febcb23480df0b5edb22a21c59c772bb8e29", 0, "renamed-50.txt", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + + { + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { 0100644, "a77a56a49f8f3ae242e02717f18ebbc60c5cc543", 0, "renamed-75.txt", GIT_DELTA_ADDED }, + GIT_MERGE_DIFF_NONE, + }, + }; + + test_find_differences(TREE_OID_ANCESTOR, TREE_OID_MASTER, TREE_OID_RENAMES2, treediff_conflict_data, 7); +} From 75d1c8c664eba0ddef802b1bf6d1327707014c6e Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 30 Apr 2013 17:33:11 -0500 Subject: [PATCH 116/134] move NAME and REUC extensions to sys/ --- include/git2/index.h | 156 --------------------------- include/git2/sys/index.h | 180 +++++++++++++++++++++++++++++++ src/index.c | 1 + src/merge.c | 1 + tests-clar/index/names.c | 1 + tests-clar/index/reuc.c | 1 + tests-clar/merge/merge_helpers.c | 1 + tests-clar/merge/trees/trivial.c | 1 + 8 files changed, 186 insertions(+), 156 deletions(-) create mode 100644 include/git2/sys/index.h diff --git a/include/git2/index.h b/include/git2/index.h index 01e3d2c29..d23c3a8ea 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -84,19 +84,6 @@ typedef struct git_index_entry { char *path; } git_index_entry; -typedef struct git_index_name_entry { - char *ancestor; - char *ours; - char *theirs; -} git_index_name_entry; - -/** 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_reuc_entry; - /** Capabilities of system that affect index actions. */ enum { GIT_INDEXCAP_IGNORE_CASE = 1, @@ -484,149 +471,6 @@ GIT_EXTERN(int) git_index_has_conflicts(const git_index *index); /**@}*/ -/** @name Conflict Name entry functions - * - * These functions work on rename conflict entries. - */ -/**@{*/ - -/** - * Get the count of filename conflict entries currently in the index. - * - * @param index an existing index object - * @return integer of count of current filename conflict entries - */ -GIT_EXTERN(unsigned int) git_index_name_entrycount(git_index *index); - -/** - * Get a filename conflict entry from the index. - * - * The returned entry is read-only and should not be modified - * or freed by the caller. - * - * @param index an existing index object - * @param n the position of the entry - * @return a pointer to the filename conflict entry; NULL if out of bounds - */ -GIT_EXTERN(const git_index_name_entry *) git_index_name_get_byindex( - git_index *index, size_t n); - -/** - * Record the filenames involved in a rename conflict. - * - * @param index an existing index object - * @param ancestor the path of the file as it existed in the ancestor - * @param ours the path of the file as it existed in our tree - * @param theirs the path of the file as it existed in their tree - */ -GIT_EXTERN(int) git_index_name_add(git_index *index, - const char *ancestor, const char *ours, const char *theirs); - -/** - * Remove all filename conflict entries. - * - * @param index an existing index object - * @return 0 or an error code - */ -GIT_EXTERN(void) git_index_name_clear(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 resolve undo entries currently in the index. - * - * @param index an existing index object - * @return integer of count of current resolve undo entries - */ -GIT_EXTERN(unsigned int) git_index_reuc_entrycount(git_index *index); - -/** - * Finds the resolve undo entry that points to the given path in the Git - * index. - * - * @param at_pos the address to which the position of the reuc entry is written (optional) - * @param index an existing index object - * @param path path to search - * @return 0 if found, < 0 otherwise (GIT_ENOTFOUND) - */ -GIT_EXTERN(int) git_index_reuc_find(size_t *at_pos, git_index *index, const char *path); - -/** - * Get a resolve undo entry from the index. - * - * The returned entry is read-only and should not be modified - * or freed by the caller. - * - * @param index an existing index object - * @param path path to search - * @return the resolve undo entry; NULL if not found - */ -GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_bypath(git_index *index, const char *path); - -/** - * Get a resolve undo entry from the index. - * - * The returned entry is read-only and should not be modified - * or freed by the caller. - * - * @param index an existing index object - * @param n the position of the entry - * @return a pointer to the resolve undo entry; NULL if out of bounds - */ -GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_byindex(git_index *index, size_t n); - -/** - * Adds a resolve undo entry for a file based on the given parameters. - * - * 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. - * - * If there exists a resolve undo entry for the given path in the index, - * it will be removed. - * - * This method will fail in bare index instances. - * - * @param index an existing index object - * @param path filename to add - * @param ancestor_mode mode of the ancestor file - * @param ancestor_id oid of the ancestor file - * @param our_mode mode of our file - * @param our_id oid of our file - * @param their_mode mode of their file - * @param their_id oid of their file - * @return 0 or an error code - */ -GIT_EXTERN(int) git_index_reuc_add(git_index *index, const char *path, - int ancestor_mode, const git_oid *ancestor_id, - int our_mode, const git_oid *our_id, - int their_mode, const git_oid *their_id); - -/** - * Remove an resolve undo entry from the index - * - * @param index an existing index object - * @param n position of the resolve undo entry to remove - * @return 0 or an error code - */ -GIT_EXTERN(int) git_index_reuc_remove(git_index *index, size_t n); - -/** - * Remove all resolve undo entries from the index - * - * @param index an existing index object - * @return 0 or an error code - */ -GIT_EXTERN(void) git_index_reuc_clear(git_index *index); - -/**@}*/ - /** @} */ GIT_END_DECL #endif diff --git a/include/git2/sys/index.h b/include/git2/sys/index.h new file mode 100644 index 000000000..f74637f84 --- /dev/null +++ b/include/git2/sys/index.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_sys_git_index_h__ +#define INCLUDE_sys_git_index_h__ + +/** + * @file git2/sys/index.h + * @brief Low-level Git index manipulation routines + * @defgroup git_backend Git custom backend APIs + * @ingroup Git + * @{ + */ +GIT_BEGIN_DECL + +/** Representation of a rename conflict entry in the index. */ +typedef struct git_index_name_entry { + char *ancestor; + char *ours; + char *theirs; +} git_index_name_entry; + +/** 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_reuc_entry; + +/** @name Conflict Name entry functions + * + * These functions work on rename conflict entries. + */ +/**@{*/ + +/** + * Get the count of filename conflict entries currently in the index. + * + * @param index an existing index object + * @return integer of count of current filename conflict entries + */ +GIT_EXTERN(unsigned int) git_index_name_entrycount(git_index *index); + +/** + * Get a filename conflict entry from the index. + * + * The returned entry is read-only and should not be modified + * or freed by the caller. + * + * @param index an existing index object + * @param n the position of the entry + * @return a pointer to the filename conflict entry; NULL if out of bounds + */ +GIT_EXTERN(const git_index_name_entry *) git_index_name_get_byindex( + git_index *index, size_t n); + +/** + * Record the filenames involved in a rename conflict. + * + * @param index an existing index object + * @param ancestor the path of the file as it existed in the ancestor + * @param ours the path of the file as it existed in our tree + * @param theirs the path of the file as it existed in their tree + */ +GIT_EXTERN(int) git_index_name_add(git_index *index, + const char *ancestor, const char *ours, const char *theirs); + +/** + * Remove all filename conflict entries. + * + * @param index an existing index object + * @return 0 or an error code + */ +GIT_EXTERN(void) git_index_name_clear(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 resolve undo entries currently in the index. + * + * @param index an existing index object + * @return integer of count of current resolve undo entries + */ +GIT_EXTERN(unsigned int) git_index_reuc_entrycount(git_index *index); + +/** + * Finds the resolve undo entry that points to the given path in the Git + * index. + * + * @param at_pos the address to which the position of the reuc entry is written (optional) + * @param index an existing index object + * @param path path to search + * @return 0 if found, < 0 otherwise (GIT_ENOTFOUND) + */ +GIT_EXTERN(int) git_index_reuc_find(size_t *at_pos, git_index *index, const char *path); + +/** + * Get a resolve undo entry from the index. + * + * The returned entry is read-only and should not be modified + * or freed by the caller. + * + * @param index an existing index object + * @param path path to search + * @return the resolve undo entry; NULL if not found + */ +GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_bypath(git_index *index, const char *path); + +/** + * Get a resolve undo entry from the index. + * + * The returned entry is read-only and should not be modified + * or freed by the caller. + * + * @param index an existing index object + * @param n the position of the entry + * @return a pointer to the resolve undo entry; NULL if out of bounds + */ +GIT_EXTERN(const git_index_reuc_entry *) git_index_reuc_get_byindex(git_index *index, size_t n); + +/** + * Adds a resolve undo entry for a file based on the given parameters. + * + * 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. + * + * If there exists a resolve undo entry for the given path in the index, + * it will be removed. + * + * This method will fail in bare index instances. + * + * @param index an existing index object + * @param path filename to add + * @param ancestor_mode mode of the ancestor file + * @param ancestor_id oid of the ancestor file + * @param our_mode mode of our file + * @param our_id oid of our file + * @param their_mode mode of their file + * @param their_id oid of their file + * @return 0 or an error code + */ +GIT_EXTERN(int) git_index_reuc_add(git_index *index, const char *path, + int ancestor_mode, const git_oid *ancestor_id, + int our_mode, const git_oid *our_id, + int their_mode, const git_oid *their_id); + +/** + * Remove an resolve undo entry from the index + * + * @param index an existing index object + * @param n position of the resolve undo entry to remove + * @return 0 or an error code + */ +GIT_EXTERN(int) git_index_reuc_remove(git_index *index, size_t n); + +/** + * Remove all resolve undo entries from the index + * + * @param index an existing index object + * @return 0 or an error code + */ +GIT_EXTERN(void) git_index_reuc_clear(git_index *index); + +/**@}*/ + +/** @} */ +GIT_END_DECL +#endif + diff --git a/src/index.c b/src/index.c index 656fb5bc5..a935c00db 100644 --- a/src/index.c +++ b/src/index.c @@ -19,6 +19,7 @@ #include "git2/oid.h" #include "git2/blob.h" #include "git2/config.h" +#include "git2/sys/index.h" #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7) #define short_entry_size(len) entry_size(struct entry_short, len) diff --git a/src/merge.c b/src/merge.c index 681f302f4..3595eb058 100644 --- a/src/merge.c +++ b/src/merge.c @@ -36,6 +36,7 @@ #include "git2/signature.h" #include "git2/config.h" #include "git2/tree.h" +#include "git2/sys/index.h" #define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) diff --git a/tests-clar/index/names.c b/tests-clar/index/names.c index ffc984249..68615531a 100644 --- a/tests-clar/index/names.c +++ b/tests-clar/index/names.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include "index.h" +#include "git2/sys/index.h" #include "git2/repository.h" #include "../reset/reset_helpers.h" diff --git a/tests-clar/index/reuc.c b/tests-clar/index/reuc.c index 4d5955a01..0e38a92f3 100644 --- a/tests-clar/index/reuc.c +++ b/tests-clar/index/reuc.c @@ -1,5 +1,6 @@ #include "clar_libgit2.h" #include "index.h" +#include "git2/sys/index.h" #include "git2/repository.h" #include "../reset/reset_helpers.h" diff --git a/tests-clar/merge/merge_helpers.c b/tests-clar/merge/merge_helpers.c index 7cb1e53da..b2c70bea7 100644 --- a/tests-clar/merge/merge_helpers.c +++ b/tests-clar/merge/merge_helpers.c @@ -5,6 +5,7 @@ #include "merge_helpers.h" #include "merge.h" #include "git2/merge.h" +#include "git2/sys/index.h" int merge_trees_from_branches( git_index **index, git_repository *repo, diff --git a/tests-clar/merge/trees/trivial.c b/tests-clar/merge/trees/trivial.c index 54b07e74a..7d8d2cbf5 100644 --- a/tests-clar/merge/trees/trivial.c +++ b/tests-clar/merge/trees/trivial.c @@ -5,6 +5,7 @@ #include "../merge_helpers.h" #include "refs.h" #include "fileops.h" +#include "git2/sys/index.h" static git_repository *repo; From 2ba55c1f0df3400c15dbdd7b21d1f3d354ab2e3c Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 1 May 2013 15:20:08 +0200 Subject: [PATCH 117/134] refdb: Proper namespace root --- src/refdb_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 5228cb811..6f2162e77 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -1011,7 +1011,7 @@ int git_refdb_backend_fs( git_buf_puts(&path, repository->path_repository); if (repository->namespace != NULL) - git_buf_printf(&path, "refs/%s/", repository->namespace); + git_buf_printf(&path, "refs/namespaces/%s/", repository->namespace); backend->path = git_buf_detach(&path); From e1807113c43b7c5008e2d5c8c449ae56c8dceeb4 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 1 May 2013 15:31:23 +0200 Subject: [PATCH 118/134] merge: Warning noise --- src/checkout.c | 1 + src/index.c | 3 +++ src/merge.c | 2 +- tests-clar/merge/merge_helpers.c | 6 +++--- tests-clar/merge/trees/treediff.c | 11 ----------- 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/checkout.c b/src/checkout.c index 96e15093c..defc21d2d 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -16,6 +16,7 @@ #include "git2/config.h" #include "git2/diff.h" #include "git2/submodule.h" +#include "git2/sys/index.h" #include "refs.h" #include "repository.h" diff --git a/src/index.c b/src/index.c index a935c00db..1771f2957 100644 --- a/src/index.c +++ b/src/index.c @@ -209,6 +209,9 @@ static int conflict_name_cmp(const void *a, const void *b) return strcmp(name_a->ours, name_b->ours); } +/** + * TODO: enable this when resolving case insensitive conflicts + */ static int conflict_name_icmp(const void *a, const void *b) { const git_index_name_entry *name_a = a; diff --git a/src/merge.c b/src/merge.c index 3595eb058..320be005a 100644 --- a/src/merge.c +++ b/src/merge.c @@ -1269,7 +1269,7 @@ int git_merge_diff_list__find_differences( const git_tree *their_tree) { git_iterator *iterators[3] = {0}; - git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3]; + const git_index_entry *items[3] = {0}, *best_cur_item, *cur_items[3]; git_vector_cmp entry_compare = git_index_entry__cmp; struct merge_diff_df_data df_data = {0}; int cur_item_modified; diff --git a/tests-clar/merge/merge_helpers.c b/tests-clar/merge/merge_helpers.c index b2c70bea7..5c3421e7e 100644 --- a/tests-clar/merge/merge_helpers.c +++ b/tests-clar/merge/merge_helpers.c @@ -52,7 +52,7 @@ int merge_trees_from_branches( return 0; } -static void dump_index_entries(git_vector *index_entries) +void merge__dump_index_entries(git_vector *index_entries) { size_t i; const git_index_entry *index_entry; @@ -70,7 +70,7 @@ static void dump_index_entries(git_vector *index_entries) printf("\n"); } -static void dump_names(git_index *index) +void merge__dump_names(git_index *index) { size_t i; const git_index_name_entry *conflict_name; @@ -83,7 +83,7 @@ static void dump_names(git_index *index) printf("\n"); } -static void dump_reuc(git_index *index) +void merge__dump_reuc(git_index *index) { size_t i; const git_index_reuc_entry *reuc; diff --git a/tests-clar/merge/trees/treediff.c b/tests-clar/merge/trees/treediff.c index afd8ac3ca..5da6f7658 100644 --- a/tests-clar/merge/trees/treediff.c +++ b/tests-clar/merge/trees/treediff.c @@ -33,13 +33,6 @@ void test_merge_trees_treediff__cleanup(void) cl_git_sandbox_cleanup(); } -struct treediff_cb_data { - struct merge_index_conflict_data *conflict_data; - size_t conflict_data_len; - - size_t idx; -}; - static void test_find_differences( const char *ancestor_oidstr, const char *ours_oidstr, @@ -50,7 +43,6 @@ static void test_find_differences( git_merge_diff_list *merge_diff_list = git_merge_diff_list__alloc(repo); git_oid ancestor_oid, ours_oid, theirs_oid; git_tree *ancestor_tree, *ours_tree, *theirs_tree; - struct treediff_cb_data treediff_cb_data = {0}; git_merge_tree_opts opts = GIT_MERGE_TREE_OPTS_INIT; opts.flags |= GIT_MERGE_TREE_FIND_RENAMES; @@ -82,9 +74,6 @@ static void test_find_differences( */ cl_assert(treediff_conflict_data_len == merge_diff_list->conflicts.length); - - treediff_cb_data.conflict_data = treediff_conflict_data; - treediff_cb_data.conflict_data_len = treediff_conflict_data_len; cl_assert(merge_test_merge_conflicts(&merge_diff_list->conflicts, treediff_conflict_data, treediff_conflict_data_len)); From 0cc7d8df19c82a13fd9d7c48563f40580d366cd3 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 1 May 2013 09:50:40 -0500 Subject: [PATCH 119/134] allow empty dirs to exist when doing checkout --- src/checkout.c | 8 ++++++-- tests-clar/checkout/tree.c | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/checkout.c b/src/checkout.c index defc21d2d..21f32d89a 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -467,6 +467,7 @@ static int checkout_action( int cmp = -1, act; int (*strcomp)(const char *, const char *) = data->diff->strcomp; int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp; + int error; /* move workdir iterator to follow along with deltas */ @@ -490,8 +491,11 @@ static int checkout_action( if (cmp == 0) { if (wd->mode == GIT_FILEMODE_TREE) { /* case 2 - entry prefixed by workdir tree */ - if (git_iterator_advance_into(&wd, workdir) < 0) - goto fail; + if ((error = git_iterator_advance_into(&wd, workdir)) < 0) { + if (error != GIT_ENOTFOUND || + git_iterator_advance(&wd, workdir) < 0) + goto fail; + } *wditem_ptr = wd; continue; diff --git a/tests-clar/checkout/tree.c b/tests-clar/checkout/tree.c index 0748b22e0..eb129f34e 100644 --- a/tests-clar/checkout/tree.c +++ b/tests-clar/checkout/tree.c @@ -501,3 +501,28 @@ void test_checkout_tree__issue_1397(void) git_object_free(tree); } + +void test_checkout_tree__can_write_to_empty_dirs(void) +{ + git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + git_oid oid; + git_object *obj = NULL; + + assert_on_branch(g_repo, "master"); + + cl_git_pass(p_mkdir("testrepo/a", 0777)); + + /* do first checkout with FORCE because we don't know if testrepo + * base data is clean for a checkout or not + */ + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + + cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); + + cl_assert(git_path_isfile("testrepo/a/b.txt")); + + git_object_free(obj); +} From 8cddf9b83a542bd66fcf0c4a1b692d47ff6556c2 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 1 May 2013 18:21:10 +0200 Subject: [PATCH 120/134] refdb: Properly load namespaces --- src/refdb_fs.c | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 6f2162e77..85444b692 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -997,6 +997,43 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend) git__free(backend); } +static int setup_namespace(git_buf *path, git_repository *repo) +{ + char *parts, *start, *end; + + /* Load the path to the repo first */ + git_buf_puts(path, repo->path_repository); + + /* if the repo is not namespaced, nothing else to do */ + if (repo->namespace == NULL) + return 0; + + parts = end = git__strdup(repo->namespace); + if (parts == NULL) + return -1; + + /** + * From `man gitnamespaces`: + * namespaces which include a / will expand to a hierarchy + * of namespaces; for example, GIT_NAMESPACE=foo/bar will store + * refs under refs/namespaces/foo/refs/namespaces/bar/ + */ + while ((start = git__strsep(&end, "/")) != NULL) { + git_buf_printf(path, "refs/namespaces/%s/", start); + } + + git_buf_printf(path, "refs/namespaces/%s/refs", end); + free(parts); + + /* Make sure that the folder with the namespace exists */ + if (git_futils_mkdir_r(git_buf_cstr(path), repo->path_repository, 0777) < 0) + return -1; + + /* Return the root of the namespaced path, i.e. without the trailing '/refs' */ + git_buf_rtruncate_at_char(path, '/'); + return 0; +} + int git_refdb_backend_fs( git_refdb_backend **backend_out, git_repository *repository) @@ -1009,9 +1046,10 @@ int git_refdb_backend_fs( backend->repo = repository; - git_buf_puts(&path, repository->path_repository); - if (repository->namespace != NULL) - git_buf_printf(&path, "refs/namespaces/%s/", repository->namespace); + if (setup_namespace(&path, repository) < 0) { + git__free(backend); + return -1; + } backend->path = git_buf_detach(&path); From 9d2f841a5d39fc25ce722a3904f6ebc9aa112222 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 2 May 2013 03:03:54 -0700 Subject: [PATCH 121/134] Add extra locking around packfile open We were still seeing a few issues in threaded access to packs. This adds extra locks around the opening of the mwindow to avoid a different race. --- src/pack.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/pack.c b/src/pack.c index f8b621ef8..47534f195 100644 --- a/src/pack.c +++ b/src/pack.c @@ -205,13 +205,18 @@ static int pack_index_check(const char *path, struct git_pack_file *p) if (fd < 0) return fd; - if (p_fstat(fd, &st) < 0 || - !S_ISREG(st.st_mode) || + if (p_fstat(fd, &st) < 0) { + p_close(fd); + giterr_set(GITERR_OS, "Unable to stat pack index '%s'", path); + return -1; + } + + if (!S_ISREG(st.st_mode) || !git__is_sizet(st.st_size) || (idx_size = (size_t)st.st_size) < 4 * 256 + 20 + 20) { p_close(fd); - giterr_set(GITERR_OS, "Failed to check pack index."); + giterr_set(GITERR_ODB, "Invalid pack index '%s'", path); return -1; } @@ -402,7 +407,7 @@ int git_packfile_unpack_header( if (base == NULL) return GIT_EBUFS; - ret = packfile_unpack_header1(&used, size_p, type_p, base, left); + ret = packfile_unpack_header1(&used, size_p, type_p, base, left); git_mwindow_close(w_curs); if (ret == GIT_EBUFS) return ret; @@ -799,9 +804,6 @@ void git_packfile_free(struct git_pack_file *p) if (!p) return; - if (git_mutex_lock(&p->lock) < 0) - return; - cache_free(&p->bases); git_mwindow_free_all(&p->mwf); @@ -813,8 +815,6 @@ void git_packfile_free(struct git_pack_file *p) git__free(p->bad_object_sha1); - git_mutex_unlock(&p->lock); - git_mutex_free(&p->lock); git__free(p); } @@ -829,12 +829,19 @@ static int packfile_open(struct git_pack_file *p) if (!p->index_map.data && pack_index_open(p) < 0) return git_odb__error_notfound("failed to open packfile", NULL); + /* if mwf opened by another thread, return now */ + if (git_mutex_lock(&p->lock) < 0) + return packfile_error("failed to get lock for open"); + + if (p->mwf.fd >= 0) { + git_mutex_unlock(&p->lock); + return 0; + } + /* TODO: open with noatime */ p->mwf.fd = git_futils_open_ro(p->pack_name); - if (p->mwf.fd < 0) { - p->mwf.fd = -1; - return -1; - } + if (p->mwf.fd < 0) + goto cleanup; if (p_fstat(p->mwf.fd, &st) < 0 || git_mwindow_file_register(&p->mwf) < 0) @@ -875,13 +882,20 @@ static int packfile_open(struct git_pack_file *p) idx_sha1 = ((unsigned char *)p->index_map.data) + p->index_map.len - 40; - if (git_oid__cmp(&sha1, (git_oid *)idx_sha1) == 0) - return 0; + if (git_oid__cmp(&sha1, (git_oid *)idx_sha1) != 0) + goto cleanup; + + git_mutex_unlock(&p->lock); + return 0; cleanup: giterr_set(GITERR_OS, "Invalid packfile '%s'", p->pack_name); + p_close(p->mwf.fd); p->mwf.fd = -1; + + git_mutex_unlock(&p->lock); + return -1; } From d82d66c96d11131440deb8f79443ee0b44d40eff Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 2 May 2013 03:05:21 -0700 Subject: [PATCH 122/134] Extra threading tests We need to hammer the packfile open phase harder in the thread tests, in addition to the cache API. --- tests-clar/object/cache.c | 58 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/tests-clar/object/cache.c b/tests-clar/object/cache.c index a3eba8737..e06760e2a 100644 --- a/tests-clar/object/cache.c +++ b/tests-clar/object/cache.c @@ -5,7 +5,7 @@ static git_repository *g_repo; void test_object_cache__initialize(void) { - cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + g_repo = NULL; } void test_object_cache__cleanup(void) @@ -56,6 +56,7 @@ void test_object_cache__cache_everything(void) git_libgit2_opts( GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)32767); + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_odb(&odb, g_repo)); start = (int)git_cache_size(&g_repo->objects); @@ -105,6 +106,7 @@ void test_object_cache__cache_no_blobs(void) git_libgit2_opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, (int)GIT_OBJ_BLOB, (size_t)0); + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_odb(&odb, g_repo)); start = (int)git_cache_size(&g_repo->objects); @@ -189,8 +191,8 @@ static void *cache_raw(void *arg) return arg; } -#define REPEAT 50 -#define THREADCOUNT 20 +#define REPEAT 20 +#define THREADCOUNT 50 void test_object_cache__threadmania(void) { @@ -207,6 +209,8 @@ void test_object_cache__threadmania(void) for (try = 0; try < REPEAT; ++try) { + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + for (th = 0; th < THREADCOUNT; ++th) { data = git__malloc(2 * sizeof(int)); @@ -231,5 +235,53 @@ void test_object_cache__threadmania(void) } #endif + git_repository_free(g_repo); + g_repo = NULL; + } +} + +static void *cache_quick(void *arg) +{ + git_oid oid; + git_object *obj; + + cl_git_pass(git_oid_fromstr(&oid, g_data[4].sha)); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_assert(g_data[4].type == git_object_type(obj)); + git_object_free(obj); + + return arg; +} + +void test_object_cache__fast_thread_rush(void) +{ + int try, th, data[THREADCOUNT*2]; +#ifdef GIT_THREADS + git_thread t[THREADCOUNT*2]; +#endif + + for (try = 0; try < REPEAT; ++try) { + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + + for (th = 0; th < THREADCOUNT*2; ++th) { + data[th] = th; +#ifdef GIT_THREADS + cl_git_pass( + git_thread_create(&t[th], NULL, cache_quick, &data[th])); +#else + cl_assert(cache_quick(&data[th]) == &data[th]); +#endif + } + +#ifdef GIT_THREADS + for (th = 0; th < THREADCOUNT*2; ++th) { + void *rval; + cl_git_pass(git_thread_join(t[th], &rval)); + cl_assert_equal_i(th, *((int *)rval)); + } +#endif + + git_repository_free(g_repo); + g_repo = NULL; } } From 81b7dec4ee21454775f932717273a90a46f78e1f Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 2 May 2013 03:06:34 -0700 Subject: [PATCH 123/134] Fix some compile warnings and trailing whitespace --- src/index.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/index.c b/src/index.c index 1771f2957..d4aa475a9 100644 --- a/src/index.c +++ b/src/index.c @@ -193,44 +193,46 @@ static int conflict_name_cmp(const void *a, const void *b) { const git_index_name_entry *name_a = a; const git_index_name_entry *name_b = b; - + if (name_a->ancestor && !name_b->ancestor) return 1; - + if (!name_a->ancestor && name_b->ancestor) return -1; - + if (name_a->ancestor) return strcmp(name_a->ancestor, name_b->ancestor); - + if (!name_a->ours || !name_b->ours) return 0; - + return strcmp(name_a->ours, name_b->ours); } /** * TODO: enable this when resolving case insensitive conflicts */ +#if 0 static int conflict_name_icmp(const void *a, const void *b) { const git_index_name_entry *name_a = a; const git_index_name_entry *name_b = b; - + if (name_a->ancestor && !name_b->ancestor) return 1; - + if (!name_a->ancestor && name_b->ancestor) return -1; - + if (name_a->ancestor) return strcasecmp(name_a->ancestor, name_b->ancestor); - + if (!name_a->ours || !name_b->ours) return 0; - + return strcasecmp(name_a->ours, name_b->ours); } +#endif static int reuc_srch(const void *key, const void *array_member) { From 8c535f3f6879c6796d8107d7eb80dd8b2105621b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 2 May 2013 03:34:56 -0700 Subject: [PATCH 124/134] Protect sha1_entry_pos call with mutex There is an occasional assertion failure in sha1_entry_pos from pack_entry_find_index when running threaded. Holding the mutex around the code that grabs the index_map data and processes it makes this assertion failure go away. --- src/pack.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/pack.c b/src/pack.c index 47534f195..1ffad29ae 100644 --- a/src/pack.c +++ b/src/pack.c @@ -1050,24 +1050,24 @@ static int pack_entry_find_offset( const git_oid *short_oid, size_t len) { - const uint32_t *level1_ofs = p->index_map.data; - const unsigned char *index = p->index_map.data; + const uint32_t *level1_ofs; + const unsigned char *index; unsigned hi, lo, stride; int pos, found = 0; const unsigned char *current = 0; *offset_out = 0; - if (index == NULL) { - int error; + if (!p->index_map.data && pack_index_open(p) < 0) + return git_odb__error_notfound("failed to open packfile", NULL); - if ((error = pack_index_open(p)) < 0) - return error; - assert(p->index_map.data); + if (git_mutex_lock(&p->lock) < 0) + return packfile_error("failed to get lock for finding entry offset"); - index = p->index_map.data; - level1_ofs = p->index_map.data; - } + assert(p->index_map.data); + + index = p->index_map.data; + level1_ofs = p->index_map.data; if (p->index_version > 1) { level1_ofs += 2; @@ -1093,6 +1093,8 @@ static int pack_entry_find_offset( /* Use git.git lookup code */ pos = sha1_entry_pos(index, stride, 0, lo, hi, p->num_objects, short_oid->id); + git_mutex_unlock(&p->lock); + if (pos >= 0) { /* An object matching exactly the oid was found */ found = 1; From 7edb9071da8e78e8cf9aff969f1b8137bca3c33d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 2 May 2013 11:07:20 -0400 Subject: [PATCH 125/134] refdb_fs: do not require peeled packed refs to be tags Older versions of git would only write peeled entries for items under refs/tags/. Newer versions will write them for all refs, and we should be prepared to handle that. --- src/refdb_fs.c | 4 --- tests-clar/refs/peel.c | 31 ++++++++++++++++-- tests-clar/resources/peeled.git/HEAD | 1 + tests-clar/resources/peeled.git/config | 8 +++++ .../resources/peeled.git/objects/info/packs | 2 ++ ...4773eaf3fce1774755580e3dbb8d9f3a1adc45.idx | Bin 0 -> 1156 bytes ...773eaf3fce1774755580e3dbb8d9f3a1adc45.pack | Bin 0 -> 274 bytes tests-clar/resources/peeled.git/packed-refs | 6 ++++ .../resources/peeled.git/refs/heads/master | 1 + 9 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 tests-clar/resources/peeled.git/HEAD create mode 100644 tests-clar/resources/peeled.git/config create mode 100644 tests-clar/resources/peeled.git/objects/info/packs create mode 100644 tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.idx create mode 100644 tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.pack create mode 100644 tests-clar/resources/peeled.git/packed-refs create mode 100644 tests-clar/resources/peeled.git/refs/heads/master diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 85444b692..9ee3568da 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -132,10 +132,6 @@ static int packed_parse_peel( if (tag_ref == NULL) goto corrupt; - /* Ensure reference is a tag */ - if (git__prefixcmp(tag_ref->name, GIT_REFS_TAGS_DIR) != 0) - goto corrupt; - if (buffer + GIT_OID_HEXSZ > buffer_end) goto corrupt; diff --git a/tests-clar/refs/peel.c b/tests-clar/refs/peel.c index 34bd02ce0..f2fb6e259 100644 --- a/tests-clar/refs/peel.c +++ b/tests-clar/refs/peel.c @@ -1,19 +1,24 @@ #include "clar_libgit2.h" static git_repository *g_repo; +static git_repository *g_peel_repo; void test_refs_peel__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_open(&g_peel_repo, cl_fixture("peeled.git"))); } void test_refs_peel__cleanup(void) { git_repository_free(g_repo); g_repo = NULL; + git_repository_free(g_peel_repo); + g_peel_repo = NULL; } -static void assert_peel( +static void assert_peel_generic( + git_repository *repo, const char *ref_name, git_otype requested_type, const char* expected_sha, @@ -23,7 +28,7 @@ static void assert_peel( git_reference *ref; git_object *peeled; - cl_git_pass(git_reference_lookup(&ref, g_repo, ref_name)); + cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); cl_git_pass(git_reference_peel(&peeled, ref, requested_type)); @@ -36,6 +41,16 @@ static void assert_peel( git_reference_free(ref); } +static void assert_peel( + const char *ref_name, + git_otype requested_type, + const char* expected_sha, + git_otype expected_type) +{ + assert_peel_generic(g_repo, ref_name, requested_type, + expected_sha, expected_type); +} + static void assert_peel_error(int error, const char *ref_name, git_otype requested_type) { git_reference *ref; @@ -90,3 +105,15 @@ void test_refs_peel__can_peel_into_any_non_tag_object(void) assert_peel("refs/tags/test", GIT_OBJ_ANY, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_COMMIT); } + +void test_refs_peel__can_peel_fully_peeled_packed_refs(void) +{ + assert_peel_generic(g_peel_repo, + "refs/tags/tag-inside-tags", GIT_OBJ_ANY, + "0df1a5865c8abfc09f1f2182e6a31be550e99f07", + GIT_OBJ_COMMIT); + assert_peel_generic(g_peel_repo, + "refs/foo/tag-outside-tags", GIT_OBJ_ANY, + "0df1a5865c8abfc09f1f2182e6a31be550e99f07", + GIT_OBJ_COMMIT); +} diff --git a/tests-clar/resources/peeled.git/HEAD b/tests-clar/resources/peeled.git/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/tests-clar/resources/peeled.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests-clar/resources/peeled.git/config b/tests-clar/resources/peeled.git/config new file mode 100644 index 000000000..88300524a --- /dev/null +++ b/tests-clar/resources/peeled.git/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true +[remote "origin"] + url = /home/peff/compile/libgit2/tests-clar/resources/peeled + fetch = +refs/*:refs/* + mirror = true diff --git a/tests-clar/resources/peeled.git/objects/info/packs b/tests-clar/resources/peeled.git/objects/info/packs new file mode 100644 index 000000000..0d88b32e5 --- /dev/null +++ b/tests-clar/resources/peeled.git/objects/info/packs @@ -0,0 +1,2 @@ +P pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.pack + diff --git a/tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.idx b/tests-clar/resources/peeled.git/objects/pack/pack-e84773eaf3fce1774755580e3dbb8d9f3a1adc45.idx new file mode 100644 index 0000000000000000000000000000000000000000..9b79e9b85f879d05623c23d8f2c6d73d6a70e807 GIT binary patch literal 1156 zcmexg;-AdGz`z8=r!Y~W~(S1(g3xJ#!=OZD+ z8cyM)c2uM$Rpkx0hi>N0C?BZ?xTt4JfokHS6|;Jse3~Ti?28bgta1e*{&H-gP8_(VeRdm99oB#j- literal 0 HcmV?d00001 diff --git a/tests-clar/resources/peeled.git/packed-refs b/tests-clar/resources/peeled.git/packed-refs new file mode 100644 index 000000000..ad053d550 --- /dev/null +++ b/tests-clar/resources/peeled.git/packed-refs @@ -0,0 +1,6 @@ +# pack-refs with: peeled fully-peeled +c2596aa0151888587ec5c0187f261e63412d9e11 refs/foo/tag-outside-tags +^0df1a5865c8abfc09f1f2182e6a31be550e99f07 +0df1a5865c8abfc09f1f2182e6a31be550e99f07 refs/heads/master +c2596aa0151888587ec5c0187f261e63412d9e11 refs/tags/tag-inside-tags +^0df1a5865c8abfc09f1f2182e6a31be550e99f07 diff --git a/tests-clar/resources/peeled.git/refs/heads/master b/tests-clar/resources/peeled.git/refs/heads/master new file mode 100644 index 000000000..76c15e203 --- /dev/null +++ b/tests-clar/resources/peeled.git/refs/heads/master @@ -0,0 +1 @@ +0df1a5865c8abfc09f1f2182e6a31be550e99f07 From 34bd59992e9e11107d16837b671f867e2a5e77ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 2 May 2013 17:14:05 +0200 Subject: [PATCH 126/134] Revert "Protect sha1_entry_pos call with mutex" This reverts commit 8c535f3f6879c6796d8107d7eb80dd8b2105621b. --- src/pack.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/pack.c b/src/pack.c index 1ffad29ae..47534f195 100644 --- a/src/pack.c +++ b/src/pack.c @@ -1050,24 +1050,24 @@ static int pack_entry_find_offset( const git_oid *short_oid, size_t len) { - const uint32_t *level1_ofs; - const unsigned char *index; + const uint32_t *level1_ofs = p->index_map.data; + const unsigned char *index = p->index_map.data; unsigned hi, lo, stride; int pos, found = 0; const unsigned char *current = 0; *offset_out = 0; - if (!p->index_map.data && pack_index_open(p) < 0) - return git_odb__error_notfound("failed to open packfile", NULL); + if (index == NULL) { + int error; - if (git_mutex_lock(&p->lock) < 0) - return packfile_error("failed to get lock for finding entry offset"); + if ((error = pack_index_open(p)) < 0) + return error; + assert(p->index_map.data); - assert(p->index_map.data); - - index = p->index_map.data; - level1_ofs = p->index_map.data; + index = p->index_map.data; + level1_ofs = p->index_map.data; + } if (p->index_version > 1) { level1_ofs += 2; @@ -1093,8 +1093,6 @@ static int pack_entry_find_offset( /* Use git.git lookup code */ pos = sha1_entry_pos(index, stride, 0, lo, hi, p->num_objects, short_oid->id); - git_mutex_unlock(&p->lock); - if (pos >= 0) { /* An object matching exactly the oid was found */ found = 1; From 3bb00f3360bd11a48e1b04dc7dec971f0019891f Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 2 May 2013 17:17:46 +0200 Subject: [PATCH 127/134] refdb_fs: implement the fully-peeled trait --- src/refdb_fs.c | 7 ------- src/refs.h | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 9ee3568da..8a2d56327 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -677,13 +677,6 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) if (ref->flags & GIT_PACKREF_HAS_PEEL) return 0; - /* - * Only applies to tags, i.e. references - * in the /refs/tags folder - */ - if (git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) != 0) - return 0; - /* * Find the tagged object in the repository */ diff --git a/src/refs.h b/src/refs.h index 908e86f29..927bc83ce 100644 --- a/src/refs.h +++ b/src/refs.h @@ -26,7 +26,7 @@ #define GIT_SYMREF "ref: " #define GIT_PACKEDREFS_FILE "packed-refs" -#define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled " +#define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled fully-peeled" #define GIT_PACKEDREFS_FILE_MODE 0666 #define GIT_HEAD_FILE "HEAD" From f69db390fb5cbacbb1c63d146aef4e0fb6754ddf Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 2 May 2013 17:29:58 +0200 Subject: [PATCH 128/134] refdb_fs: store "cannot be peeled" flag for packed refs Fixes #1532 --- src/refdb_fs.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 8a2d56327..00d1c4fd5 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -26,8 +26,15 @@ GIT__USE_STRMAP; #define MAX_NESTING_LEVEL 10 enum { - GIT_PACKREF_HAS_PEEL = 1, - GIT_PACKREF_WAS_LOOSE = 2 + PACKREF_HAS_PEEL = 1, + PACKREF_WAS_LOOSE = 2, + PACKREF_CANNOT_PEEL = 4 +}; + +enum { + PEELING_NONE = 0, + PEELING_STANDARD, + PEELING_FULL }; struct packref { @@ -44,6 +51,7 @@ typedef struct refdb_fs_backend { char *path; git_refcache refcache; + int peeling_mode; } refdb_fs_backend; static int reference_read( @@ -150,6 +158,7 @@ static int packed_parse_peel( goto corrupt; } + tag_ref->flags |= PACKREF_HAS_PEEL; *buffer_out = buffer; return 0; @@ -201,6 +210,25 @@ static int packed_load(refdb_fs_backend *backend) buffer_start = (const char *)packfile.ptr; buffer_end = (const char *)(buffer_start) + packfile.size; + backend->peeling_mode = PEELING_NONE; + + if (buffer_start[0] == '#') { + static const char *traits_header = "# pack-refs with: "; + + if (git__prefixcmp(buffer_start, traits_header) == 0) { + const char *traits = buffer_start + strlen(traits_header); + const char *traits_end = strchr(traits, '\n'); + + if (strstr(traits, "fully-peeled") != NULL) { + backend->peeling_mode = PEELING_FULL; + } else if (strstr(traits, "peeled") != NULL) { + backend->peeling_mode = PEELING_STANDARD; + } + + buffer_start = traits_end + 1; + } + } + while (buffer_start < buffer_end && buffer_start[0] == '#') { buffer_start = strchr(buffer_start, '\n'); if (buffer_start == NULL) @@ -219,6 +247,8 @@ static int packed_load(refdb_fs_backend *backend) if (buffer_start[0] == '^') { if (packed_parse_peel(ref, &buffer_start, buffer_end) < 0) goto parse_failed; + } else if (backend->peeling_mode == PEELING_FULL) { + ref->flags |= PACKREF_CANNOT_PEEL; } git_strmap_insert(ref_cache->packfile, ref->name, ref, err); @@ -291,7 +321,7 @@ static int loose_lookup_to_packfile( return -1; } - ref->flags = GIT_PACKREF_WAS_LOOSE; + ref->flags = PACKREF_WAS_LOOSE; *ref_out = ref; git_buf_free(&ref_file); @@ -674,7 +704,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) { git_object *object; - if (ref->flags & GIT_PACKREF_HAS_PEEL) + if (ref->flags & PACKREF_HAS_PEEL || ref->flags & PACKREF_CANNOT_PEEL) return 0; /* @@ -695,7 +725,7 @@ static int packed_find_peel(refdb_fs_backend *backend, struct packref *ref) * Find the object pointed at by this tag */ git_oid_cpy(&ref->peel, git_tag_target_id(tag)); - ref->flags |= GIT_PACKREF_HAS_PEEL; + ref->flags |= PACKREF_HAS_PEEL; /* * The reference has now cached the resolved OID, and is @@ -728,7 +758,7 @@ static int packed_write_ref(struct packref *ref, git_filebuf *file) * This obviously only applies to tags. * The required peels have already been loaded into `ref->peel_target`. */ - if (ref->flags & GIT_PACKREF_HAS_PEEL) { + if (ref->flags & PACKREF_HAS_PEEL) { char peel[GIT_OID_HEXSZ + 1]; git_oid_fmt(peel, &ref->peel); peel[GIT_OID_HEXSZ] = 0; @@ -765,7 +795,7 @@ static int packed_remove_loose( for (i = 0; i < packing_list->length; ++i) { struct packref *ref = git_vector_get(packing_list, i); - if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0) + if ((ref->flags & PACKREF_WAS_LOOSE) == 0) continue; if (git_buf_joinpath(&full_path, backend->path, ref->name) < 0) From 1022db2b6860d602e79169906eee4f299855975b Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 2 May 2013 17:42:09 +0200 Subject: [PATCH 129/134] refdb_fs: Traits are always surrounded by spaces This makes parsing easier! :p --- src/refdb_fs.c | 4 ++-- src/refs.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 00d1c4fd5..6a6f589f0 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -219,9 +219,9 @@ static int packed_load(refdb_fs_backend *backend) const char *traits = buffer_start + strlen(traits_header); const char *traits_end = strchr(traits, '\n'); - if (strstr(traits, "fully-peeled") != NULL) { + if (strstr(traits, " fully-peeled ") != NULL) { backend->peeling_mode = PEELING_FULL; - } else if (strstr(traits, "peeled") != NULL) { + } else if (strstr(traits, " peeled ") != NULL) { backend->peeling_mode = PEELING_STANDARD; } diff --git a/src/refs.h b/src/refs.h index 927bc83ce..f487ee3fc 100644 --- a/src/refs.h +++ b/src/refs.h @@ -26,7 +26,7 @@ #define GIT_SYMREF "ref: " #define GIT_PACKEDREFS_FILE "packed-refs" -#define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled fully-peeled" +#define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled fully-peeled " #define GIT_PACKEDREFS_FILE_MODE 0666 #define GIT_HEAD_FILE "HEAD" From 822645f6298ae0ff86fa717a79c5b7e105bc4a0d Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 2 May 2013 17:48:49 +0200 Subject: [PATCH 130/134] refdb_fs: Only strstr the traits line --- src/refdb_fs.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 6a6f589f0..2c45eabb7 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -216,8 +216,13 @@ static int packed_load(refdb_fs_backend *backend) static const char *traits_header = "# pack-refs with: "; if (git__prefixcmp(buffer_start, traits_header) == 0) { - const char *traits = buffer_start + strlen(traits_header); - const char *traits_end = strchr(traits, '\n'); + char *traits = (char *)buffer_start + strlen(traits_header); + char *traits_end = strchr(traits, '\n'); + + if (traits_end == NULL) + goto parse_failed; + + *traits_end = '\0'; if (strstr(traits, " fully-peeled ") != NULL) { backend->peeling_mode = PEELING_FULL; From a591ed3ea9e46771510628f1f677f2f3791078d6 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 2 May 2013 12:06:46 -0400 Subject: [PATCH 131/134] refdb_fs: respect PEELING_STANDARD We only set our negative flag for PEELING_FULL; we can fall back to the lesser PEELING_STANDARD if our ref is in the refs/tags/ hierarchy. --- src/refdb_fs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 2c45eabb7..c0a32bae7 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -252,7 +252,9 @@ static int packed_load(refdb_fs_backend *backend) if (buffer_start[0] == '^') { if (packed_parse_peel(ref, &buffer_start, buffer_end) < 0) goto parse_failed; - } else if (backend->peeling_mode == PEELING_FULL) { + } else if (backend->peeling_mode == PEELING_FULL || + (backend->peeling_mode == PEELING_STANDARD && + git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) == 0)) { ref->flags |= PACKREF_CANNOT_PEEL; } From 0ddfcb40d5ddf2e6d74f061efcccd944d18460cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 2 May 2013 18:06:14 +0200 Subject: [PATCH 132/134] Switch to index_version as "git_pack_file is ready" flag We use p->index_map.data to check whether the struct has been set up and all the information about the index is stored there. This variable gets set up halfway through the setup process, however, and a thread can come along and use fields that haven't been written to yet. Crucially, pack_entry_find_offset() needs to read the index version (which is written after index_map) to know the offset and stride length to pass to sha1_entry_pos(). If these values are wrong, assertions in it will fail, as it will be reading bogus data. Make index_version the last field to be written and switch from using p->index_map.data to p->index_version as "git_pack_file is ready" flag as we can use it to know if every field has been written. --- src/pack.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pack.c b/src/pack.c index 47534f195..417d225f3 100644 --- a/src/pack.c +++ b/src/pack.c @@ -293,8 +293,8 @@ static int pack_index_check(const char *path, struct git_pack_file *p) } } - p->index_version = version; p->num_objects = nr; + p->index_version = version; return 0; } @@ -304,7 +304,7 @@ static int pack_index_open(struct git_pack_file *p) int error = 0; size_t name_len, base_len; - if (p->index_map.data) + if (p->index_version > -1) return 0; name_len = strlen(p->pack_name); @@ -320,7 +320,7 @@ static int pack_index_open(struct git_pack_file *p) if ((error = git_mutex_lock(&p->lock)) < 0) return error; - if (!p->index_map.data) + if (p->index_version == -1) error = pack_index_check(idx_name, p); git__free(idx_name); @@ -826,7 +826,7 @@ static int packfile_open(struct git_pack_file *p) git_oid sha1; unsigned char *idx_sha1; - if (!p->index_map.data && pack_index_open(p) < 0) + if (p->index_version == -1 && pack_index_open(p) < 0) return git_odb__error_notfound("failed to open packfile", NULL); /* if mwf opened by another thread, return now */ @@ -942,6 +942,7 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) p->mwf.size = st.st_size; p->pack_local = 1; p->mtime = (git_time_t)st.st_mtime; + p->index_version = -1; git_mutex_init(&p->lock); @@ -1058,7 +1059,7 @@ static int pack_entry_find_offset( *offset_out = 0; - if (index == NULL) { + if (p->index_version == -1) { int error; if ((error = pack_index_open(p)) < 0) From 4e7c15608f427466ef941cad45b27f1ad30bd25a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 May 2013 14:58:40 -0500 Subject: [PATCH 133/134] puns are not funny; type punning especially so --- src/merge.c | 22 ++++++++++++++++------ tests-clar/merge/merge_helpers.c | 6 +++--- tests-clar/merge/merge_helpers.h | 7 ++----- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/merge.c b/src/merge.c index 320be005a..56290bfad 100644 --- a/src/merge.c +++ b/src/merge.c @@ -357,7 +357,7 @@ static int merge_conflict_resolve_trivial( git_merge_diff_list *diff_list, const git_merge_diff *conflict) { - int ancestor_empty, ours_empty, theirs_empty; + int ours_empty, theirs_empty; int ours_changed, theirs_changed, ours_theirs_differ; git_index_entry const *result = NULL; int error = 0; @@ -374,7 +374,6 @@ static int merge_conflict_resolve_trivial( conflict->their_status == GIT_DELTA_RENAMED) return 0; - ancestor_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry); ours_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry); theirs_empty = !GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry); @@ -678,6 +677,7 @@ static int index_entry_similarity_calc( { git_blob *blob; git_diff_file diff_file = {{{0}}}; + git_off_t blobsize; int error; *out = NULL; @@ -691,8 +691,14 @@ static int index_entry_similarity_calc( diff_file.mode = entry->mode; diff_file.flags = 0; + blobsize = git_blob_rawsize(blob); + + /* file too big for rename processing */ + if (!git__is_sizet(blobsize)) + return 0; + error = opts->metric->buffer_signature(out, &diff_file, - git_blob_rawcontent(blob), git_blob_rawsize(blob), + git_blob_rawcontent(blob), (size_t)blobsize, opts->metric->payload); git_blob_free(blob); @@ -1273,7 +1279,7 @@ int git_merge_diff_list__find_differences( git_vector_cmp entry_compare = git_index_entry__cmp; struct merge_diff_df_data df_data = {0}; int cur_item_modified; - size_t i; + size_t i, j; int error = 0; assert(diff_list && our_tree && their_tree); @@ -1290,7 +1296,9 @@ int git_merge_diff_list__find_differences( } while (true) { - memset(cur_items, 0x0, sizeof(git_index_entry *) * 3); + for (i = 0; i < 3; i++) + cur_items[i] = NULL; + best_cur_item = NULL; cur_item_modified = 0; @@ -1312,7 +1320,9 @@ int git_merge_diff_list__find_differences( * Found an item that sorts before our current item, make * our current item this one. */ - memset(cur_items, 0x0, sizeof(git_index_entry *) * 3); + for (j = 0; j < i; j++) + cur_items[j] = NULL; + cur_item_modified = 1; best_cur_item = items[i]; cur_items[i] = items[i]; diff --git a/tests-clar/merge/merge_helpers.c b/tests-clar/merge/merge_helpers.c index 5c3421e7e..71bb96781 100644 --- a/tests-clar/merge/merge_helpers.c +++ b/tests-clar/merge/merge_helpers.c @@ -149,9 +149,9 @@ static int name_entry_eq_merge_name_entry(const struct merge_name_entry *expecte static int index_conflict_data_eq_merge_diff(const struct merge_index_conflict_data *expected, git_merge_diff *actual) { - if (!index_entry_eq_merge_index_entry((const struct merge_index_entry *)&expected->ancestor, &actual->ancestor_entry) || - !index_entry_eq_merge_index_entry((const struct merge_index_entry *)&expected->ours, &actual->our_entry) || - !index_entry_eq_merge_index_entry((const struct merge_index_entry *)&expected->theirs, &actual->their_entry)) + if (!index_entry_eq_merge_index_entry(&expected->ancestor.entry, &actual->ancestor_entry) || + !index_entry_eq_merge_index_entry(&expected->ours.entry, &actual->our_entry) || + !index_entry_eq_merge_index_entry(&expected->theirs.entry, &actual->their_entry)) return 0; if (expected->ours.status != actual->our_status || diff --git a/tests-clar/merge/merge_helpers.h b/tests-clar/merge/merge_helpers.h index 1a0b8921b..cb718e01a 100644 --- a/tests-clar/merge/merge_helpers.h +++ b/tests-clar/merge/merge_helpers.h @@ -18,11 +18,8 @@ struct merge_name_entry { }; struct merge_index_with_status { - uint16_t mode; - char oid_str[41]; - int stage; - char path[128]; - unsigned int status; + struct merge_index_entry entry; + unsigned int status; }; struct merge_reuc_entry { From 5e151329fbb048dfc74f37432f619a4e331d24f7 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 May 2013 15:19:49 -0500 Subject: [PATCH 134/134] braces --- tests-clar/merge/trees/treediff.c | 360 +++++++++++++++--------------- 1 file changed, 180 insertions(+), 180 deletions(-) diff --git a/tests-clar/merge/trees/treediff.c b/tests-clar/merge/trees/treediff.c index 5da6f7658..06ea94e0d 100644 --- a/tests-clar/merge/trees/treediff.c +++ b/tests-clar/merge/trees/treediff.c @@ -90,51 +90,51 @@ void test_merge_trees_treediff__simple(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt", GIT_DELTA_ADDED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE }, { - { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt", GIT_DELTA_MODIFIED }, - { 0100644, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe", 0, "automergeable.txt", GIT_DELTA_MODIFIED }, + { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_BOTH_MODIFIED }, { - { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "4eb04c9e79e88f6640d01ff5b25ca2a60764f216", 0, "changed-in-branch.txt", GIT_DELTA_MODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "4eb04c9e79e88f6640d01ff5b25ca2a60764f216", 0, "changed-in-branch.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_NONE }, { - { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt", GIT_DELTA_MODIFIED }, - { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE }, { - { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt", GIT_DELTA_MODIFIED }, - { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 0, "conflicting.txt", GIT_DELTA_MODIFIED }, + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "2bd0a343aeef7a2cf0d158478966a6e587ff3863", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_BOTH_MODIFIED }, { - { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_NONE }, { - { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE }, }; @@ -146,142 +146,142 @@ void test_merge_trees_treediff__df_conflicts(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "49130a28ef567af9a6a6104c38773fedfa5f9742", 0, "dir-10", GIT_DELTA_ADDED }, - { 0100644, "6c06dcd163587c2cc18be44857e0b71116382aeb", 0, "dir-10", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "49130a28ef567af9a6a6104c38773fedfa5f9742", 0, "dir-10" }, GIT_DELTA_ADDED }, + { { 0100644, "6c06dcd163587c2cc18be44857e0b71116382aeb", 0, "dir-10" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_BOTH_ADDED, }, { - { 0100644, "242591eb280ee9eeb2ce63524b9a8b9bc4cb515d", 0, "dir-10/file.txt", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, + { { 0100644, "242591eb280ee9eeb2ce63524b9a8b9bc4cb515d", 0, "dir-10/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_BOTH_DELETED, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "43aafd43bea779ec74317dc361f45ae3f532a505", 0, "dir-6", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "43aafd43bea779ec74317dc361f45ae3f532a505", 0, "dir-6" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, + { { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "cf8c5cc8a85a1ff5a4ba51e0bc7cf5665669924d", 0, "dir-6/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_NONE, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "a031a28ae70e33a641ce4b8a8f6317f1ab79dee4", 0, "dir-7", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "a031a28ae70e33a641ce4b8a8f6317f1ab79dee4", 0, "dir-7" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_DIRECTORY_FILE, }, { - { 0100644, "5012fd565b1393bdfda1805d4ec38ce6619e1fd1", 0, "dir-7/file.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "a5563304ddf6caba25cb50323a2ea6f7dbfcadca", 0, "dir-7/file.txt", GIT_DELTA_MODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, + { { 0100644, "5012fd565b1393bdfda1805d4ec38ce6619e1fd1", 0, "dir-7/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "a5563304ddf6caba25cb50323a2ea6f7dbfcadca", 0, "dir-7/file.txt" }, GIT_DELTA_MODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_DF_CHILD, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "e9ad6ec3e38364a3d07feda7c4197d4d845c53b5", 0, "dir-8", GIT_DELTA_ADDED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "e9ad6ec3e38364a3d07feda7c4197d4d845c53b5", 0, "dir-8" }, GIT_DELTA_ADDED }, + { {0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "f20c9063fa0bda9a397c96947a7b687305c49753", 0, "dir-8/file.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "3ef4d30382ca33fdeba9fda895a99e0891ba37aa", 0, "dir-9", GIT_DELTA_ADDED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "3ef4d30382ca33fdeba9fda895a99e0891ba37aa", 0, "dir-9" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_DIRECTORY_FILE, }, { - { 0100644, "fc4c636d6515e9e261f9260dbcf3cc6eca97ea08", 0, "dir-9/file.txt", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0100644, "76ab0e2868197ec158ddd6c78d8a0d2fd73d38f9", 0, "dir-9/file.txt", GIT_DELTA_MODIFIED }, + { { 0100644, "fc4c636d6515e9e261f9260dbcf3cc6eca97ea08", 0, "dir-9/file.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "76ab0e2868197ec158ddd6c78d8a0d2fd73d38f9", 0, "dir-9/file.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_DF_CHILD, }, { - { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1", GIT_DELTA_UNMODIFIED }, - { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, + { { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "1e4ff029aee68d0d69ef9eb6efa6cbf1ec732f99", 0, "file-1" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_NONE, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "5c2411f8075f48a6b2fdb85ebc0d371747c4df15", 0, "file-1/new", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "5c2411f8075f48a6b2fdb85ebc0d371747c4df15", 0, "file-1/new" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "a39a620dae5bc8b4e771cd4d251b7d080401a21e", 0, "file-2", GIT_DELTA_UNMODIFIED }, - { 0100644, "d963979c237d08b6ba39062ee7bf64c7d34a27f8", 0, "file-2", GIT_DELTA_MODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, + { { 0100644, "a39a620dae5bc8b4e771cd4d251b7d080401a21e", 0, "file-2" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "d963979c237d08b6ba39062ee7bf64c7d34a27f8", 0, "file-2" }, GIT_DELTA_MODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_DIRECTORY_FILE, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "5c341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d", 0, "file-2/new", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "5c341ead2ba6f2af98ce5ec3fe84f6b6d2899c0d", 0, "file-2/new" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_DF_CHILD, }, { - { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3", GIT_DELTA_UNMODIFIED }, + { { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "032ebc5ab85d9553bb187d3cd40875ff23a63ed0", 0, "file-3" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "9efe7723802d4305142eee177e018fee1572c4f4", 0, "file-3/new", GIT_DELTA_ADDED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "9efe7723802d4305142eee177e018fee1572c4f4", 0, "file-3/new" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "bacac9b3493509aa15e1730e1545fc0919d1dae0", 0, "file-4", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0100644, "7663fce0130db092936b137cabd693ec234eb060", 0, "file-4", GIT_DELTA_MODIFIED }, + { { 0100644, "bacac9b3493509aa15e1730e1545fc0919d1dae0", 0, "file-4" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "7663fce0130db092936b137cabd693ec234eb060", 0, "file-4" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_DIRECTORY_FILE, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "e49f917b448d1340b31d76e54ba388268fd4c922", 0, "file-4/new", GIT_DELTA_ADDED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "e49f917b448d1340b31d76e54ba388268fd4c922", 0, "file-4/new" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_DF_CHILD, }, { - { 0100644, "ac4045f965119e6998f4340ed0f411decfb3ec05", 0, "file-5", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, + { { 0100644, "ac4045f965119e6998f4340ed0f411decfb3ec05", 0, "file-5" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_BOTH_DELETED, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "cab2cf23998b40f1af2d9d9a756dc9e285a8df4b", 0, "file-5/new", GIT_DELTA_ADDED }, - { 0100644, "f5504f36e6f4eb797a56fc5bac6c6c7f32969bf2", 0, "file-5/new", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "cab2cf23998b40f1af2d9d9a756dc9e285a8df4b", 0, "file-5/new" }, GIT_DELTA_ADDED }, + { { 0100644, "f5504f36e6f4eb797a56fc5bac6c6c7f32969bf2", 0, "file-5/new" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_BOTH_ADDED, }, }; @@ -293,58 +293,58 @@ void test_merge_trees_treediff__strict_renames(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt", GIT_DELTA_ADDED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt", GIT_DELTA_MODIFIED }, - { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt", GIT_DELTA_MODIFIED }, - { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt", GIT_DELTA_MODIFIED }, - { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "renamed-in-branch.txt", GIT_DELTA_RENAMED }, + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "renamed-in-branch.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "renamed.txt", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "renamed.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "copied.txt", GIT_DELTA_RENAMED }, + { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "copied.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_NONE, }, }; @@ -356,128 +356,128 @@ void test_merge_trees_treediff__rename_conflicts(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt", GIT_DELTA_ADDED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-rewritten-in-ours.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 0, "0b-rewritten-in-ours.txt", GIT_DELTA_MODIFIED }, - { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 0, "0b-rewritten-in-ours.txt", GIT_DELTA_MODIFIED }, + { { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-rewritten-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "e376fbdd06ebf021c92724da9f26f44212734e3e", 0, "0b-rewritten-in-ours.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "b2d399ae15224e1d58066e3c8df70ce37de7a656", 0, "0b-rewritten-in-ours.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_BOTH_MODIFIED, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-rewritten-in-theirs.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 0, "0c-rewritten-in-theirs.txt", GIT_DELTA_MODIFIED }, - { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 0, "0c-rewritten-in-theirs.txt", GIT_DELTA_MODIFIED }, + { { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-rewritten-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 0, "0c-rewritten-in-theirs.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "712ebba6669ea847d9829e4f1059d6c830c8b531", 0, "0c-rewritten-in-theirs.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_BOTH_MODIFIED, }, { - { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-renamed-in-ours-edited-in-theirs.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-newname-in-ours-edited-in-theirs.txt", GIT_DELTA_RENAMED }, - { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 0, "1a-renamed-in-ours-edited-in-theirs.txt", GIT_DELTA_MODIFIED }, + { { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-renamed-in-ours-edited-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "c3d02eeef75183df7584d8d13ac03053910c1301", 0, "1a-newname-in-ours-edited-in-theirs.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "0d872f8e871a30208305978ecbf9e66d864f1638", 0, "1a-renamed-in-ours-edited-in-theirs.txt" }, GIT_DELTA_MODIFIED }, GIT_MERGE_DIFF_RENAMED_MODIFIED, }, { - { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt", GIT_DELTA_RENAMED }, - { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-newname-in-ours.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "d0d4594e16f2e19107e3fa7ea63e7aaaff305ffb", 0, "1a-renamed-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-renamed-in-theirs-edited-in-ours.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 0, "1b-renamed-in-theirs-edited-in-ours.txt", GIT_DELTA_MODIFIED }, - { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-newname-in-theirs-edited-in-ours.txt", GIT_DELTA_RENAMED }, + { { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-renamed-in-theirs-edited-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ed9523e62e453e50dd9be1606af19399b96e397a", 0, "1b-renamed-in-theirs-edited-in-ours.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "241a1005cd9b980732741b74385b891142bcba28", 0, "1b-newname-in-theirs-edited-in-ours.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_RENAMED_MODIFIED, }, { - { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt", GIT_DELTA_RENAMED }, + { { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-renamed-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "2b5f1f181ee3b58ea751f5dd5d8f9b445520a136", 0, "1b-newname-in-theirs.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-renamed-in-both.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt", GIT_DELTA_RENAMED }, - { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt", GIT_DELTA_RENAMED }, + { { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-renamed-in-both.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "178940b450f238a56c0d75b7955cb57b38191982", 0, "2-newname-in-both.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_BOTH_RENAMED, }, { - { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-renamed-in-ours-deleted-in-theirs.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-newname-in-ours-deleted-in-theirs.txt", GIT_DELTA_RENAMED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, + { { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-renamed-in-ours-deleted-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "18cb316b1cefa0f8a6946f0e201a8e1a6f845ab9", 0, "3a-newname-in-ours-deleted-in-theirs.txt" }, GIT_DELTA_RENAMED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_RENAMED_DELETED, }, { - { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-renamed-in-theirs-deleted-in-ours.txt", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt", GIT_DELTA_RENAMED }, + { { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-renamed-in-theirs-deleted-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_RENAMED_DELETED, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 0, "4a-newname-in-ours-added-in-theirs.txt", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 0, "4a-newname-in-ours-added-in-theirs.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_RENAMED_ADDED, }, { - { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-renamed-in-ours-added-in-theirs.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-newname-in-ours-added-in-theirs.txt", GIT_DELTA_RENAMED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, + { { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-renamed-in-ours-added-in-theirs.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-newname-in-ours-added-in-theirs.txt" }, GIT_DELTA_RENAMED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, GIT_MERGE_DIFF_RENAMED_ADDED, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 0, "4b-newname-in-theirs-added-in-ours.txt", GIT_DELTA_ADDED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 0, "4b-newname-in-theirs-added-in-ours.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_RENAMED_ADDED, }, { - { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-renamed-in-theirs-added-in-ours.txt", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-newname-in-theirs-added-in-ours.txt", GIT_DELTA_RENAMED }, + { { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-renamed-in-theirs-added-in-ours.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-newname-in-theirs-added-in-ours.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_RENAMED_ADDED, }, { - { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-ours.txt", GIT_DELTA_RENAMED }, - { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-theirs.txt", GIT_DELTA_RENAMED }, + { { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-ours.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "5-both-renamed-1-to-2-theirs.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_BOTH_RENAMED_1_TO_2, }, { - { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed.txt", GIT_DELTA_RENAMED }, - { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed.txt" }, GIT_DELTA_RENAMED }, + { { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "6-both-renamed-side-1.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1, }, { - { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed.txt", GIT_DELTA_RENAMED }, + { { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed-side-2.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "6-both-renamed.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_BOTH_RENAMED_2_TO_1, }, }; @@ -490,51 +490,51 @@ void test_merge_trees_treediff__best_renames(void) { struct merge_index_conflict_data treediff_conflict_data[] = { { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt", GIT_DELTA_ADDED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt", GIT_DELTA_MODIFIED }, - { 0100644, "45299c1ca5e07bba1fd90843056fb559f96b1f5a", 0, "renamed-90.txt", GIT_DELTA_RENAMED }, + { { 0100644, "6212c31dab5e482247d7977e4f0dd3601decf13b", 0, "automergeable.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "45299c1ca5e07bba1fd90843056fb559f96b1f5a", 0, "renamed-90.txt" }, GIT_DELTA_RENAMED }, GIT_MERGE_DIFF_RENAMED_MODIFIED, }, { - { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt", GIT_DELTA_MODIFIED }, - { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, - { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt", GIT_DELTA_MODIFIED }, - { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, GIT_DELTA_MODIFIED }, + { { 0100644, "d427e0b2e138501a3d15cc376077a3631e15bd46", 0, "conflicting.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_NONE, }, { - { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt",GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_DELETED }, - { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt", GIT_DELTA_UNMODIFIED }, + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" },GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_DELETED }, + { { 0100644, "5c3b68a71fc4fa5d362fd3875e53137c6a5ab7a5", 0, "removed-in-master.txt" }, GIT_DELTA_UNMODIFIED }, GIT_MERGE_DIFF_MODIFIED_DELETED, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "5843febcb23480df0b5edb22a21c59c772bb8e29", 0, "renamed-50.txt", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "5843febcb23480df0b5edb22a21c59c772bb8e29", 0, "renamed-50.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, { - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0, "", 0, "", GIT_DELTA_UNMODIFIED }, - { 0100644, "a77a56a49f8f3ae242e02717f18ebbc60c5cc543", 0, "renamed-75.txt", GIT_DELTA_ADDED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0, "", 0, "" }, GIT_DELTA_UNMODIFIED }, + { { 0100644, "a77a56a49f8f3ae242e02717f18ebbc60c5cc543", 0, "renamed-75.txt" }, GIT_DELTA_ADDED }, GIT_MERGE_DIFF_NONE, }, };