From 7ef9f1b5606c2672105ecbbf34c022a71ef212fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicent=20Mart=C3=AD?= Date: Mon, 2 Apr 2012 21:05:45 +0200 Subject: [PATCH 001/181] Backport .travis.yml --- .travis.yml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000..4c8c42aaa17 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,38 @@ +# Travis-CI Build for libgit2 +# see travis-ci.org for details + +# As CMake is not officially supported we use erlang VMs +language: erlang + +# Settings to try +env: + - OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release" + - OPTIONS="-DBUILD_CLAR=ON" + +# Make sure CMake is installed +install: + - sudo apt-get install cmake + +# Run the Build script +script: + - mkdir _build + - cd _build + - cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS + - cmake --build . --target install + +# Run Tests +after_script: + - ctest . + +# Only watch the development branch +branches: + only: + - development + +# Notify development list when needed +notifications: + recipients: + - vicent@github.com + email: + on_success: change + on_failure: always From 799f9a04e38579a6340145440bb927d3dd83c642 Mon Sep 17 00:00:00 2001 From: Philip Kelley Date: Tue, 19 Mar 2013 14:56:45 -0400 Subject: [PATCH 002/181] Reduce the number of unnecessary objects in pushed packs --- src/push.c | 177 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 142 insertions(+), 35 deletions(-) diff --git a/src/push.c b/src/push.c index 37f64181279..ee21bd9d115 100644 --- a/src/push.c +++ b/src/push.c @@ -13,6 +13,7 @@ #include "remote.h" #include "vector.h" #include "push.h" +#include "tree.h" static int push_spec_rref_cmp(const void *a, const void *b) { @@ -346,60 +347,166 @@ static int revwalk(git_vector *commits, git_push *push) return error == GIT_ITEROVER ? 0 : error; } -static int queue_objects(git_push *push) +static int queue_differences( + git_tree *base, + git_tree *delta, + git_packbuilder *pb) { - git_vector commits; - git_oid *o; - unsigned int i; + git_tree *b_child = NULL, *d_child = NULL; + size_t b_length = git_tree_entrycount(base); + size_t d_length = git_tree_entrycount(delta); + size_t i = 0, j = 0; int error; - if (git_vector_init(&commits, 0, NULL) < 0) - return -1; +#define _enqueue_object(ENTRY) do { \ + switch (git_tree_entry_type((ENTRY))) { \ + case GIT_OBJ_COMMIT: \ + break; \ + case GIT_OBJ_TREE: \ + if ((error = git_packbuilder_insert_tree(pb, &(ENTRY)->oid)) < 0) \ + goto on_error; \ + break; \ + default: \ + if ((error = git_packbuilder_insert(pb, &(ENTRY)->oid, \ + (ENTRY)->filename)) < 0) \ + goto on_error; \ + break; \ + } \ +} while (0) + + while (i < b_length && j < d_length) { + const git_tree_entry *b_entry = git_tree_entry_byindex(base, i); + 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)) + goto loop; + + cmp = memcmp(b_entry->filename, + d_entry->filename, + b_entry->filename_len); + + /* If the entries are both trees and they have the same name but are + * different, then we'll recurse after adding the right-hand entry */ + if (!cmp && + git_tree_entry__is_tree(b_entry) && + git_tree_entry__is_tree(d_entry)) { + /* Add the right-hand entry */ + if ((error = git_packbuilder_insert(pb, &d_entry->oid, + d_entry->filename)) < 0) + goto on_error; + + /* Acquire the subtrees and recurse */ + if ((error = git_tree_lookup(&b_child, + git_tree_owner(base), &b_entry->oid)) < 0 || + (error = git_tree_lookup(&d_child, + git_tree_owner(delta), &d_entry->oid)) < 0 || + (error = queue_differences(b_child, d_child, pb)) < 0) + goto on_error; + + git_tree_free(b_child); b_child = NULL; + git_tree_free(d_child); d_child = NULL; + } + /* If the object is new or different in the right-hand tree, + * then enumerate it */ + else if (cmp >= 0) + _enqueue_object(d_entry); + + loop: + if (cmp <= 0) i++; + if (cmp >= 0) j++; + } + + /* Drain the right-hand tree of entries */ + for (; j < d_length; j++) + _enqueue_object(git_tree_entry_byindex(delta, j)); + +#undef _enqueue_object + + error = 0; + +on_error: + if (b_child) + git_tree_free(b_child); + + if (d_child) + git_tree_free(d_child); + + return error; +} + +static int queue_objects(git_push *push) +{ + git_vector commits = GIT_VECTOR_INIT; + git_oid *oid; + size_t i; + unsigned j; + int error; if ((error = revwalk(&commits, push)) < 0) goto on_error; - if (!commits.length) { - git_vector_free(&commits); - return 0; /* nothing to do */ - } + git_vector_foreach(&commits, i, oid) { + git_commit *parent = NULL, *commit; + git_tree *tree = NULL, *ptree = NULL; + size_t parentcount; - git_vector_foreach(&commits, i, o) { - if ((error = git_packbuilder_insert(push->pb, o, NULL)) < 0) + if ((error = git_commit_lookup(&commit, push->repo, oid)) < 0) goto on_error; - } - git_vector_foreach(&commits, i, o) { - git_object *obj; + /* Insert the commit */ + if ((error = git_packbuilder_insert(push->pb, oid, NULL)) < 0) + goto loop_error; - if ((error = git_object_lookup(&obj, push->repo, o, GIT_OBJ_ANY)) < 0) - goto on_error; + parentcount = git_commit_parentcount(commit); - switch (git_object_type(obj)) { - case GIT_OBJ_TAG: /* TODO: expect tags */ - case GIT_OBJ_COMMIT: + if (!parentcount) { if ((error = git_packbuilder_insert_tree(push->pb, - git_commit_tree_id((git_commit *)obj))) < 0) { - git_object_free(obj); - goto on_error; + git_commit_tree_id(commit))) < 0) + goto loop_error; + } else { + if ((error = git_tree_lookup(&tree, push->repo, + git_commit_tree_id(commit))) < 0 || + (error = git_packbuilder_insert(push->pb, + git_commit_tree_id(commit), NULL)) < 0) + goto loop_error; + + /* For each parent, add the items which are different */ + for (j = 0; j < parentcount; j++) { + if ((error = git_commit_parent(&parent, commit, j)) < 0 || + (error = git_commit_tree(&ptree, parent)) < 0 || + (error = queue_differences(ptree, tree, push->pb)) < 0) + goto loop_error; + + git_tree_free(ptree); ptree = NULL; + git_commit_free(parent); parent = NULL; } - break; - case GIT_OBJ_TREE: - case GIT_OBJ_BLOB: - default: - git_object_free(obj); - giterr_set(GITERR_INVALID, "Given object type invalid"); - error = -1; - goto on_error; } - git_object_free(obj); + + error = 0; + + loop_error: + if (tree) + git_tree_free(tree); + + if (ptree) + git_tree_free(ptree); + + if (parent) + git_commit_free(parent); + + git_commit_free(commit); + + if (error < 0) + goto on_error; } + error = 0; on_error: - git_vector_foreach(&commits, i, o) { - git__free(o); - } + git_vector_foreach(&commits, i, oid) + git__free(oid); + git_vector_free(&commits); return error; } From bef2a12cc0859a65a6bc6e72465395a4a48bd3e7 Mon Sep 17 00:00:00 2001 From: Philip Kelley Date: Tue, 19 Mar 2013 15:35:26 -0400 Subject: [PATCH 003/181] Convert enqueue_object to a function --- src/push.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/push.c b/src/push.c index ee21bd9d115..00745fbccfe 100644 --- a/src/push.c +++ b/src/push.c @@ -347,6 +347,20 @@ static int revwalk(git_vector *commits, git_push *push) return error == GIT_ITEROVER ? 0 : error; } +static int enqueue_object( + const git_tree_entry *entry, + git_packbuilder *pb) +{ + switch (git_tree_entry_type(entry)) { + case GIT_OBJ_COMMIT: + return 0; + case GIT_OBJ_TREE: + return git_packbuilder_insert_tree(pb, &entry->oid); + default: + return git_packbuilder_insert(pb, &entry->oid, entry->filename); + } +} + static int queue_differences( git_tree *base, git_tree *delta, @@ -358,22 +372,6 @@ static int queue_differences( size_t i = 0, j = 0; int error; -#define _enqueue_object(ENTRY) do { \ - switch (git_tree_entry_type((ENTRY))) { \ - case GIT_OBJ_COMMIT: \ - break; \ - case GIT_OBJ_TREE: \ - if ((error = git_packbuilder_insert_tree(pb, &(ENTRY)->oid)) < 0) \ - goto on_error; \ - break; \ - default: \ - if ((error = git_packbuilder_insert(pb, &(ENTRY)->oid, \ - (ENTRY)->filename)) < 0) \ - goto on_error; \ - break; \ - } \ -} while (0) - while (i < b_length && j < d_length) { const git_tree_entry *b_entry = git_tree_entry_byindex(base, i); const git_tree_entry *d_entry = git_tree_entry_byindex(delta, j); @@ -409,8 +407,9 @@ static int queue_differences( } /* If the object is new or different in the right-hand tree, * then enumerate it */ - else if (cmp >= 0) - _enqueue_object(d_entry); + else if (cmp >= 0 && + (error = enqueue_object(d_entry, pb)) < 0) + goto on_error; loop: if (cmp <= 0) i++; @@ -419,9 +418,8 @@ static int queue_differences( /* Drain the right-hand tree of entries */ for (; j < d_length; j++) - _enqueue_object(git_tree_entry_byindex(delta, j)); - -#undef _enqueue_object + if ((error = enqueue_object(git_tree_entry_byindex(delta, j), pb)) < 0) + goto on_error; error = 0; From cd01dd5d63a7e7899f31a9c1c3fd361bcdf3f74c Mon Sep 17 00:00:00 2001 From: Philip Kelley Date: Tue, 19 Mar 2013 15:43:34 -0400 Subject: [PATCH 004/181] Fix dumb mistake in the comparison function --- src/push.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/push.c b/src/push.c index 00745fbccfe..f81a0aee9cf 100644 --- a/src/push.c +++ b/src/push.c @@ -380,9 +380,7 @@ static int queue_differences( if (!git_oid_cmp(&b_entry->oid, &d_entry->oid)) goto loop; - cmp = memcmp(b_entry->filename, - d_entry->filename, - b_entry->filename_len); + cmp = strcmp(b_entry->filename, d_entry->filename); /* If the entries are both trees and they have the same name but are * different, then we'll recurse after adding the right-hand entry */ From a258d8e3574c4e993bf16e0c136d1a5fbc356728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 30 Mar 2013 03:39:19 +0100 Subject: [PATCH 005/181] branch: rename 'tracking' to 'upstream' The term 'tracking' is overloaded. Help distinguish what we mean by using 'upstream' for this part of the library. --- include/git2/branch.h | 4 +- src/branch.c | 16 +++---- src/branch.h | 2 +- src/remote.c | 2 +- src/revparse.c | 2 +- src/submodule.c | 2 +- tests-clar/clone/empty.c | 2 +- tests-clar/refs/branches/trackingname.c | 42 ------------------- .../refs/branches/{tracking.c => upstream.c} | 38 ++++++++--------- tests-clar/refs/branches/upstreamname.c | 42 +++++++++++++++++++ 10 files changed, 76 insertions(+), 76 deletions(-) delete mode 100644 tests-clar/refs/branches/trackingname.c rename tests-clar/refs/branches/{tracking.c => upstream.c} (64%) create mode 100644 tests-clar/refs/branches/upstreamname.c diff --git a/include/git2/branch.h b/include/git2/branch.h index 4d24e2d825c..28bb1f5f074 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -173,7 +173,7 @@ GIT_EXTERN(int) git_branch_name(const char **out, * @return 0 on success; GIT_ENOTFOUND when no remote tracking * reference exists, otherwise an error code. */ -GIT_EXTERN(int) git_branch_tracking( +GIT_EXTERN(int) git_branch_upstream( git_reference **out, git_reference *branch); @@ -195,7 +195,7 @@ GIT_EXTERN(int) git_branch_tracking( * including the trailing NUL byte; GIT_ENOTFOUND when no remote tracking * reference exists, otherwise an error code. */ -GIT_EXTERN(int) git_branch_tracking_name( +GIT_EXTERN(int) git_branch_upstream_name( char *tracking_branch_name_out, size_t buffer_size, git_repository *repo, diff --git a/src/branch.c b/src/branch.c index 45ecca7515d..56c63a82a66 100644 --- a/src/branch.c +++ b/src/branch.c @@ -228,7 +228,7 @@ int git_branch_name(const char **out, git_reference *ref) return 0; } -static int retrieve_tracking_configuration( +static int retrieve_upstream_configuration( const char **out, git_repository *repo, const char *canonical_branch_name, @@ -250,7 +250,7 @@ static int retrieve_tracking_configuration( return error; } -int git_branch_tracking__name( +int git_branch_upstream__name( git_buf *tracking_name, git_repository *repo, const char *canonical_branch_name) @@ -266,11 +266,11 @@ int git_branch_tracking__name( if (!git_reference__is_branch(canonical_branch_name)) return not_a_local_branch(canonical_branch_name); - if ((error = retrieve_tracking_configuration( + if ((error = retrieve_upstream_configuration( &remote_name, repo, canonical_branch_name, "branch.%s.remote")) < 0) goto cleanup; - if ((error = retrieve_tracking_configuration( + if ((error = retrieve_upstream_configuration( &merge_name, repo, canonical_branch_name, "branch.%s.merge")) < 0) goto cleanup; @@ -386,7 +386,7 @@ int git_branch_remote_name( return error; } -int git_branch_tracking_name( +int git_branch_upstream_name( char *tracking_branch_name_out, size_t buffer_size, git_repository *repo, @@ -400,7 +400,7 @@ int git_branch_tracking_name( if (tracking_branch_name_out && buffer_size) *tracking_branch_name_out = '\0'; - if ((error = git_branch_tracking__name( + if ((error = git_branch_upstream__name( &buf, repo, canonical_branch_name)) < 0) goto cleanup; @@ -422,14 +422,14 @@ int git_branch_tracking_name( return (int)error; } -int git_branch_tracking( +int git_branch_upstream( git_reference **tracking_out, git_reference *branch) { int error; git_buf tracking_name = GIT_BUF_INIT; - if ((error = git_branch_tracking__name(&tracking_name, + if ((error = git_branch_upstream__name(&tracking_name, git_reference_owner(branch), git_reference_name(branch))) < 0) return error; diff --git a/src/branch.h b/src/branch.h index 8a26c4fea79..d02f2af0de4 100644 --- a/src/branch.h +++ b/src/branch.h @@ -9,7 +9,7 @@ #include "buffer.h" -int git_branch_tracking__name( +int git_branch_upstream__name( git_buf *tracking_name, git_repository *repo, const char *canonical_branch_name); diff --git a/src/remote.c b/src/remote.c index a6f62d6a525..896361e3081 100644 --- a/src/remote.c +++ b/src/remote.c @@ -705,7 +705,7 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_ve if ((error = git_reference_resolve(&resolved_ref, ref)) < 0 || (!git_reference_is_branch(resolved_ref)) || - (error = git_branch_tracking(&tracking_ref, resolved_ref)) < 0 || + (error = git_branch_upstream(&tracking_ref, resolved_ref)) < 0 || (error = git_refspec_transform_l(&remote_name, &remote->fetch, git_reference_name(tracking_ref))) < 0) { /* Not an error if HEAD is orphaned or no tracking branch */ if (error == GIT_ENOTFOUND) diff --git a/src/revparse.c b/src/revparse.c index 1518a7c3c2f..2fd636135b4 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -356,7 +356,7 @@ static int retrieve_remote_tracking_reference(git_reference **base_ref, const ch goto cleanup; } - if ((error = git_branch_tracking(&tracking, ref)) < 0) + if ((error = git_branch_upstream(&tracking, ref)) < 0) goto cleanup; *base_ref = tracking; diff --git a/src/submodule.c b/src/submodule.c index 066a881cb69..2fdaf2f7770 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -1327,7 +1327,7 @@ static int lookup_head_remote(git_buf *url, git_repository *repo) goto cleanup; } - if ((error = git_branch_tracking(&remote, head)) < 0) + if ((error = git_branch_upstream(&remote, head)) < 0) goto cleanup; /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */ diff --git a/tests-clar/clone/empty.c b/tests-clar/clone/empty.c index 0f867257a43..f190523b657 100644 --- a/tests-clar/clone/empty.c +++ b/tests-clar/clone/empty.c @@ -49,7 +49,7 @@ void test_clone_empty__can_clone_an_empty_local_repo_barely(void) /* ...one can still retrieve the name of the remote tracking reference */ cl_assert_equal_i((int)strlen(expected_tracked_branch_name) + 1, - git_branch_tracking_name(buffer, 1024, g_repo_cloned, local_name)); + git_branch_upstream_name(buffer, 1024, g_repo_cloned, local_name)); cl_assert_equal_s(expected_tracked_branch_name, buffer); diff --git a/tests-clar/refs/branches/trackingname.c b/tests-clar/refs/branches/trackingname.c deleted file mode 100644 index 5aee33343e9..00000000000 --- a/tests-clar/refs/branches/trackingname.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "clar_libgit2.h" -#include "branch.h" - -static git_repository *repo; -static git_buf tracking_name; - -void test_refs_branches_trackingname__initialize(void) -{ - cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); - - git_buf_init(&tracking_name, 0); -} - -void test_refs_branches_trackingname__cleanup(void) -{ - git_buf_free(&tracking_name); - - git_repository_free(repo); - repo = NULL; -} - -void test_refs_branches_trackingname__can_retrieve_the_remote_tracking_reference_name_of_a_local_branch(void) -{ - cl_git_pass(git_branch_tracking__name( - &tracking_name, repo, "refs/heads/master")); - - cl_assert_equal_s("refs/remotes/test/master", git_buf_cstr(&tracking_name)); -} - -void test_refs_branches_trackingname__can_retrieve_the_local_tracking_reference_name_of_a_local_branch(void) -{ - cl_git_pass(git_branch_tracking__name( - &tracking_name, repo, "refs/heads/track-local")); - - cl_assert_equal_s("refs/heads/master", git_buf_cstr(&tracking_name)); -} - -void test_refs_branches_trackingname__can_return_the_size_of_thelocal_tracking_reference_name_of_a_local_branch(void) -{ - cl_assert_equal_i((int)strlen("refs/heads/master") + 1, - git_branch_tracking_name(NULL, 0, repo, "refs/heads/track-local")); -} diff --git a/tests-clar/refs/branches/tracking.c b/tests-clar/refs/branches/upstream.c similarity index 64% rename from tests-clar/refs/branches/tracking.c rename to tests-clar/refs/branches/upstream.c index 30599d9fcd7..fca25416190 100644 --- a/tests-clar/refs/branches/tracking.c +++ b/tests-clar/refs/branches/upstream.c @@ -2,19 +2,19 @@ #include "refs.h" static git_repository *repo; -static git_reference *branch, *tracking; +static git_reference *branch, *upstream; -void test_refs_branches_tracking__initialize(void) +void test_refs_branches_upstream__initialize(void) { cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); branch = NULL; - tracking = NULL; + upstream = NULL; } -void test_refs_branches_tracking__cleanup(void) +void test_refs_branches_upstream__cleanup(void) { - git_reference_free(tracking); + git_reference_free(upstream); git_reference_free(branch); branch = NULL; @@ -22,43 +22,43 @@ void test_refs_branches_tracking__cleanup(void) repo = NULL; } -void test_refs_branches_tracking__can_retrieve_the_remote_tracking_reference_of_a_local_branch(void) +void test_refs_branches_upstream__can_retrieve_the_remote_tracking_reference_of_a_local_branch(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master")); - cl_git_pass(git_branch_tracking(&tracking, branch)); + cl_git_pass(git_branch_upstream(&upstream, branch)); - cl_assert_equal_s("refs/remotes/test/master", git_reference_name(tracking)); + cl_assert_equal_s("refs/remotes/test/master", git_reference_name(upstream)); } -void test_refs_branches_tracking__can_retrieve_the_local_tracking_reference_of_a_local_branch(void) +void test_refs_branches_upstream__can_retrieve_the_local_upstream_reference_of_a_local_branch(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/track-local")); - cl_git_pass(git_branch_tracking(&tracking, branch)); + cl_git_pass(git_branch_upstream(&upstream, branch)); - cl_assert_equal_s("refs/heads/master", git_reference_name(tracking)); + cl_assert_equal_s("refs/heads/master", git_reference_name(upstream)); } -void test_refs_branches_tracking__cannot_retrieve_a_remote_tracking_reference_from_a_non_branch(void) +void test_refs_branches_upstream__cannot_retrieve_a_remote_upstream_reference_from_a_non_branch(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/tags/e90810b")); - cl_git_fail(git_branch_tracking(&tracking, branch)); + cl_git_fail(git_branch_upstream(&upstream, branch)); } -void test_refs_branches_tracking__trying_to_retrieve_a_remote_tracking_reference_from_a_plain_local_branch_returns_GIT_ENOTFOUND(void) +void test_refs_branches_upstream__trying_to_retrieve_a_remote_tracking_reference_from_a_plain_local_branch_returns_GIT_ENOTFOUND(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/subtrees")); - cl_assert_equal_i(GIT_ENOTFOUND, git_branch_tracking(&tracking, branch)); + cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch)); } -void test_refs_branches_tracking__trying_to_retrieve_a_remote_tracking_reference_from_a_branch_with_no_fetchspec_returns_GIT_ENOTFOUND(void) +void test_refs_branches_upstream__trying_to_retrieve_a_remote_tracking_reference_from_a_branch_with_no_fetchspec_returns_GIT_ENOTFOUND(void) { cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/cannot-fetch")); - cl_assert_equal_i(GIT_ENOTFOUND, git_branch_tracking(&tracking, branch)); + cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch)); } static void assert_merge_and_or_remote_key_missing(git_repository *repository, const git_commit *target, const char *entry_name) @@ -68,12 +68,12 @@ static void assert_merge_and_or_remote_key_missing(git_repository *repository, c cl_assert_equal_i(GIT_OBJ_COMMIT, git_object_type((git_object*)target)); cl_git_pass(git_branch_create(&branch, repository, entry_name, (git_commit*)target, 0)); - cl_assert_equal_i(GIT_ENOTFOUND, git_branch_tracking(&tracking, branch)); + cl_assert_equal_i(GIT_ENOTFOUND, git_branch_upstream(&upstream, branch)); git_reference_free(branch); } -void test_refs_branches_tracking__retrieve_a_remote_tracking_reference_from_a_branch_with_no_remote_returns_GIT_ENOTFOUND(void) +void test_refs_branches_upstream__retrieve_a_remote_tracking_reference_from_a_branch_with_no_remote_returns_GIT_ENOTFOUND(void) { git_reference *head; git_repository *repository; diff --git a/tests-clar/refs/branches/upstreamname.c b/tests-clar/refs/branches/upstreamname.c new file mode 100644 index 00000000000..f05607d4469 --- /dev/null +++ b/tests-clar/refs/branches/upstreamname.c @@ -0,0 +1,42 @@ +#include "clar_libgit2.h" +#include "branch.h" + +static git_repository *repo; +static git_buf upstream_name; + +void test_refs_branches_upstreamname__initialize(void) +{ + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + + git_buf_init(&upstream_name, 0); +} + +void test_refs_branches_upstreamname__cleanup(void) +{ + git_buf_free(&upstream_name); + + git_repository_free(repo); + repo = NULL; +} + +void test_refs_branches_upstreamname__can_retrieve_the_remote_tracking_reference_name_of_a_local_branch(void) +{ + cl_git_pass(git_branch_upstream__name( + &upstream_name, repo, "refs/heads/master")); + + cl_assert_equal_s("refs/remotes/test/master", git_buf_cstr(&upstream_name)); +} + +void test_refs_branches_upstreamname__can_retrieve_the_local_upstream_reference_name_of_a_local_branch(void) +{ + cl_git_pass(git_branch_upstream__name( + &upstream_name, repo, "refs/heads/track-local")); + + cl_assert_equal_s("refs/heads/master", git_buf_cstr(&upstream_name)); +} + +void test_refs_branches_upstreamname__can_return_the_size_of_thelocal_upstream_reference_name_of_a_local_branch(void) +{ + cl_assert_equal_i((int)strlen("refs/heads/master") + 1, + git_branch_upstream_name(NULL, 0, repo, "refs/heads/track-local")); +} From 97016f29ab2359da5c59e2acae6369794fceb9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 30 Mar 2013 09:30:29 +0100 Subject: [PATCH 006/181] branch: refactor git_branch_remote_name Return the size we'd need to write to instead of simply an error. Split the function into two to be used later by the upstream configuration functions. --- src/branch.c | 47 +++++++++++++++---------------- tests-clar/refs/branches/remote.c | 2 +- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/branch.c b/src/branch.c index 56c63a82a66..3b5d1d3c761 100644 --- a/src/branch.c +++ b/src/branch.c @@ -305,23 +305,16 @@ int git_branch_upstream__name( return error; } -int git_branch_remote_name( - char *remote_name_out, - size_t buffer_size, - git_repository *repo, - const char *canonical_branch_name) +static int remote_name(git_buf *buf, git_repository *repo, const char *canonical_branch_name) { git_strarray remote_list = {0}; - size_t i, remote_name_size; + size_t i; git_remote *remote; const git_refspec *fetchspec; int error = 0; char *remote_name = NULL; - assert(repo && canonical_branch_name); - - if (remote_name_out && buffer_size) - *remote_name_out = '\0'; + assert(buf && repo && canonical_branch_name); /* Verify that this is a remote branch */ if (!git_reference__is_remote(canonical_branch_name)) { @@ -362,23 +355,10 @@ int git_branch_remote_name( } if (remote_name) { - remote_name_size = strlen(remote_name) + 1; - error = (int) remote_name_size; - - if (remote_name_out) { - if(remote_name_size > buffer_size) { - giterr_set( - GITERR_INVALID, - "Buffer too short to hold the remote name."); - error = GIT_ERROR; - goto cleanup; - } - - memcpy(remote_name_out, remote_name, remote_name_size); - } + git_buf_clear(buf); + error = git_buf_puts(buf, remote_name); } else { error = GIT_ENOTFOUND; - goto cleanup; } cleanup: @@ -386,6 +366,23 @@ int git_branch_remote_name( return error; } +int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo, const char *refname) +{ + int ret; + git_buf buf = GIT_BUF_INIT; + + if ((ret = remote_name(&buf, repo, refname)) < 0) + return ret; + + if (buffer) + git_buf_copy_cstr(buffer, buffer_len, &buf); + + ret = git_buf_len(&buf) + 1; + git_buf_free(&buf); + + return ret; +} + int git_branch_upstream_name( char *tracking_branch_name_out, size_t buffer_size, diff --git a/tests-clar/refs/branches/remote.c b/tests-clar/refs/branches/remote.c index 5272d1236a7..2beef372440 100644 --- a/tests-clar/refs/branches/remote.c +++ b/tests-clar/refs/branches/remote.c @@ -42,7 +42,7 @@ void test_refs_branches_remote__insufficient_buffer_returns_error(void) cl_git_fail_with(git_branch_remote_name(remotename, expected_remote_name_length - 1, g_repo, remote_tracking_branch_name), - GIT_ERROR); + expected_remote_name_length); } void test_refs_branches_remote__no_matching_remote_returns_error(void) From 804c5f562736b164148e648d475d95298d6d49a8 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Sun, 3 Mar 2013 20:22:51 -0800 Subject: [PATCH 007/181] Fix puzzling doc comment Signed-off-by: Greg Price --- include/git2/revwalk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index ad57b622ee1..0af80625e31 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -92,7 +92,7 @@ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker); * * The given commit will be used as one of the roots * when starting the revision walk. At least one commit - * must be pushed the repository before a walk can + * must be pushed onto the walker before a walk can * be started. * * @param walk the walker being used for the traversal. From 06e6eab0e208966c1152fb13b54eec884e63f2aa Mon Sep 17 00:00:00 2001 From: Greg Price Date: Tue, 19 Mar 2013 12:02:19 -0700 Subject: [PATCH 008/181] revwalk tests: better diagram of example repo The purported command output was already inaccurate, as the refs aren't where it shows. In any event, the labels a reader of this file really needs are the indices used in commit_sorting_*, to make it possible to understand them by referring directly from those arrays to the diagram rather than from the index arrays, to commit_ids, to the diagram. Add those. Signed-off-by: Greg Price --- tests-clar/revwalk/basic.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c index 438ec01627d..de529a9e200 100644 --- a/tests-clar/revwalk/basic.c +++ b/tests-clar/revwalk/basic.c @@ -1,15 +1,14 @@ #include "clar_libgit2.h" /* - $ git log --oneline --graph --decorate - * a4a7dce (HEAD, br2) Merge branch 'master' into br2 + * a4a7dce [0] Merge branch 'master' into br2 |\ - | * 9fd738e (master) a fourth commit - | * 4a202b3 a third commit - * | c47800c branch commit one + | * 9fd738e [1] a fourth commit + | * 4a202b3 [2] a third commit + * | c47800c [3] branch commit one |/ - * 5b5b025 another commit - * 8496071 testing + * 5b5b025 [5] another commit + * 8496071 [4] testing */ static const char *commit_head = "a4a7dce85cf63874e984719f4fdd239f5145052f"; From 2932c8826a1d948565124aa6c9a32df68a15895b Mon Sep 17 00:00:00 2001 From: Greg Price Date: Mon, 4 Mar 2013 02:17:04 -0800 Subject: [PATCH 009/181] revwalk: refactor tests a bit Signed-off-by: Greg Price --- tests-clar/revwalk/basic.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c index de529a9e200..2f1f817c93b 100644 --- a/tests-clar/revwalk/basic.c +++ b/tests-clar/revwalk/basic.c @@ -56,22 +56,17 @@ static int get_commit_index(git_oid *raw_oid) return -1; } -static int test_walk(git_revwalk *walk, const git_oid *root, - int flags, const int possible_results[][6], int results_count) +static int test_walk_only(git_revwalk *walk, + const int possible_results[][commit_count], int results_count) { git_oid oid; - int i; int result_array[commit_count]; - git_revwalk_sorting(walk, flags); - git_revwalk_push(walk, root); - for (i = 0; i < commit_count; ++i) result_array[i] = -1; i = 0; - while (git_revwalk_next(&oid, walk) == 0) { result_array[i++] = get_commit_index(&oid); /*{ @@ -90,6 +85,15 @@ static int test_walk(git_revwalk *walk, const git_oid *root, return GIT_ERROR; } +static int test_walk(git_revwalk *walk, const git_oid *root, + int flags, const int possible_results[][6], int results_count) +{ + git_revwalk_sorting(walk, flags); + git_revwalk_push(walk, root); + + return test_walk_only(walk, possible_results, results_count); +} + static git_repository *_repo; static git_revwalk *_walk; From b08c3173466bf233f27b9085c22dd66c15d5bd6a Mon Sep 17 00:00:00 2001 From: nulltoken Date: Mon, 1 Apr 2013 22:01:13 +0200 Subject: [PATCH 010/181] branch: Fix git_branch_create() documentation --- include/git2/branch.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/git2/branch.h b/include/git2/branch.h index 4d24e2d825c..89a1396afae 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -38,10 +38,8 @@ GIT_BEGIN_DECL * validated for consistency. It should also not conflict with * an already existing branch name. * - * @param target Object to which this branch should point. This object - * must belong to the given `repo` and can either be a git_commit or a - * git_tag. When a git_tag is being passed, it should be dereferencable - * to a git_commit which oid will be used as the target of the branch. + * @param target Commit to which this branch should point. This object + * must belong to the given `repo`. * * @param force Overwrite existing branch. * From c869e26878d752e1e26d2c09efd3bc389584b0a5 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 2 Apr 2013 18:57:42 -0500 Subject: [PATCH 011/181] export git_reference__alloc --- include/git2/refdb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 8d5be8e4702..0586b119e3f 100644 --- a/include/git2/refdb.h +++ b/include/git2/refdb.h @@ -31,7 +31,7 @@ GIT_BEGIN_DECL * @param symbolic the target for a symbolic reference * @return the created git_reference or NULL on error */ -git_reference *git_reference__alloc( +GIT_EXTERN(git_reference *) git_reference__alloc( git_refdb *refdb, const char *name, const git_oid *oid, From f8591e519ad8330ae7314e7259fc943fe9afe053 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Thu, 4 Apr 2013 11:44:50 -0700 Subject: [PATCH 012/181] General example: run against testrepo.git Fixes #1455 --- examples/general.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/examples/general.c b/examples/general.c index c7853fa62dd..a65295f985f 100644 --- a/examples/general.c +++ b/examples/general.c @@ -51,6 +51,8 @@ int main (int argc, char** argv) // There are a couple of methods for opening a repository, this being the // simplest. There are also [methods][me] for specifying the index file // and work tree locations, here we assume they are in the normal places. + // + // (Try running this program against tests-clar/resources/testrepo.git.) // // [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository int error; @@ -65,7 +67,7 @@ int main (int argc, char** argv) // For our first example, we will convert a 40 character hex value to the // 20 byte raw SHA1 value. printf("*Hex to Raw*\n"); - char hex[] = "fd6e612585290339ea8bf39c692a7ff6a29cb7c3"; + char hex[] = "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"; // The `git_oid` is the structure that keeps the SHA value. We will use // this throughout the example for storing the value of the current SHA @@ -164,7 +166,7 @@ int main (int argc, char** argv) printf("\n*Commit Parsing*\n"); git_commit *commit; - git_oid_fromstr(&oid, "f0877d0b841d75172ec404fc9370173dfffc20d1"); + git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479"); error = git_commit_lookup(&commit, repo, &oid); check_error(error, "looking up commit"); @@ -232,9 +234,9 @@ int main (int argc, char** argv) // Commit objects need a tree to point to and optionally one or more // parents. Here we're creating oid objects to create the commit with, // but you can also use - git_oid_fromstr(&tree_id, "28873d96b4e8f4e33ea30f4c682fd325f7ba56ac"); + git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1"); git_tree_lookup(&tree, repo, &tree_id); - git_oid_fromstr(&parent_id, "f0877d0b841d75172ec404fc9370173dfffc20d1"); + git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); git_commit_lookup(&parent, repo, &parent_id); // Here we actually create the commit object with a single call with all @@ -269,7 +271,7 @@ int main (int argc, char** argv) // We create an oid for the tag object if we know the SHA and look it up // the same way that we would a commit (or any other object). - git_oid_fromstr(&oid, "bc422d45275aca289c51d79830b45cecebff7c3a"); + git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); error = git_tag_lookup(&tag, repo, &oid); check_error(error, "looking up tag"); @@ -313,7 +315,7 @@ int main (int argc, char** argv) // You can also access tree entries by name if you know the name of the // entry you're looking for. - entry = git_tree_entry_byname(tree, "hello.c"); + entry = git_tree_entry_byname(tree, "README"); git_tree_entry_name(entry); // "hello.c" // Once you have the entry object, you can access the content or subtree @@ -339,7 +341,7 @@ int main (int argc, char** argv) printf("\n*Blob Parsing*\n"); git_blob *blob; - git_oid_fromstr(&oid, "af7574ea73f7b166f869ef1a39be126d9a186ae0"); + git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08"); git_blob_lookup(&blob, repo, &oid); // You can access a buffer with the raw contents of the blob directly. @@ -365,7 +367,7 @@ int main (int argc, char** argv) git_revwalk *walk; git_commit *wcommit; - git_oid_fromstr(&oid, "f0877d0b841d75172ec404fc9370173dfffc20d1"); + git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); // To use the revwalker, create a new walker, tell it how you want to sort // the output and then push one or more starting points onto the walker. @@ -495,7 +497,9 @@ int main (int argc, char** argv) git_config *cfg; // Open a config object so we can read global values from it. - git_config_open_ondisk(&cfg, "~/.gitconfig"); + char config_path[256]; + sprintf(config_path, "%s/config", repo_path); + check_error(git_config_open_ondisk(&cfg, config_path), "opening config"); git_config_get_int32(&j, cfg, "help.autocorrect"); printf("Autocorrect: %d\n", j); From b208d9002289dcd8170750cb94c84678afdd6e0c Mon Sep 17 00:00:00 2001 From: Greg Price Date: Wed, 20 Mar 2013 10:01:58 -0700 Subject: [PATCH 013/181] revparse: Parse range-like syntax Signed-off-by: Greg Price --- include/git2/revparse.h | 13 ++++++++++++ src/revparse.c | 25 ++++++++++++++++++++++ tests-clar/refs/revparse.c | 43 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 6edb7767c9a..edd8b3cce82 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -32,6 +32,19 @@ GIT_BEGIN_DECL */ GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, const char *spec); +/** + * Parse a string with the form of a revision range, as accepted by + * `git rev-list`, `git diff`, and others. + * + * @param left (output) the left-hand commit + * @param right (output) the right-hand commit + * @param threedots (output) 0 if the endpoints are separated by two dots, 1 if by three + * @param repo the repository to find the commits in + * @param rangelike the rangelike string to be parsed + * @return 0 on success, or any error `git_revparse_single` can return + */ +GIT_EXTERN(int) git_revparse_rangelike(git_object **left, git_object **right, int *threedots, git_repository *repo, const char *rangelike); + /** @} */ GIT_END_DECL #endif diff --git a/src/revparse.c b/src/revparse.c index 8848799751f..7f149713063 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -866,3 +866,28 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec git_buf_free(&buf); return error; } + +int git_revparse_rangelike(git_object **left, git_object **right, int *threedots, git_repository *repo, const char *rangelike) +{ + int error = 0; + const char *p, *q; + char *revspec; + + p = strstr(rangelike, ".."); + if (!p) { + giterr_set(GITERR_INVALID, "Malformed range (or rangelike syntax): %s", rangelike); + return GIT_EINVALIDSPEC; + } else if (p[2] == '.') { + *threedots = 1; + q = p + 3; + } else { + *threedots = 0; + q = p + 2; + } + + revspec = git__substrdup(rangelike, p - rangelike); + error = (git_revparse_single(left, repo, revspec) + || git_revparse_single(right, repo, q)); + git__free(revspec); + return error; +} diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index be92c19564c..b8d7d5edc1b 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -32,6 +32,33 @@ static void test_object(const char *spec, const char *expected_oid) test_object_inrepo(spec, expected_oid, g_repo); } +static void test_rangelike(const char *rangelike, + const char *expected_left, + const char *expected_right, + int expected_threedots) +{ + char objstr[64] = {0}; + git_object *left, *right; + int threedots; + int error; + + error = git_revparse_rangelike(&left, &right, &threedots, g_repo, rangelike); + + if (expected_left != NULL) { + cl_assert_equal_i(0, error); + cl_assert_equal_i(threedots, expected_threedots); + git_oid_fmt(objstr, git_object_id(left)); + cl_assert_equal_s(objstr, expected_left); + git_oid_fmt(objstr, git_object_id(right)); + cl_assert_equal_s(objstr, expected_right); + } else + cl_assert(error != 0); + + git_object_free(left); + git_object_free(right); +} + + void test_refs_revparse__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); @@ -595,3 +622,19 @@ void test_refs_revparse__try_to_retrieve_branch_before_abbrev_sha(void) git_object_free(target); cl_git_sandbox_cleanup(); } + + +void test_refs_revparse__range(void) +{ + test_rangelike("be3563a^1..be3563a", + "9fd738e8f7967c078dceed8190330fc8648ee56a", + "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", + 0); + + test_rangelike("be3563a^1...be3563a", + "9fd738e8f7967c078dceed8190330fc8648ee56a", + "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", + 1); + + test_rangelike("be3563a^1.be3563a", NULL, NULL, 0); +} From af079d8bf69a4bd92d6a4eff3c3d1e4d73190a78 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Sun, 3 Mar 2013 20:54:23 -0800 Subject: [PATCH 014/181] revwalk: Parse revision ranges All the hard work is already in revparse. Signed-off-by: Greg Price --- include/git2/revwalk.h | 15 +++++++++++++++ src/revwalk.c | 25 +++++++++++++++++++++++++ tests-clar/revwalk/basic.c | 12 ++++++++++++ 3 files changed, 52 insertions(+) diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index 0af80625e31..8bfe0b502da 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -216,6 +216,21 @@ GIT_EXTERN(int) git_revwalk_next(git_oid *out, git_revwalk *walk); */ GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode); +/** + * Push and hide the respective endpoints of the given range. + * + * The range should be of the form + * .. + * where each is in the form accepted by 'git_revparse_single'. + * The left-hand commit will be hidden and the right-hand commit pushed. + * + * @param walk the walker being used for the traversal + * @param range the range + * @return 0 or an error code + * + */ +GIT_EXTERN(int) git_revwalk_push_range(git_revwalk *walk, const char *range); + /** * Free a revision walker previously allocated. * diff --git a/src/revwalk.c b/src/revwalk.c index 02834ab3659..c1071843b2f 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -11,6 +11,7 @@ #include "pool.h" #include "revwalk.h" +#include "git2/revparse.h" #include "merge.h" #include @@ -228,6 +229,30 @@ int git_revwalk_push_ref(git_revwalk *walk, const char *refname) return push_ref(walk, refname, 0); } +int git_revwalk_push_range(git_revwalk *walk, const char *range) +{ + git_object *left, *right; + int threedots; + int error = 0; + + if ((error = git_revparse_rangelike(&left, &right, &threedots, walk->repo, range))) + return error; + if (threedots) { + /* TODO: support "..." */ + giterr_set(GITERR_INVALID, "Symmetric differences not implemented in revwalk"); + return GIT_EINVALIDSPEC; + } + + if ((error = push_commit(walk, git_object_id(left), 1))) + goto out; + error = push_commit(walk, git_object_id(right), 0); + + out: + git_object_free(left); + git_object_free(right); + return error; +} + int git_revwalk_hide_ref(git_revwalk *walk, const char *refname) { assert(walk && refname); diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c index 2f1f817c93b..e8277626059 100644 --- a/tests-clar/revwalk/basic.c +++ b/tests-clar/revwalk/basic.c @@ -38,6 +38,10 @@ static const int commit_sorting_time_reverse[][6] = { {4, 5, 2, 1, 3, 0} }; +static const int commit_sorting_segment[][6] = { + {1, 2, -1, -1, -1, -1} +}; + #define commit_count 6 static const int result_bytes = 24; @@ -192,3 +196,11 @@ void test_revwalk_basic__disallow_non_commit(void) cl_git_pass(git_oid_fromstr(&oid, "521d87c1ec3aef9824daf6d96cc0ae3710766d91")); cl_git_fail(git_revwalk_push(_walk, &oid)); } + +void test_revwalk_basic__push_range(void) +{ + git_revwalk_reset(_walk); + git_revwalk_sorting(_walk, 0); + cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e")); + cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1)); +} From 8f7f5e55436eb6b20c12c435eab03e9f37be2e39 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Sun, 31 Mar 2013 14:56:32 -0700 Subject: [PATCH 015/181] examples: rev-list This demonstrates parts of the interface for specifying revisions that Git users are familiar with from 'git rev-list', 'git log', and other Git commands. A similar query interface is used in out-of-core command-line programs that browse a Git repo (like 'tig'), and may be useful for an 'advanced search' interface in GUI or web applications. In this version, we parse all the query modifiers we can support with the existing logic in revwalk: basic include/exclude commits, and the ordering flags. More logic will be required to support '--grep', '--author', the pickaxe '-S', etc. Signed-off-by: Greg Price --- examples/.gitignore | 1 + examples/rev-list.c | 116 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 examples/rev-list.c diff --git a/examples/.gitignore b/examples/.gitignore index e40bfc29f28..e8e0820a5bb 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,4 +1,5 @@ general showindex diff +rev-list *.dSYM diff --git a/examples/rev-list.c b/examples/rev-list.c new file mode 100644 index 00000000000..b7e466f9eaf --- /dev/null +++ b/examples/rev-list.c @@ -0,0 +1,116 @@ +#include +#include + +#include + +static void check_error(int error_code, const char *action) +{ + if (!error_code) + return; + + const git_error *error = giterr_last(); + fprintf(stderr, "Error %d %s: %s\n", -error_code, action, + (error && error->message) ? error->message : "???"); + exit(1); +} + +static int push_commit(git_revwalk *walk, git_object *obj, int hide) +{ + if (hide) + return git_revwalk_hide(walk, git_object_id(obj)); + else + return git_revwalk_push(walk, git_object_id(obj)); +} + +static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, int hide) +{ + int error; + git_object *obj; + + if ((error = git_revparse_single(&obj, repo, spec))) + return error; + return push_commit(walk, obj, hide); +} + +static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide) +{ + git_object *left, *right; + int threedots; + int error = 0; + + if ((error = git_revparse_rangelike(&left, &right, &threedots, repo, range))) + return error; + if (threedots) { + /* TODO: support "..." */ + return GIT_EINVALIDSPEC; + } + + if ((error = push_commit(walk, left, !hide))) + goto out; + error = push_commit(walk, right, hide); + + out: + git_object_free(left); + git_object_free(right); + return error; +} + +static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, const char *const *opts) +{ + int hide, i, error; + unsigned int sorting = GIT_SORT_NONE; + + hide = 0; + for (i = 0; i < nopts; i++) { + if (!strcmp(opts[i], "--topo-order")) { + sorting = GIT_SORT_TOPOLOGICAL | (sorting & GIT_SORT_REVERSE); + git_revwalk_sorting(walk, sorting); + } else if (!strcmp(opts[i], "--date-order")) { + sorting = GIT_SORT_TIME | (sorting & GIT_SORT_REVERSE); + git_revwalk_sorting(walk, sorting); + } else if (!strcmp(opts[i], "--reverse")) { + sorting = (sorting & ~GIT_SORT_REVERSE) + | ((sorting & GIT_SORT_REVERSE) ? 0 : GIT_SORT_REVERSE); + git_revwalk_sorting(walk, sorting); + } else if (!strcmp(opts[i], "--not")) { + hide = !hide; + } else if (opts[i][0] == '^') { + if ((error = push_spec(repo, walk, opts[i] + 1, !hide))) + return error; + } else if (strstr(opts[i], "..")) { + if ((error = push_range(repo, walk, opts[i], hide))) + return error; + } else { + if ((error = push_spec(repo, walk, opts[i], hide))) + return error; + } + } + + return 0; +} + +int main (int argc, char **argv) +{ + int error; + git_repository *repo; + git_revwalk *walk; + git_oid oid; + char buf[41]; + + error = git_repository_open_ext(&repo, ".", 0, NULL); + check_error(error, "opening repository"); + + error = git_revwalk_new(&walk, repo); + check_error(error, "allocating revwalk"); + error = revwalk_parseopts(repo, walk, argc-1, argv+1); + check_error(error, "parsing options"); + + while (!git_revwalk_next(&oid, walk)) { + git_oid_fmt(buf, &oid); + buf[40] = '\0'; + printf("%s\n", buf); + } + + return 0; +} + From 2e2332857d26c7dbed3e4b940bb571da348bb5c7 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Wed, 20 Mar 2013 09:39:20 -0700 Subject: [PATCH 016/181] examples: a test, for rev-list This test file could probably be improved by a framework like the one in git.git:t/, or by using a language like Python instead of shell. The other examples would benefit from tests too. Probably best to settle on a framework to write them in, then add more tests. Signed-off-by: Greg Price --- examples/test/test-rev-list.sh | 95 ++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100755 examples/test/test-rev-list.sh diff --git a/examples/test/test-rev-list.sh b/examples/test/test-rev-list.sh new file mode 100755 index 00000000000..bc0eea7cf46 --- /dev/null +++ b/examples/test/test-rev-list.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +THIS_FILE="$(readlink -f "$0")" +ROOT="$(dirname "$(dirname "$(dirname "$THIS_FILE")")")" +PROGRAM="$ROOT"/examples/rev-list +LIBDIR="$ROOT"/build +REPO="$ROOT"/tests-clar/resources/testrepo.git + +cd "$REPO" + +run () { + LD_LIBRARY_PATH="$LIBDIR" "$PROGRAM" "$@" +} + +diff -u - <(run --date-order a4a7dce) </dev/null || +a4a7dce85cf63874e984719f4fdd239f5145052f +c47800c7266a2be04c571c04d5a6614691ea99bd +9fd738e8f7967c078dceed8190330fc8648ee56a +4a202b346bb0fb0db7eff3cffeb3c70babbd2045 +5b5b025afb0b4c913b4c338a42934a3863bf3644 +8496071c1b46c854b31185ea97743be6a8774479 +EOF +diff -u - <(echo "$out") </dev/null || +8496071c1b46c854b31185ea97743be6a8774479 +5b5b025afb0b4c913b4c338a42934a3863bf3644 +4a202b346bb0fb0db7eff3cffeb3c70babbd2045 +9fd738e8f7967c078dceed8190330fc8648ee56a +c47800c7266a2be04c571c04d5a6614691ea99bd +a4a7dce85cf63874e984719f4fdd239f5145052f +EOF +diff -u - <(echo "$out") </dev/null || +a4a7dce85cf63874e984719f4fdd239f5145052f +c47800c7266a2be04c571c04d5a6614691ea99bd +9fd738e8f7967c078dceed8190330fc8648ee56a +4a202b346bb0fb0db7eff3cffeb3c70babbd2045 +5b5b025afb0b4c913b4c338a42934a3863bf3644 +8496071c1b46c854b31185ea97743be6a8774479 +EOF +diff -u - <(echo "$out") < Date: Sun, 7 Apr 2013 07:23:08 +0200 Subject: [PATCH 017/181] test: Add missing NULLs --- tests-clar/refs/revparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 705014c2a9e..66ee391a760 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -38,7 +38,7 @@ static void test_rangelike(const char *rangelike, int expected_threedots) { char objstr[64] = {0}; - git_object *left, *right; + git_object *left = NULL, *right = NULL; int threedots; int error; From 4d13d07ab21d5041dc3b2e77c9447298d6b39eaa Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 11 Mar 2013 13:20:47 -0700 Subject: [PATCH 018/181] Propose unified rev-parse API --- include/git2/revparse.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/include/git2/revparse.h b/include/git2/revparse.h index edd8b3cce82..71ff6d6966e 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -45,6 +45,43 @@ GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, cons */ GIT_EXTERN(int) git_revparse_rangelike(git_object **left, git_object **right, int *threedots, git_repository *repo, const char *rangelike); + +/** + * Revparse flags. These indicate the intended behavior of the spec passed to + * git_revparse. + */ +typedef enum { + /** The spec targeted a single object. */ + GIT_REVPARSE_SINGLE = 1 << 0, + /** The spec targeted a range of commits. */ + GIT_REVPARSE_RANGE = 1 << 1, + /** The spec used the '...' operator, which invokes special semantics. */ + GIT_REVPARSE_MERGE_BASE = 1 << 2, +} git_revparse_flag_t; + + +/** + * Find an object or range of commits as specified by a revision string. + * See `man gitrevisions` or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions + * for information on the syntax accepted. + * + * @param left buffer that receives the target of the left side of a range operator. If + * there is no range operator, this buffer receives the single target. + * @param right buffer that receives the target of the right side of a range operator. + * This is only filled in if `spec` specifies a range of commits + * @param flags buffer that receives a bitwise combination of `git_revparse_flag_t` values + * @param repo the repository to search in + * @param spec the rev-parse spec to parse + * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code + */ +GIT_EXTERN(int) git_revparse( + git_oid *left, + git_oid *right, + unsigned int *flags, + git_repository *repo, + const char *spec); + + /** @} */ GIT_END_DECL #endif From 8480eef7ee0c8e52a8bf3ea12e5626009a966164 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 11 Mar 2013 20:27:16 -0700 Subject: [PATCH 019/181] Implement unified git_revparse --- include/git2/revparse.h | 34 ++++++++++---------- src/revparse.c | 64 ++++++++++++++++++++++++++++++++++---- tests-clar/refs/revparse.c | 59 +++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 22 deletions(-) diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 71ff6d6966e..9315b66eb56 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -51,35 +51,37 @@ GIT_EXTERN(int) git_revparse_rangelike(git_object **left, git_object **right, in * git_revparse. */ typedef enum { - /** The spec targeted a single object. */ - GIT_REVPARSE_SINGLE = 1 << 0, - /** The spec targeted a range of commits. */ - GIT_REVPARSE_RANGE = 1 << 1, - /** The spec used the '...' operator, which invokes special semantics. */ - GIT_REVPARSE_MERGE_BASE = 1 << 2, + /** The spec targeted a single object. */ + GIT_REVPARSE_SINGLE = 1 << 0, + /** The spec targeted a range of commits. */ + GIT_REVPARSE_RANGE = 1 << 1, + /** The spec used the '...' operator, which invokes special semantics. */ + GIT_REVPARSE_MERGE_BASE = 1 << 2, } git_revparse_flag_t; /** - * Find an object or range of commits as specified by a revision string. - * See `man gitrevisions` or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions - * for information on the syntax accepted. + * Parse a revision string for left, right, and intent. See `man gitrevisions` or + * http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for information + * on the syntax accepted. * * @param left buffer that receives the target of the left side of a range operator. If * there is no range operator, this buffer receives the single target. * @param right buffer that receives the target of the right side of a range operator. - * This is only filled in if `spec` specifies a range of commits - * @param flags buffer that receives a bitwise combination of `git_revparse_flag_t` values + * This is only filled in if `spec` specifies a range of commits. May + * be NULL. + * @param flags buffer that receives a bitwise combination of `git_revparse_flag_t` values. + * May be NULL. * @param repo the repository to search in * @param spec the rev-parse spec to parse * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code */ GIT_EXTERN(int) git_revparse( - git_oid *left, - git_oid *right, - unsigned int *flags, - git_repository *repo, - const char *spec); + git_oid *left, + git_oid *right, + unsigned int *flags, + git_repository *repo, + const char *spec); /** @} */ diff --git a/src/revparse.c b/src/revparse.c index 2ba29383e4d..2ba42d8e3ac 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -107,7 +107,7 @@ static int build_regex(regex_t *regex, const char *pattern) error = regcomp(regex, pattern, REG_EXTENDED); if (!error) return 0; - + error = giterr_set_regex(regex, error); regfree(regex); @@ -125,7 +125,7 @@ static int maybe_describe(git_object**out, git_repository *repo, const char *spe if (substr == NULL) return GIT_ENOTFOUND; - + if (build_regex(®ex, ".+-[0-9]+-g[0-9a-fA-F]+") < 0) return -1; @@ -358,7 +358,7 @@ static int retrieve_remote_tracking_reference(git_reference **base_ref, const ch if ((error = git_branch_tracking(&tracking, ref)) < 0) goto cleanup; - + *base_ref = tracking; cleanup: @@ -508,7 +508,7 @@ static int walk_and_search(git_object **out, git_revwalk *walk, regex_t *regex) int error; git_oid oid; git_object *obj; - + while (!(error = git_revwalk_next(&oid, walk))) { error = git_object_lookup(&obj, git_revwalk_repository(walk), &oid, GIT_OBJ_COMMIT); @@ -537,7 +537,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_ if ((error = build_regex(&preg, pattern)) < 0) return error; - + if ((error = git_revwalk_new(&walk, repo)) < 0) goto cleanup; @@ -551,7 +551,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_ goto cleanup; error = walk_and_search(out, walk, &preg); - + cleanup: regfree(&preg); git_revwalk_free(walk); @@ -892,3 +892,55 @@ int git_revparse_rangelike(git_object **left, git_object **right, int *threedots git__free(revspec); return error; } + + +int git_revparse( + git_oid *left, + git_oid *right, + unsigned int *flags, + git_repository *repo, + const char *spec) +{ + unsigned int lflags = 0; + const char *dotdot; + int error = 0; + git_object *obj = NULL; + + assert(left && repo && spec); + + if ((dotdot = strstr(spec, "..")) != NULL) { + char *lstr; + const char *rstr; + lflags = GIT_REVPARSE_RANGE; + + lstr = git__substrdup(spec, dotdot-spec); + rstr = dotdot + 2; + if (dotdot[2] == '.') { + lflags |= GIT_REVPARSE_MERGE_BASE; + rstr++; + } + + if (!(error = git_revparse_single(&obj, repo, lstr))) { + git_oid_cpy(left, git_object_id(obj)); + git_object_free(obj); + } + if (right && !(error = git_revparse_single(&obj, repo, rstr))) { + git_oid_cpy(right, git_object_id(obj)); + git_object_free(obj); + } + + git__free((void*)lstr); + } else { + lflags = GIT_REVPARSE_SINGLE; + if (!(error = git_revparse_single(&obj, repo, spec))) { + git_oid_cpy(left, git_object_id(obj)); + git_object_free(obj); + } + } + + if (flags) + *flags = lflags; + + return error; +} + diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 66ee391a760..ab8839fda4d 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -27,6 +27,37 @@ static void test_object_inrepo(const char *spec, const char *expected_oid, git_r git_object_free(obj); } +static void test_id_inrepo( + const char *spec, + const char *expected_left, + const char *expected_right, + git_revparse_flag_t expected_flags, + git_repository *repo) +{ + git_oid l = {{0}}, r = {{0}}; + git_revparse_flag_t flags = 0; + + int error = git_revparse(&l, &r, &flags, repo, spec); + + if (expected_left) { + char str[64] = {0}; + cl_assert_equal_i(0, error); + git_oid_fmt(str, &l); + cl_assert_equal_s(str, expected_left); + } else { + cl_assert_equal_i(GIT_ENOTFOUND, error); + } + + if (expected_right) { + char str[64] = {0}; + git_oid_fmt(str, &r); + cl_assert_equal_s(str, expected_right); + } + + if (expected_flags) + cl_assert_equal_i(expected_flags, flags); +} + static void test_object(const char *spec, const char *expected_oid) { test_object_inrepo(spec, expected_oid, g_repo); @@ -59,6 +90,15 @@ static void test_rangelike(const char *rangelike, } +static void test_id( + const char *spec, + const char *expected_left, + const char *expected_right, + git_revparse_flag_t expected_flags) +{ + test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo); +} + void test_refs_revparse__initialize(void) { cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); @@ -639,3 +679,22 @@ void test_refs_revparse__range(void) test_rangelike("be3563a^1.be3563a", NULL, NULL, 0); } + +void test_refs_revparse__validates_args(void) +{ + git_oid l={{0}}, r={{0}}; + git_revparse_flag_t flags = 0; + + cl_git_pass(git_revparse(&l,&r,NULL, g_repo, "HEAD")); + cl_git_pass(git_revparse(&l,NULL,&flags, g_repo, "HEAD")); + cl_assert_equal_i(GIT_EINVALIDSPEC, git_revparse(&l,&r,&flags, g_repo, "^&*(")); +} + +void test_refs_revparse__parses_range_operator(void) +{ + test_id("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVPARSE_SINGLE); + test_id("HEAD~3..HEAD", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_REVPARSE_RANGE); + test_id("HEAD~3...HEAD", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); +} + From 7d5b0f8b1f3a9f829847188d2d25b7f47cf00b1c Mon Sep 17 00:00:00 2001 From: Maxwell Swadling Date: Tue, 9 Apr 2013 09:28:40 +1000 Subject: [PATCH 020/181] Updated link to Haskell bindings The old one hasn't been updated in a long time. This one is current. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ab1d05ec8b2..790e202d7de 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Here are the bindings to libgit2 that are currently available: * GObject * libgit2-glib * Haskell - * hgit2 + * hgit2 * Lua * luagit2 * .NET From 1aa21fe3b87a1e601023f49c41fab3ce76c189ac Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Tue, 9 Apr 2013 05:03:51 +0400 Subject: [PATCH 021/181] Deprecate git_revparse_single and _rangelike --- examples/diff.c | 4 +- examples/rev-list.c | 28 ++++++------- include/git2/revparse.h | 25 ------------ include/git2/revwalk.h | 2 +- src/push.c | 23 +++++------ src/revparse.c | 27 +----------- src/revwalk.c | 14 +++---- src/transports/local.c | 7 ++-- tests-clar/checkout/tree.c | 50 +++++++++++++++++------ tests-clar/checkout/typechange.c | 8 +++- tests-clar/clone/nonetwork.c | 9 ++-- tests-clar/refs/revparse.c | 70 ++++++++++++++++++-------------- tests-clar/repo/head.c | 8 +++- tests-clar/reset/default.c | 12 ++++-- tests-clar/stash/drop.c | 19 ++++----- tests-clar/stash/save.c | 16 +++++--- 16 files changed, 156 insertions(+), 166 deletions(-) diff --git a/examples/diff.c b/examples/diff.c index a153b493b8e..6fa0fee5271 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -15,9 +15,11 @@ static int resolve_to_tree( git_repository *repo, const char *identifier, git_tree **tree) { int err = 0; + git_oid oid; git_object *obj = NULL; - if (git_revparse_single(&obj, repo, identifier) < 0) + if (git_revparse(&oid, NULL, NULL, repo, identifier) < 0 || + git_object_lookup(&obj, repo, &oid, GIT_OBJ_ANY) < 0) return GIT_ENOTFOUND; switch (git_object_type(obj)) { diff --git a/examples/rev-list.c b/examples/rev-list.c index b7e466f9eaf..71a8180f75d 100644 --- a/examples/rev-list.c +++ b/examples/rev-list.c @@ -14,48 +14,46 @@ static void check_error(int error_code, const char *action) exit(1); } -static int push_commit(git_revwalk *walk, git_object *obj, int hide) +static int push_commit(git_revwalk *walk, git_oid *oid, int hide) { if (hide) - return git_revwalk_hide(walk, git_object_id(obj)); + return git_revwalk_hide(walk, oid); else - return git_revwalk_push(walk, git_object_id(obj)); + return git_revwalk_push(walk, oid); } static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, int hide) { int error; - git_object *obj; + git_oid oid; - if ((error = git_revparse_single(&obj, repo, spec))) + if ((error = git_revparse(&oid, NULL, NULL, repo, spec))) return error; - return push_commit(walk, obj, hide); + return push_commit(walk, &oid, hide); } static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide) { - git_object *left, *right; - int threedots; + git_oid left, right; + git_revparse_flag_t flags; int error = 0; - if ((error = git_revparse_rangelike(&left, &right, &threedots, repo, range))) + if ((error = git_revparse(&left, &right, &flags, repo, range))) return error; - if (threedots) { + if (flags & GIT_REVPARSE_MERGE_BASE) { /* TODO: support "..." */ return GIT_EINVALIDSPEC; } - if ((error = push_commit(walk, left, !hide))) + if ((error = push_commit(walk, &left, !hide))) goto out; - error = push_commit(walk, right, hide); + error = push_commit(walk, &right, hide); out: - git_object_free(left); - git_object_free(right); return error; } -static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, const char *const *opts) +static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, char **opts) { int hide, i, error; unsigned int sorting = GIT_SORT_NONE; diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 9315b66eb56..7fe910b4514 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -20,31 +20,6 @@ */ GIT_BEGIN_DECL -/** - * Find an object, as specified by a revision string. See `man gitrevisions`, or the documentation - * for `git rev-parse` for information on the syntax accepted. - * - * @param out pointer to output object - * @param repo the repository to search in - * @param spec the textual specification for an object - * @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, - * GIT_EINVALIDSPEC or an error code - */ -GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, const char *spec); - -/** - * Parse a string with the form of a revision range, as accepted by - * `git rev-list`, `git diff`, and others. - * - * @param left (output) the left-hand commit - * @param right (output) the right-hand commit - * @param threedots (output) 0 if the endpoints are separated by two dots, 1 if by three - * @param repo the repository to find the commits in - * @param rangelike the rangelike string to be parsed - * @return 0 on success, or any error `git_revparse_single` can return - */ -GIT_EXTERN(int) git_revparse_rangelike(git_object **left, git_object **right, int *threedots, git_repository *repo, const char *rangelike); - /** * Revparse flags. These indicate the intended behavior of the spec passed to diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index 8bfe0b502da..c9f7372e9df 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -221,7 +221,7 @@ GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode); * * The range should be of the form * .. - * where each is in the form accepted by 'git_revparse_single'. + * where each is in the form accepted by 'git_revparse'. * The left-hand commit will be hidden and the right-hand commit pushed. * * @param walk the walker being used for the traversal diff --git a/src/push.c b/src/push.c index 37f64181279..dcd8122d17e 100644 --- a/src/push.c +++ b/src/push.c @@ -96,21 +96,18 @@ static int check_rref(char *ref) static int check_lref(git_push *push, char *ref) { /* lref must be resolvable to an existing object */ - git_object *obj; - int error = git_revparse_single(&obj, push->repo, ref); - - if (error) { - if (error == GIT_ENOTFOUND) - giterr_set(GITERR_REFERENCE, - "src refspec '%s' does not match any existing object", ref); - else - giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref); + git_oid oid; + int error = git_revparse(&oid, NULL, NULL, push->repo, ref); - return -1; - } else - git_object_free(obj); + if (!error) + return 0; - return 0; + if (error == GIT_ENOTFOUND) + giterr_set(GITERR_REFERENCE, + "src refspec '%s' does not match any existing object", ref); + else + giterr_set(GITERR_INVALID, "Not a valid reference '%s'", ref); + return -1; } static int parse_refspec(git_push *push, push_spec **spec, const char *str) diff --git a/src/revparse.c b/src/revparse.c index 2ba42d8e3ac..7842c49b7e6 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -722,7 +722,7 @@ static int ensure_left_hand_identifier_is_not_known_yet(git_object *object, git_ return GIT_EINVALIDSPEC; } -int git_revparse_single(git_object **out, git_repository *repo, const char *spec) +static int git_revparse_single(git_object **out, git_repository *repo, const char *spec) { size_t pos = 0, identifier_len = 0; int error = -1, n; @@ -868,31 +868,6 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec return error; } -int git_revparse_rangelike(git_object **left, git_object **right, int *threedots, git_repository *repo, const char *rangelike) -{ - int error = 0; - const char *p, *q; - char *revspec; - - p = strstr(rangelike, ".."); - if (!p) { - giterr_set(GITERR_INVALID, "Malformed range (or rangelike syntax): %s", rangelike); - return GIT_EINVALIDSPEC; - } else if (p[2] == '.') { - *threedots = 1; - q = p + 3; - } else { - *threedots = 0; - q = p + 2; - } - - revspec = git__substrdup(rangelike, p - rangelike); - error = (git_revparse_single(left, repo, revspec) - || git_revparse_single(right, repo, q)); - git__free(revspec); - return error; -} - int git_revparse( git_oid *left, diff --git a/src/revwalk.c b/src/revwalk.c index c1071843b2f..b22fef07f3b 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -231,25 +231,23 @@ int git_revwalk_push_ref(git_revwalk *walk, const char *refname) int git_revwalk_push_range(git_revwalk *walk, const char *range) { - git_object *left, *right; - int threedots; + git_oid left, right; + git_revparse_flag_t revparseflags; int error = 0; - if ((error = git_revparse_rangelike(&left, &right, &threedots, walk->repo, range))) + if ((error = git_revparse(&left, &right, &revparseflags, walk->repo, range))) return error; - if (threedots) { + if (revparseflags & GIT_REVPARSE_MERGE_BASE) { /* TODO: support "..." */ giterr_set(GITERR_INVALID, "Symmetric differences not implemented in revwalk"); return GIT_EINVALIDSPEC; } - if ((error = push_commit(walk, git_object_id(left), 1))) + if ((error = push_commit(walk, &left, 1))) goto out; - error = push_commit(walk, git_object_id(right), 0); + error = push_commit(walk, &right, 0); out: - git_object_free(left); - git_object_free(right); return error; } diff --git a/src/transports/local.c b/src/transports/local.c index ce89bb213e5..1e27fc38c28 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -236,14 +236,13 @@ static int local_negotiate_fetch( /* Fill in the loids */ git_vector_foreach(&t->refs, i, rhead) { - git_object *obj; + git_oid oid; - int error = git_revparse_single(&obj, repo, rhead->name); + int error = git_revparse(&oid, NULL, NULL, repo, rhead->name); if (!error) - git_oid_cpy(&rhead->loid, git_object_id(obj)); + git_oid_cpy(&rhead->loid, &oid); else if (error != GIT_ENOTFOUND) return error; - git_object_free(obj); giterr_clear(); } diff --git a/tests-clar/checkout/tree.c b/tests-clar/checkout/tree.c index 5a2eacea19d..ae4087f4167 100644 --- a/tests-clar/checkout/tree.c +++ b/tests-clar/checkout/tree.c @@ -28,8 +28,11 @@ void test_checkout_tree__cleanup(void) void test_checkout_tree__cannot_checkout_a_non_treeish(void) { + git_oid oid; + /* blob */ - cl_git_pass(git_revparse_single(&g_object, g_repo, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd")); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_fail(git_checkout_tree(g_repo, g_object, NULL)); } @@ -37,11 +40,13 @@ void test_checkout_tree__cannot_checkout_a_non_treeish(void) void test_checkout_tree__can_checkout_a_subdirectory_from_a_commit(void) { char *entries[] = { "ab/de/" }; + git_oid oid; g_opts.paths.strings = entries; g_opts.paths.count = 1; - cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees")); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "subtrees")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_assert_equal_i(false, git_path_isdir("./testrepo/ab/")); @@ -53,12 +58,15 @@ void test_checkout_tree__can_checkout_a_subdirectory_from_a_commit(void) void test_checkout_tree__can_checkout_and_remove_directory(void) { + git_oid oid; + cl_assert_equal_i(false, git_path_isdir("./testrepo/ab/")); /* Checkout brach "subtrees" and update HEAD, so that HEAD matches the * current working tree */ - cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees")); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "subtrees")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/subtrees")); @@ -73,7 +81,8 @@ void test_checkout_tree__can_checkout_and_remove_directory(void) /* Checkout brach "master" and update HEAD, so that HEAD matches the * current working tree */ - cl_git_pass(git_revparse_single(&g_object, g_repo, "master")); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "master")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/master")); @@ -85,11 +94,13 @@ void test_checkout_tree__can_checkout_and_remove_directory(void) void test_checkout_tree__can_checkout_a_subdirectory_from_a_subtree(void) { char *entries[] = { "de/" }; + git_oid oid; g_opts.paths.strings = entries; g_opts.paths.count = 1; - cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees:ab")); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "subtrees:ab")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_assert_equal_i(false, git_path_isdir("./testrepo/de/")); @@ -109,11 +120,13 @@ static void progress(const char *path, size_t cur, size_t tot, void *payload) void test_checkout_tree__calls_progress_callback(void) { bool was_called = 0; + git_oid oid; g_opts.progress_cb = progress; g_opts.progress_payload = &was_called; - cl_git_pass(git_revparse_single(&g_object, g_repo, "master")); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "master")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); @@ -277,14 +290,16 @@ void test_checkout_tree__can_update_only(void) void test_checkout_tree__can_checkout_with_pattern(void) { char *entries[] = { "[l-z]*.txt" }; + git_oid oid; /* reset to beginning of history (i.e. just a README file) */ g_opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; - cl_git_pass(git_revparse_single(&g_object, g_repo, + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass( @@ -304,7 +319,8 @@ void test_checkout_tree__can_checkout_with_pattern(void) g_opts.paths.strings = entries; g_opts.paths.count = 1; - cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master")); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "refs/heads/master")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); @@ -317,14 +333,16 @@ void test_checkout_tree__can_checkout_with_pattern(void) void test_checkout_tree__can_disable_pattern_match(void) { char *entries[] = { "b*.txt" }; + git_oid oid; /* reset to beginning of history (i.e. just a README file) */ g_opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; - cl_git_pass(git_revparse_single(&g_object, g_repo, + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass( @@ -342,7 +360,8 @@ void test_checkout_tree__can_disable_pattern_match(void) g_opts.paths.strings = entries; g_opts.paths.count = 1; - cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master")); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "refs/heads/master")); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); @@ -367,11 +386,13 @@ void assert_conflict( git_object *hack_tree; git_reference *branch, *head; git_buf file_path = GIT_BUF_INIT; + git_oid oid; cl_git_pass(git_repository_index(&index, g_repo)); /* Create a branch pointing at the parent */ - cl_git_pass(git_revparse_single(&g_object, g_repo, parent_sha)); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, parent_sha)); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_branch_create(&branch, g_repo, "potential_conflict", (git_commit *)g_object, 0)); @@ -400,7 +421,8 @@ void assert_conflict( git_buf_free(&file_path); /* Trying to checkout the original commit */ - cl_git_pass(git_revparse_single(&g_object, g_repo, commit_sha)); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, commit_sha)); + cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); g_opts.checkout_strategy = GIT_CHECKOUT_SAFE; cl_assert_equal_i( @@ -487,6 +509,7 @@ void test_checkout_tree__issue_1397(void) git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; const char *partial_oid = "8a7ef04"; git_object *tree = NULL; + git_oid oid; test_checkout_tree__cleanup(); /* cleanup default checkout */ @@ -494,7 +517,8 @@ void test_checkout_tree__issue_1397(void) cl_repo_set_bool(g_repo, "core.autocrlf", true); - cl_git_pass(git_revparse_single(&tree, g_repo, partial_oid)); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, partial_oid)); + cl_git_pass(git_object_lookup(&tree, g_repo, &oid, GIT_OBJ_ANY)); opts.checkout_strategy = GIT_CHECKOUT_FORCE; diff --git a/tests-clar/checkout/typechange.c b/tests-clar/checkout/typechange.c index b92cc23fa52..74521312aca 100644 --- a/tests-clar/checkout/typechange.c +++ b/tests-clar/checkout/typechange.c @@ -107,10 +107,12 @@ void test_checkout_typechange__checkout_typechanges_safe(void) { int i; git_object *obj; + git_oid oid; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; for (i = 0; g_typechange_oids[i] != NULL; ++i) { - cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i])); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, g_typechange_oids[i])); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); opts.checkout_strategy = GIT_CHECKOUT_FORCE; @@ -194,6 +196,7 @@ void test_checkout_typechange__checkout_with_conflicts(void) { int i; git_object *obj; + git_oid oid; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; notify_counts cts = {0}; @@ -203,7 +206,8 @@ void test_checkout_typechange__checkout_with_conflicts(void) opts.notify_payload = &cts; for (i = 0; g_typechange_oids[i] != NULL; ++i) { - cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i])); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, g_typechange_oids[i])); + cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); force_create_file("typechanges/a/blocker"); force_create_file("typechanges/b"); diff --git a/tests-clar/clone/nonetwork.c b/tests-clar/clone/nonetwork.c index 2c4cba4eb75..d86c1f4c920 100644 --- a/tests-clar/clone/nonetwork.c +++ b/tests-clar/clone/nonetwork.c @@ -214,23 +214,22 @@ void test_clone_nonetwork__can_checkout_given_branch(void) void test_clone_nonetwork__can_detached_head(void) { - git_object *commit; + git_oid oid; git_repository *cloned; git_reference *cloned_head; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); - cl_git_pass(git_revparse_single(&commit, g_repo, "master~1")); - cl_git_pass(git_repository_set_head_detached(g_repo, git_object_id(commit))); + cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "master~1")); + cl_git_pass(git_repository_set_head_detached(g_repo, &oid)); cl_git_pass(git_clone(&cloned, "./foo", "./foo1", &g_options)); cl_assert(git_repository_head_detached(cloned)); cl_git_pass(git_repository_head(&cloned_head, cloned)); - cl_assert(!git_oid_cmp(git_object_id(commit), git_reference_target(cloned_head))); + cl_assert(!git_oid_cmp(&oid, git_reference_target(cloned_head))); - git_commit_free((git_commit*)commit); git_reference_free(cloned_head); git_repository_free(cloned); diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index ab8839fda4d..39e77c8eb8b 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -6,25 +6,22 @@ #include "path.h" static git_repository *g_repo; -static git_object *g_obj; /* Helpers */ static void test_object_inrepo(const char *spec, const char *expected_oid, git_repository *repo) { char objstr[64] = {0}; - git_object *obj = NULL; + git_oid oid; int error; - error = git_revparse_single(&obj, repo, spec); + error = git_revparse(&oid, NULL, NULL, repo, spec); if (expected_oid != NULL) { cl_assert_equal_i(0, error); - git_oid_fmt(objstr, git_object_id(obj)); + git_oid_fmt(objstr, &oid); cl_assert_equal_s(objstr, expected_oid); } else cl_assert_equal_i(GIT_ENOTFOUND, error); - - git_object_free(obj); } static void test_id_inrepo( @@ -66,27 +63,24 @@ static void test_object(const char *spec, const char *expected_oid) static void test_rangelike(const char *rangelike, const char *expected_left, const char *expected_right, - int expected_threedots) + git_revparse_flag_t expected_revparseflags) { char objstr[64] = {0}; - git_object *left = NULL, *right = NULL; - int threedots; + git_oid left = {{0}}, right = {{0}}; + git_revparse_flag_t revparseflags; int error; - error = git_revparse_rangelike(&left, &right, &threedots, g_repo, rangelike); + error = git_revparse(&left, &right, &revparseflags, g_repo, rangelike); if (expected_left != NULL) { cl_assert_equal_i(0, error); - cl_assert_equal_i(threedots, expected_threedots); - git_oid_fmt(objstr, git_object_id(left)); + cl_assert_equal_i(revparseflags, expected_revparseflags); + git_oid_fmt(objstr, &left); cl_assert_equal_s(objstr, expected_left); - git_oid_fmt(objstr, git_object_id(right)); + git_oid_fmt(objstr, &right); cl_assert_equal_s(objstr, expected_right); } else cl_assert(error != 0); - - git_object_free(left); - git_object_free(right); } @@ -118,8 +112,9 @@ void test_refs_revparse__nonexistant_object(void) static void assert_invalid_spec(const char *invalid_spec) { + git_oid oid; cl_assert_equal_i( - GIT_EINVALIDSPEC, git_revparse_single(&g_obj, g_repo, invalid_spec)); + GIT_EINVALIDSPEC, git_revparse(&oid, NULL, NULL, g_repo, invalid_spec)); } void test_refs_revparse__invalid_reference_name(void) @@ -196,10 +191,12 @@ void test_refs_revparse__not_tag(void) void test_refs_revparse__to_type(void) { + git_oid oid; + assert_invalid_spec("wrapped_tag^{trip}"); test_object("point_to_blob^{commit}", NULL); cl_assert_equal_i( - GIT_EAMBIGUOUS, git_revparse_single(&g_obj, g_repo, "wrapped_tag^{blob}")); + GIT_EAMBIGUOUS, git_revparse(&oid, NULL, NULL, g_repo, "wrapped_tag^{blob}")); test_object("wrapped_tag^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("wrapped_tag^{tree}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); @@ -263,7 +260,8 @@ void test_refs_revparse__ordinal(void) assert_invalid_spec("master@{-2}"); /* TODO: make the test below actually fail - * cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{1a}")); + * git_oid oid; + * cl_git_fail(git_revparse(&oid, NULL, NULL, g_repo, "master@{1a}")); */ test_object("nope@{0}", NULL); @@ -425,9 +423,11 @@ void test_refs_revparse__date(void) void test_refs_revparse__colon(void) { + git_oid oid; + assert_invalid_spec(":/"); assert_invalid_spec("point_to_blob:readme.txt"); - cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); /* Not implemented */ + cl_git_fail(git_revparse(&oid, NULL, NULL, g_repo, ":2:README")); /* Not implemented */ test_object(":/not found in any commit", NULL); test_object("subtrees:ab/42.txt", NULL); @@ -517,8 +517,9 @@ void test_refs_revparse__disambiguation(void) void test_refs_revparse__a_too_short_objectid_returns_EAMBIGUOUS(void) { + git_oid oid; cl_assert_equal_i( - GIT_EAMBIGUOUS, git_revparse_single(&g_obj, g_repo, "e90")); + GIT_EAMBIGUOUS, git_revparse(&oid, NULL, NULL, g_repo, "e90")); } void test_refs_revparse__issue_994(void) @@ -526,14 +527,15 @@ void test_refs_revparse__issue_994(void) git_repository *repo; git_reference *head, *with_at; git_object *target; + git_oid oid; repo = cl_git_sandbox_init("testrepo.git"); cl_assert_equal_i(GIT_ENOTFOUND, - git_revparse_single(&target, repo, "origin/bim_with_3d@11296")); + git_revparse(&oid, NULL, NULL, repo, "origin/bim_with_3d@11296")); cl_assert_equal_i(GIT_ENOTFOUND, - git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296")); + git_revparse(&oid, NULL, NULL, repo, "refs/remotes/origin/bim_with_3d@11296")); cl_git_pass(git_repository_head(&head, repo)); @@ -544,10 +546,12 @@ void test_refs_revparse__issue_994(void) git_reference_target(head), 0)); - cl_git_pass(git_revparse_single(&target, repo, "origin/bim_with_3d@11296")); + cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "origin/bim_with_3d@11296")); + cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); git_object_free(target); - cl_git_pass(git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296")); + cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "refs/remotes/origin/bim_with_3d@11296")); + cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); git_object_free(target); git_reference_free(with_at); @@ -573,12 +577,14 @@ void test_refs_revparse__try_to_retrieve_branch_before_described_tag(void) git_reference *branch; git_object *target; char sha[GIT_OID_HEXSZ + 1]; + git_oid oid; repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("blah-7-gc47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd", repo); - cl_git_pass(git_revparse_single(&target, repo, "HEAD~3")); + cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "HEAD~3")); + cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); cl_git_pass(git_branch_create(&branch, repo, "blah-7-gc47800c", (git_commit *)target, 0)); git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target)); @@ -611,12 +617,14 @@ void test_refs_revparse__try_to_retrieve_sha_before_branch(void) git_reference *branch; git_object *target; char sha[GIT_OID_HEXSZ + 1]; + git_oid oid; repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); - cl_git_pass(git_revparse_single(&target, repo, "HEAD~3")); + cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "HEAD~3")); + cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); cl_git_pass(git_branch_create(&branch, repo, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", (git_commit *)target, 0)); git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target)); @@ -647,12 +655,14 @@ void test_refs_revparse__try_to_retrieve_branch_before_abbrev_sha(void) git_reference *branch; git_object *target; char sha[GIT_OID_HEXSZ + 1]; + git_oid oid; repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("c47800", "c47800c7266a2be04c571c04d5a6614691ea99bd", repo); - cl_git_pass(git_revparse_single(&target, repo, "HEAD~3")); + cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "HEAD~3")); + cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); cl_git_pass(git_branch_create(&branch, repo, "c47800", (git_commit *)target, 0)); git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target)); @@ -670,12 +680,12 @@ void test_refs_revparse__range(void) test_rangelike("be3563a^1..be3563a", "9fd738e8f7967c078dceed8190330fc8648ee56a", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", - 0); + GIT_REVPARSE_RANGE); test_rangelike("be3563a^1...be3563a", "9fd738e8f7967c078dceed8190330fc8648ee56a", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", - 1); + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); test_rangelike("be3563a^1.be3563a", NULL, NULL, 0); } diff --git a/tests-clar/repo/head.c b/tests-clar/repo/head.c index a9f5cfc58d7..bb81bb087d4 100644 --- a/tests-clar/repo/head.c +++ b/tests-clar/repo/head.c @@ -120,9 +120,11 @@ void test_repo_head__set_head_detached_Return_ENOTFOUND_when_the_object_doesnt_e void test_repo_head__set_head_detached_Fails_when_the_object_isnt_a_commitish(void) { + git_oid oid; git_object *blob; - cl_git_pass(git_revparse_single(&blob, repo, "point_to_blob")); + cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "point_to_blob")); + cl_git_pass(git_object_lookup(&blob, repo, &oid, GIT_OBJ_ANY)); cl_git_fail(git_repository_set_head_detached(repo, git_object_id(blob))); @@ -131,9 +133,11 @@ void test_repo_head__set_head_detached_Fails_when_the_object_isnt_a_commitish(vo void test_repo_head__set_head_detached_Detaches_HEAD_and_make_it_point_to_the_peeled_commit(void) { + git_oid oid; git_object *tag; - cl_git_pass(git_revparse_single(&tag, repo, "tags/test")); + cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "tags/test")); + cl_git_pass(git_object_lookup(&tag, repo, &oid, GIT_OBJ_ANY)); cl_assert_equal_i(GIT_OBJ_TAG, git_object_type(tag)); cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag))); diff --git a/tests-clar/reset/default.c b/tests-clar/reset/default.c index 506d971ffba..bc8da739204 100644 --- a/tests-clar/reset/default.c +++ b/tests-clar/reset/default.c @@ -95,6 +95,7 @@ void test_reset_default__resetting_filepaths_against_a_null_target_removes_them_ void test_reset_default__resetting_filepaths_replaces_their_corresponding_index_entries(void) { git_strarray before, after; + git_oid oid; char *paths[] = { "staged_changes", "staged_changes_file_deleted" }; char *before_shas[] = { "55d316c9ba708999f1918e9677d01dfcae69c6b9", @@ -109,7 +110,8 @@ void test_reset_default__resetting_filepaths_replaces_their_corresponding_index_ after.strings = after_shas; after.count = 2; - cl_git_pass(git_revparse_single(&_target, _repo, "0017bd4")); + cl_git_pass(git_revparse(&oid, NULL, NULL, _repo, "0017bd4")); + cl_git_pass(git_object_lookup(&_target, _repo, &oid, GIT_OBJ_ANY)); assert_content_in_index(&_pathspecs, true, &before); cl_git_pass(git_reset_default(_repo, _target, &_pathspecs)); @@ -135,6 +137,7 @@ void test_reset_default__resetting_filepaths_clears_previous_conflicts(void) { git_index_entry *conflict_entry[3]; git_strarray after; + git_oid oid; char *paths[] = { "conflicts-one.txt" }; char *after_shas[] = { "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81" }; @@ -150,7 +153,8 @@ void test_reset_default__resetting_filepaths_clears_previous_conflicts(void) cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], _index, "conflicts-one.txt")); - cl_git_pass(git_revparse_single(&_target, _repo, "9a05ccb")); + cl_git_pass(git_revparse(&oid, NULL, NULL, _repo, "9a05ccb")); + cl_git_pass(git_object_lookup(&_target, _repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_reset_default(_repo, _target, &_pathspecs)); assert_content_in_index(&_pathspecs, true, &after); @@ -167,13 +171,15 @@ Unstaged changes after reset: void test_reset_default__resetting_unknown_filepaths_does_not_fail(void) { char *paths[] = { "I_am_not_there.txt", "me_neither.txt" }; + git_oid oid; _pathspecs.strings = paths; _pathspecs.count = 2; assert_content_in_index(&_pathspecs, false, NULL); - cl_git_pass(git_revparse_single(&_target, _repo, "HEAD")); + cl_git_pass(git_revparse(&oid, NULL, NULL, _repo, "HEAD")); + cl_git_pass(git_object_lookup(&_target, _repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_reset_default(_repo, _target, &_pathspecs)); assert_content_in_index(&_pathspecs, false, NULL); diff --git a/tests-clar/stash/drop.c b/tests-clar/stash/drop.c index d171390daf1..da9e676a977 100644 --- a/tests-clar/stash/drop.c +++ b/tests-clar/stash/drop.c @@ -140,35 +140,30 @@ void test_stash_drop__dropping_the_last_entry_removes_the_stash(void) void retrieve_top_stash_id(git_oid *out) { - git_object *top_stash; + git_oid top_stash_id; - cl_git_pass(git_revparse_single(&top_stash, repo, "stash@{0}")); + cl_git_pass(git_revparse(&top_stash_id, NULL, NULL, repo, "stash@{0}")); 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); + cl_assert_equal_i(true, git_oid_cmp(out, &top_stash_id) == 0); } void test_stash_drop__dropping_the_top_stash_updates_the_stash_reference(void) { - git_object *next_top_stash; + git_oid next_top_stash_id; git_oid oid; push_three_states(); retrieve_top_stash_id(&oid); - cl_git_pass(git_revparse_single(&next_top_stash, repo, "stash@{1}")); - cl_assert_equal_i( - false, git_oid_cmp(&oid, git_object_id(next_top_stash)) == 0); + cl_git_pass(git_revparse(&next_top_stash_id, NULL, NULL, repo, "stash@{1}")); + cl_assert_equal_i(false, git_oid_cmp(&oid, &next_top_stash_id) == 0); cl_git_pass(git_stash_drop(repo, 0)); retrieve_top_stash_id(&oid); cl_assert_equal_i( - true, git_oid_cmp(&oid, git_object_id(next_top_stash)) == 0); - - git_object_free(next_top_stash); + true, git_oid_cmp(&oid, &next_top_stash_id) == 0); } diff --git a/tests-clar/stash/save.c b/tests-clar/stash/save.c index 588dfc3ea71..4185e549c54 100644 --- a/tests-clar/stash/save.c +++ b/tests-clar/stash/save.c @@ -37,10 +37,11 @@ void test_stash_save__cleanup(void) static void assert_object_oid(const char* revision, const char* expected_oid, git_otype type) { - git_object *object; + git_oid oid; int result; + git_object *obj; - result = git_revparse_single(&object, repo, revision); + result = git_revparse(&oid, NULL, NULL, repo, revision); if (!expected_oid) { cl_assert_equal_i(GIT_ENOTFOUND, result); @@ -48,10 +49,11 @@ static void assert_object_oid(const char* revision, const char* expected_oid, gi } else cl_assert_equal_i(0, result); - cl_assert_equal_i(type, git_object_type(object)); - cl_git_pass(git_oid_streq(git_object_id(object), expected_oid)); + cl_git_pass(git_oid_streq(&oid, expected_oid)); - git_object_free(object); + cl_git_pass(git_object_lookup(&obj, repo, &oid, GIT_OBJ_ANY)); + cl_assert_equal_i(type, git_object_type(obj)); + git_object_free(obj); } static void assert_blob_oid(const char* revision, const char* expected_oid) @@ -145,9 +147,11 @@ void test_stash_save__can_keep_index(void) static void assert_commit_message_contains(const char *revision, const char *fragment) { + git_oid oid; git_commit *commit; - cl_git_pass(git_revparse_single(((git_object **)&commit), repo, revision)); + cl_git_pass(git_revparse(&oid, NULL, NULL, repo, revision)); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); cl_assert(strstr(git_commit_message(commit), fragment) != NULL); From ec7e240ba4a3277a94def51005d2558d02cb8c3c Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Tue, 9 Apr 2013 05:07:12 +0400 Subject: [PATCH 022/181] Add rev-list example to makefiles --- CMakeLists.txt | 3 +++ examples/Makefile | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dfca7363097..6bd25aacc99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -388,4 +388,7 @@ IF (BUILD_EXAMPLES) ADD_EXECUTABLE(git-showindex examples/showindex.c) TARGET_LINK_LIBRARIES(git-showindex git2) + + ADD_EXECUTABLE(git-rev-list examples/rev-list.c) + TARGET_LINK_LIBRARIES(git-rev-list git2) ENDIF () diff --git a/examples/Makefile b/examples/Makefile index b306d4800b2..2c18731fdaa 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -3,7 +3,7 @@ CC = gcc CFLAGS = -g -I../include -I../src -Wall -Wextra -Wmissing-prototypes -Wno-missing-field-initializers LFLAGS = -L../build -lgit2 -lz -APPS = general showindex diff +APPS = general showindex diff rev-list all: $(APPS) From 94750e8af246b2adf7bd5766e7e0da5fcf928d24 Mon Sep 17 00:00:00 2001 From: Linquize Date: Fri, 29 Mar 2013 11:52:18 +0800 Subject: [PATCH 023/181] Fix submodule dirty states not showing if submodules comes before files, or there are only dirty submodules but no changed files GIT_DIFF_PATCH_DIFFABLE was not set, so the diff content was not shown When submodule is dirty, the hash may be the same, but the length is different because -dirty is appended We can therefore compare the length or hash --- src/diff_output.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/diff_output.c b/src/diff_output.c index e8dd5b3172e..d462142f997 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -678,7 +678,8 @@ static int diff_patch_load( if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0 && delta->status != GIT_DELTA_UNMODIFIED && (patch->old_data.len || patch->new_data.len) && - !git_oid_equal(&delta->old_file.oid, &delta->new_file.oid)) + ((patch->old_data.len != patch->new_data.len) || + !git_oid_equal(&delta->old_file.oid, &delta->new_file.oid))) patch->flags |= GIT_DIFF_PATCH_DIFFABLE; } From 9da187e83d1b8ab513a43fd54a9fe2be11b1703f Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 9 Apr 2013 11:40:00 -0700 Subject: [PATCH 024/181] Fix clang warnings and improve checks --- examples/network/fetch.c | 10 +++++++--- examples/network/index-pack.c | 7 ++++--- examples/network/ls-remote.c | 8 ++++++-- src/date.c | 4 ++-- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/examples/network/fetch.c b/examples/network/fetch.c index d5caad4de27..6020ec6ecc7 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -16,7 +16,7 @@ struct dl_data { static void progress_cb(const char *str, int len, void *data) { - data = data; + (void)data; printf("remote: %.*s", len, str); fflush(stdout); /* We don't have the \n to force the flush */ } @@ -50,7 +50,7 @@ static void *download(void *ptr) static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) { char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1]; - data = data; + (void)data; git_oid_fmt(b_str, b); b_str[GIT_OID_HEXSZ] = '\0'; @@ -76,7 +76,11 @@ int fetch(git_repository *repo, int argc, char **argv) pthread_t worker; #endif - argc = argc; + if (argc < 2) { + fprintf(stderr, "usage: %s fetch \n", argv[-1]); + return EXIT_FAILURE; + } + // Figure out whether it's a named remote or a URL printf("Fetching %s for repo %p\n", argv[1], repo); if (git_remote_load(&remote, repo, argv[1]) < 0) { diff --git a/examples/network/index-pack.c b/examples/network/index-pack.c index 3fc4f328857..889305da824 100644 --- a/examples/network/index-pack.c +++ b/examples/network/index-pack.c @@ -23,7 +23,7 @@ // the indexing to finish in a worker thread static int index_cb(const git_transfer_progress *stats, void *data) { - data = data; + (void)data; printf("\rProcessing %d of %d", stats->indexed_objects, stats->total_objects); return 0; @@ -39,9 +39,10 @@ int index_pack(git_repository *repo, int argc, char **argv) ssize_t read_bytes; char buf[512]; - repo = repo; + (void)repo; + if (argc < 2) { - fprintf(stderr, "I need a packfile\n"); + fprintf(stderr, "usage: %s index-pack \n", argv[-1]); return EXIT_FAILURE; } diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c index 737eeacd396..25201182831 100644 --- a/examples/network/ls-remote.c +++ b/examples/network/ls-remote.c @@ -8,7 +8,7 @@ static int show_ref__cb(git_remote_head *head, void *payload) { char oid[GIT_OID_HEXSZ + 1] = {0}; - payload = payload; + (void)payload; git_oid_fmt(oid, &head->oid); printf("%s\t%s\n", oid, head->name); return 0; @@ -67,7 +67,11 @@ int ls_remote(git_repository *repo, int argc, char **argv) { int error; - argc = argc; + if (argc < 2) { + fprintf(stderr, "usage: %s ls-remote \n", argv[-1]); + return EXIT_FAILURE; + } + /* If there's a ':' in the name, assume it's an URL */ if (strchr(argv[1], ':') != NULL) { error = use_unnamed(repo, argv[1]); diff --git a/src/date.c b/src/date.c index bbf88eb44bb..ce1721a0b6b 100644 --- a/src/date.c +++ b/src/date.c @@ -681,8 +681,8 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm const char *end = date; int i; - while (isalpha(*++end)); - ; + while (isalpha(*++end)) + /* scan to non-alpha */; for (i = 0; i < 12; i++) { size_t match = match_string(date, month_names[i]); From ad26434b3b8a5eafab8ec52b83aa99beaf48fb03 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 9 Apr 2013 14:52:32 -0700 Subject: [PATCH 025/181] Tests and more fixes for submodule diffs This adds tests for diffs with submodules in them and (perhaps unsurprisingly) requires further fixes to be made. Specifically, this fixes: - when considering if a submodule is dirty in the workdir, it was being treated as dirty even if only the index was dirty. - git_diff_patch_to_str (and git_diff_patch_print) were "printing" the headers for files (and submodules) that were unmodified or had no meaningful content. - added comment to previous fix and removed unneeded parens. --- include/git2/submodule.h | 23 ++++- src/diff.c | 6 +- src/diff_output.c | 13 ++- tests-clar/diff/submodules.c | 168 +++++++++++++++++++++++++++++++++ tests-clar/status/submodules.c | 3 +- 5 files changed, 205 insertions(+), 8 deletions(-) create mode 100644 tests-clar/diff/submodules.c diff --git a/include/git2/submodule.h b/include/git2/submodule.h index 1abd33e79f0..40934b3ed4d 100644 --- a/include/git2/submodule.h +++ b/include/git2/submodule.h @@ -119,11 +119,28 @@ typedef enum { GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13), } git_submodule_status_t; -#define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \ - (((S) & ~(GIT_SUBMODULE_STATUS_IN_HEAD | \ +#define GIT_SUBMODULE_STATUS__IN_FLAGS \ + (GIT_SUBMODULE_STATUS_IN_HEAD | \ GIT_SUBMODULE_STATUS_IN_INDEX | \ GIT_SUBMODULE_STATUS_IN_CONFIG | \ - GIT_SUBMODULE_STATUS_IN_WD)) == 0) + GIT_SUBMODULE_STATUS_IN_WD) + +#define GIT_SUBMODULE_STATUS__INDEX_FLAGS \ + (GIT_SUBMODULE_STATUS_INDEX_ADDED | \ + GIT_SUBMODULE_STATUS_INDEX_DELETED | \ + GIT_SUBMODULE_STATUS_INDEX_MODIFIED) + +#define GIT_SUBMODULE_STATUS__WD_FLAGS \ + ~(GIT_SUBMODULE_STATUS__IN_FLAGS | GIT_SUBMODULE_STATUS__INDEX_FLAGS) + +#define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \ + (((S) & ~GIT_SUBMODULE_STATUS__IN_FLAGS) == 0) + +#define GIT_SUBMODULE_STATUS_IS_INDEX_UNMODIFIED(S) \ + (((S) & GIT_SUBMODULE_STATUS__INDEX_FLAGS) == 0) + +#define GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(S) \ + (((S) & GIT_SUBMODULE_STATUS__WD_FLAGS) == 0) #define GIT_SUBMODULE_STATUS_IS_WD_DIRTY(S) \ (((S) & (GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED | \ diff --git a/src/diff.c b/src/diff.c index 7152683e7dc..37c89f3f108 100644 --- a/src/diff.c +++ b/src/diff.c @@ -542,7 +542,11 @@ static int maybe_modified( unsigned int sm_status = 0; if (git_submodule_status(&sm_status, sub) < 0) return -1; - status = GIT_SUBMODULE_STATUS_IS_UNMODIFIED(sm_status) + + /* check IS_WD_UNMODIFIED because this case is only used + * when the new side of the diff is the working directory + */ + status = GIT_SUBMODULE_STATUS_IS_WD_UNMODIFIED(sm_status) ? GIT_DELTA_UNMODIFIED : GIT_DELTA_MODIFIED; /* grab OID while we are here */ diff --git a/src/diff_output.c b/src/diff_output.c index d462142f997..34a3e506c6a 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -675,11 +675,14 @@ static int diff_patch_load( if (!error) { patch->flags |= GIT_DIFF_PATCH_LOADED; + /* patch is diffable only for non-binary, modified files where at + * least one side has data and there is actual change in the data + */ if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0 && delta->status != GIT_DELTA_UNMODIFIED && (patch->old_data.len || patch->new_data.len) && - ((patch->old_data.len != patch->new_data.len) || - !git_oid_equal(&delta->old_file.oid, &delta->new_file.oid))) + (patch->old_data.len != patch->new_data.len || + !git_oid_equal(&delta->old_file.oid, &delta->new_file.oid))) patch->flags |= GIT_DIFF_PATCH_DIFFABLE; } @@ -1150,7 +1153,11 @@ static int print_patch_file( GIT_UNUSED(progress); - if (S_ISDIR(delta->new_file.mode)) + if (S_ISDIR(delta->new_file.mode) || + delta->status == GIT_DELTA_UNMODIFIED || + delta->status == GIT_DELTA_IGNORED || + (delta->status == GIT_DELTA_UNTRACKED && + (pi->diff->opts.flags & GIT_DIFF_INCLUDE_UNTRACKED_CONTENT) == 0)) return 0; if (!oldpfx) diff --git a/tests-clar/diff/submodules.c b/tests-clar/diff/submodules.c new file mode 100644 index 00000000000..f152af46fa0 --- /dev/null +++ b/tests-clar/diff/submodules.c @@ -0,0 +1,168 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "../submodule/submodule_helpers.h" + +static git_repository *g_repo = NULL; + +static void setup_submodules(void) +{ + g_repo = cl_git_sandbox_init("submodules"); + cl_fixture_sandbox("testrepo.git"); + rewrite_gitmodules(git_repository_workdir(g_repo)); + p_rename("submodules/testrepo/.gitted", "submodules/testrepo/.git"); +} + +static void setup_submodules2(void) +{ + g_repo = cl_git_sandbox_init("submod2"); + + cl_fixture_sandbox("submod2_target"); + p_rename("submod2_target/.gitted", "submod2_target/.git"); + + rewrite_gitmodules(git_repository_workdir(g_repo)); + p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git"); + p_rename("submod2/not/.gitted", "submod2/not/.git"); +} + +void test_diff_submodules__initialize(void) +{ +} + +void test_diff_submodules__cleanup(void) +{ + cl_git_sandbox_cleanup(); + + cl_fixture_cleanup("testrepo.git"); + cl_fixture_cleanup("submod2_target"); +} + +static void check_diff_patches(git_diff_list *diff, const char **expected) +{ + const git_diff_delta *delta; + git_diff_patch *patch = NULL; + size_t d, num_d = git_diff_num_deltas(diff); + char *patch_text; + + for (d = 0; d < num_d; ++d, git_diff_patch_free(patch)) { + cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); + + if (delta->status == GIT_DELTA_UNMODIFIED) + continue; + + if (expected[d] && !strcmp(expected[d], "")) + continue; + if (expected[d] && !strcmp(expected[d], "")) + cl_assert(0); + + cl_git_pass(git_diff_patch_to_str(&patch_text, patch)); + + cl_assert_equal_s(expected[d], patch_text); + git__free(patch_text); + } + + cl_assert(expected[d] && !strcmp(expected[d], "")); +} + +void test_diff_submodules__unmodified_submodule(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + static const char *expected[] = { + "", /* .gitmodules */ + NULL, /* added */ + NULL, /* ignored */ + "diff --git a/modified b/modified\nindex 092bfb9..452216e 100644\n--- a/modified\n+++ b/modified\n@@ -1 +1,2 @@\n-yo\n+changed\n+\n", /* modified */ + NULL, /* testrepo.git */ + NULL, /* unmodified */ + NULL, /* untracked */ + "" + }; + + setup_submodules(); + + opts.flags = GIT_DIFF_INCLUDE_IGNORED | + GIT_DIFF_INCLUDE_UNTRACKED | + GIT_DIFF_INCLUDE_UNMODIFIED; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + check_diff_patches(diff, expected); + git_diff_list_free(diff); +} + +void test_diff_submodules__dirty_submodule(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + static const char *expected[] = { + "", /* .gitmodules */ + NULL, /* added */ + NULL, /* ignored */ + "diff --git a/modified b/modified\nindex 092bfb9..452216e 100644\n--- a/modified\n+++ b/modified\n@@ -1 +1,2 @@\n-yo\n+changed\n+\n", /* modified */ + "diff --git a/testrepo b/testrepo\nindex a65fedf..a65fedf 160000\n--- a/testrepo\n+++ b/testrepo\n@@ -1 +1 @@\n-Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750\n+Subproject commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750-dirty\n", /* testrepo.git */ + NULL, /* unmodified */ + NULL, /* untracked */ + "" + }; + + setup_submodules(); + + cl_git_rewritefile("submodules/testrepo/README", "heyheyhey"); + cl_git_mkfile("submodules/testrepo/all_new.txt", "never seen before"); + + opts.flags = GIT_DIFF_INCLUDE_IGNORED | + GIT_DIFF_INCLUDE_UNTRACKED | + GIT_DIFF_INCLUDE_UNMODIFIED; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + check_diff_patches(diff, expected); + git_diff_list_free(diff); +} + +void test_diff_submodules__submod2_index_to_wd(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + static const char *expected[] = { + "", /* .gitmodules */ + NULL, /* not-submodule */ + NULL, /* not */ + "diff --git a/sm_changed_file b/sm_changed_file\nindex 4800958..4800958 160000\n--- a/sm_changed_file\n+++ b/sm_changed_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_file */ + "diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */ + "diff --git a/sm_changed_index b/sm_changed_index\nindex 4800958..4800958 160000\n--- a/sm_changed_index\n+++ b/sm_changed_index\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_index */ + "diff --git a/sm_changed_untracked_file b/sm_changed_untracked_file\nindex 4800958..4800958 160000\n--- a/sm_changed_untracked_file\n+++ b/sm_changed_untracked_file\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0-dirty\n", /* sm_changed_untracked_file */ + "diff --git a/sm_missing_commits b/sm_missing_commits\nindex 4800958..5e49635 160000\n--- a/sm_missing_commits\n+++ b/sm_missing_commits\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 5e4963595a9774b90524d35a807169049de8ccad\n", /* sm_missing_commits */ + "" + }; + + setup_submodules2(); + + opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; + + cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + check_diff_patches(diff, expected); + git_diff_list_free(diff); +} + +void test_diff_submodules__submod2_head_to_index(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_tree *head; + git_diff_list *diff = NULL; + static const char *expected[] = { + "", /* .gitmodules */ + "diff --git a/sm_added_and_uncommited b/sm_added_and_uncommited\nnew file mode 160000\nindex 0000000..4800958\n--- /dev/null\n+++ b/sm_added_and_uncommited\n@@ -0,0 +1 @@\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n", /* sm_added_and_uncommited */ + "" + }; + + setup_submodules2(); + + cl_git_pass(git_repository_head_tree(&head, g_repo)); + + opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; + + cl_git_pass(git_diff_tree_to_index(&diff, g_repo, head, NULL, &opts)); + check_diff_patches(diff, expected); + git_diff_list_free(diff); + + git_tree_free(head); +} diff --git a/tests-clar/status/submodules.c b/tests-clar/status/submodules.c index 4656a87e31f..8365a7f5a7a 100644 --- a/tests-clar/status/submodules.c +++ b/tests-clar/status/submodules.c @@ -165,7 +165,7 @@ void test_status_submodules__moved_head(void) cl_git_pass( git_status_foreach_ext(g_repo, &opts, cb_status__match, &counts)); cl_assert_equal_i(6, counts.entry_count); - + git_repository_free(smrepo); } @@ -219,3 +219,4 @@ void test_status_submodules__dirty_workdir_only(void) git_status_foreach_ext(g_repo, &opts, cb_status__match, &counts)); cl_assert_equal_i(6, counts.entry_count); } + From 0d3ccf0b28edb9daa5313e27149ca746b4a88c04 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 10 Apr 2013 16:41:05 +0200 Subject: [PATCH 026/181] examples: Don't print weird characters --- examples/general.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/general.c b/examples/general.c index a65295f985f..adc7ed8d2f8 100644 --- a/examples/general.c +++ b/examples/general.c @@ -76,8 +76,7 @@ int main (int argc, char** argv) git_oid_fromstr(&oid, hex); // Once we've converted the string into the oid value, we can get the raw - // value of the SHA. - printf("Raw 20 bytes: [%.20s]\n", (&oid)->id); + // value of the SHA by accessing `oid.id` // Next we will convert the 20 byte raw SHA1 value to a human readable 40 // char hex value. From 575a54db856947aeb4fc5cf1977844d22dfa1aab Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 10 Apr 2013 16:55:29 +0200 Subject: [PATCH 027/181] object: Export git_object_dup --- include/git2/object.h | 9 +++++++++ src/iterator.c | 2 +- src/object.c | 8 +++++++- src/object.h | 7 ------- src/refs.c | 2 +- src/revparse.c | 2 +- src/tree.h | 5 ----- 7 files changed, 19 insertions(+), 16 deletions(-) diff --git a/include/git2/object.h b/include/git2/object.h index e029f01254b..b91b04dbab4 100644 --- a/include/git2/object.h +++ b/include/git2/object.h @@ -188,6 +188,15 @@ GIT_EXTERN(int) git_object_peel( const git_object *object, git_otype target_type); +/** + * Create an in-memory copy of a Git object. The copy must be + * explicitly free'd or it will leak. + * + * @param dest Pointer to store the copy of the object + * @param source Original object to copy + */ +GIT_EXTERN(int) git_object_dup(git_object **dest, git_object *source); + /** @} */ GIT_END_DECL diff --git a/src/iterator.c b/src/iterator.c index 805a3c987ac..5b5ed95259f 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -578,7 +578,7 @@ int git_iterator_for_tree( if (tree == NULL) return git_iterator_for_nothing(iter, flags, start, end); - if ((error = git_tree__dup(&tree, tree)) < 0) + if ((error = git_object_dup((git_object **)&tree, (git_object *)tree)) < 0) return error; ITERATOR_BASE_INIT(ti, tree, TREE, git_tree_owner(tree)); diff --git a/src/object.c b/src/object.c index f59e4c7dad1..80fe5115218 100644 --- a/src/object.c +++ b/src/object.c @@ -360,7 +360,7 @@ int git_object_peel( assert(object && peeled); if (git_object_type(object) == target_type) - return git_object__dup(peeled, (git_object *)object); + return git_object_dup(peeled, (git_object *)object); source = (git_object *)object; @@ -396,3 +396,9 @@ int git_object_peel( return error; } +int git_object_dup(git_object **dest, git_object *source) +{ + git_cached_obj_incref(source); + *dest = source; + return 0; +} diff --git a/src/object.h b/src/object.h index 8788caba6a7..c1e50593c0f 100644 --- a/src/object.h +++ b/src/object.h @@ -17,13 +17,6 @@ struct git_object { /* fully free the object; internal method, DO NOT EXPORT */ void git_object__free(void *object); -GIT_INLINE(int) git_object__dup(git_object **dest, git_object *source) -{ - git_cached_obj_incref(source); - *dest = source; - return 0; -} - int git_object__from_odb_object( git_object **object_out, git_repository *repo, diff --git a/src/refs.c b/src/refs.c index dde2f51a9cc..b1f679632a4 100644 --- a/src/refs.c +++ b/src/refs.c @@ -934,7 +934,7 @@ int git_reference_peel( } if (target_type == GIT_OBJ_ANY && git_object_type(target) != GIT_OBJ_TAG) - error = git_object__dup(peeled, target); + error = git_object_dup(peeled, target); else error = git_object_peel(peeled, target, target_type); diff --git a/src/revparse.c b/src/revparse.c index 2ba29383e4d..b1eb51b41ab 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -432,7 +432,7 @@ static int dereference_to_non_tag(git_object **out, git_object *obj) if (git_object_type(obj) == GIT_OBJ_TAG) return git_tag_peel(out, (git_tag *)obj); - return git_object__dup(out, obj); + return git_object_dup(out, obj); } static int handle_caret_parent_syntax(git_object **out, git_object *obj, int n) diff --git a/src/tree.h b/src/tree.h index 567b5842d79..b77bfd9616f 100644 --- a/src/tree.h +++ b/src/tree.h @@ -30,11 +30,6 @@ struct git_treebuilder { size_t entrycount; /* vector may contain "removed" entries */ }; -GIT_INLINE(int) git_tree__dup(git_tree **dest, git_tree *source) -{ - return git_object__dup((git_object **)dest, (git_object *)source); -} - GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) { return (S_ISDIR(e->attr) && !S_ISGITLINK(e->attr)); From 0d32f39eb821dfec2e241ea633c0a6e94c21519d Mon Sep 17 00:00:00 2001 From: yorah Date: Mon, 4 Mar 2013 11:31:50 +0100 Subject: [PATCH 028/181] Notify '*' pathspec correctly when diffing I also moved all tests related to notifying in their own file. --- src/attr_file.c | 24 +++- src/attr_file.h | 1 + src/pathspec.c | 25 +++-- src/pathspec.h | 2 +- tests-clar/diff/notify.c | 228 ++++++++++++++++++++++++++++++++++++++ tests-clar/diff/workdir.c | 163 --------------------------- 6 files changed, 268 insertions(+), 175 deletions(-) create mode 100644 tests-clar/diff/notify.c diff --git a/src/attr_file.c b/src/attr_file.c index 74bd2133fa9..85cd87624b3 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -8,6 +8,10 @@ static int sort_by_hash_and_name(const void *a_raw, const void *b_raw); static void git_attr_rule__clear(git_attr_rule *rule); +static bool parse_optimized_patterns( + git_attr_fnmatch *spec, + git_pool *pool, + const char *pattern); int git_attr_file__new( git_attr_file **attrs_ptr, @@ -296,7 +300,6 @@ void git_attr_path__free(git_attr_path *info) info->basename = NULL; } - /* * From gitattributes(5): * @@ -345,6 +348,9 @@ int git_attr_fnmatch__parse( assert(spec && base && *base); + if (parse_optimized_patterns(spec, pool, *base)) + return 0; + spec->flags = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE); allow_space = (spec->flags != 0); @@ -430,6 +436,22 @@ int git_attr_fnmatch__parse( return 0; } +static bool parse_optimized_patterns( + git_attr_fnmatch *spec, + git_pool *pool, + const char *pattern) +{ + if (!pattern[1] && (pattern[0] == '*' || pattern[0] == '.')) { + spec->flags = GIT_ATTR_FNMATCH_MATCH_ALL; + spec->pattern = git_pool_strndup(pool, pattern, 1); + spec->length = 1; + + return true; + } + + return false; +} + static int sort_by_hash_and_name(const void *a_raw, const void *b_raw) { const git_attr_name *a = a_raw; diff --git a/src/attr_file.h b/src/attr_file.h index 2cc8546a2eb..d8abcda58e9 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -27,6 +27,7 @@ #define GIT_ATTR_FNMATCH_HASWILD (1U << 5) #define GIT_ATTR_FNMATCH_ALLOWSPACE (1U << 6) #define GIT_ATTR_FNMATCH_ICASE (1U << 7) +#define GIT_ATTR_FNMATCH_MATCH_ALL (1U << 8) extern const char *git_attr__true; extern const char *git_attr__false; diff --git a/src/pathspec.c b/src/pathspec.c index 7321802487f..d4eb12582c5 100644 --- a/src/pathspec.c +++ b/src/pathspec.c @@ -38,18 +38,20 @@ char *git_pathspec_prefix(const git_strarray *pathspec) } /* is there anything in the spec that needs to be filtered on */ -bool git_pathspec_is_interesting(const git_strarray *pathspec) +bool git_pathspec_is_empty(const git_strarray *pathspec) { - const char *str; + size_t i; - if (pathspec == NULL || pathspec->count == 0) - return false; - if (pathspec->count > 1) + if (pathspec == NULL) return true; - str = pathspec->strings[0]; - if (!str || !str[0] || (!str[1] && (str[0] == '*' || str[0] == '.'))) - return false; + for (i = 0; i < pathspec->count; ++i) { + const char *str = pathspec->strings[i]; + + if (str && str[0]) + return false; + } + return true; } @@ -61,7 +63,7 @@ int git_pathspec_init( memset(vspec, 0, sizeof(*vspec)); - if (!git_pathspec_is_interesting(strspec)) + if (git_pathspec_is_empty(strspec)) return 0; if (git_vector_init(vspec, strspec->count, NULL) < 0) @@ -138,7 +140,10 @@ bool git_pathspec_match_path( } git_vector_foreach(vspec, i, match) { - int result = use_strcmp(match->pattern, path) ? FNM_NOMATCH : 0; + int result = (match->flags & GIT_ATTR_FNMATCH_MATCH_ALL) ? 0 : FNM_NOMATCH; + + if (result == FNM_NOMATCH) + result = use_strcmp(match->pattern, path) ? FNM_NOMATCH : 0; if (fnmatch_flags >= 0 && result == FNM_NOMATCH) result = p_fnmatch(match->pattern, path, fnmatch_flags); diff --git a/src/pathspec.h b/src/pathspec.h index c4456152033..43a94baadcb 100644 --- a/src/pathspec.h +++ b/src/pathspec.h @@ -16,7 +16,7 @@ extern char *git_pathspec_prefix(const git_strarray *pathspec); /* is there anything in the spec that needs to be filtered on */ -extern bool git_pathspec_is_interesting(const git_strarray *pathspec); +extern bool git_pathspec_is_empty(const git_strarray *pathspec); /* build a vector of fnmatch patterns to evaluate efficiently */ extern int git_pathspec_init( diff --git a/tests-clar/diff/notify.c b/tests-clar/diff/notify.c new file mode 100644 index 00000000000..433b4a9c1ea --- /dev/null +++ b/tests-clar/diff/notify.c @@ -0,0 +1,228 @@ +#include "clar_libgit2.h" +#include "diff_helpers.h" + +static git_repository *g_repo = NULL; + +void test_diff_notify__initialize(void) +{ +} + +void test_diff_notify__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static int assert_called_notifications( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload) +{ + bool found = false; + notify_expected *exp = (notify_expected*)payload; + notify_expected *e;; + + GIT_UNUSED(diff_so_far); + + for (e = exp; e->path != NULL; e++) { + if (strcmp(e->path, delta_to_add->new_file.path)) + continue; + + cl_assert_equal_s(e->matched_pathspec, matched_pathspec); + + found = true; + break; + } + + cl_assert(found); + return 0; +} + +static void test_notify( + char **searched_pathspecs, + int pathspecs_count, + notify_expected *expected_matched_pathspecs, + int expected_diffed_files_count) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + diff_expects exp; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.notify_cb = assert_called_notifications; + opts.pathspec.strings = searched_pathspecs; + opts.pathspec.count = pathspecs_count; + + opts.notify_payload = expected_matched_pathspecs; + memset(&exp, 0, sizeof(exp)); + + 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(expected_diffed_files_count, exp.files); + + git_diff_list_free(diff); +} + +void test_diff_notify__notify_single_pathspec(void) +{ + char *searched_pathspecs[] = { + "*_deleted", + }; + notify_expected expected_matched_pathspecs[] = { + { "file_deleted", "*_deleted" }, + { "staged_changes_file_deleted", "*_deleted" }, + { NULL, NULL } + }; + + test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 2); +} + +void test_diff_notify__notify_multiple_pathspec(void) +{ + char *searched_pathspecs[] = { + "staged_changes_cant_find_me", + "subdir/modified_cant_find_me", + "subdir/*", + "staged*" + }; + notify_expected expected_matched_pathspecs[] = { + { "staged_changes_file_deleted", "staged*" }, + { "staged_changes_modified_file", "staged*" }, + { "staged_delete_modified_file", "staged*" }, + { "staged_new_file_deleted_file", "staged*" }, + { "staged_new_file_modified_file", "staged*" }, + { "subdir/deleted_file", "subdir/*" }, + { "subdir/modified_file", "subdir/*" }, + { "subdir/new_file", "subdir/*" }, + { NULL, NULL } + }; + + test_notify(searched_pathspecs, 4, expected_matched_pathspecs, 8); +} + +void test_diff_notify__notify_catchall_with_empty_pathspecs(void) +{ + char *searched_pathspecs[] = { + "", + "" + }; + notify_expected expected_matched_pathspecs[] = { + { "file_deleted", NULL }, + { "ignored_file", NULL }, + { "modified_file", NULL }, + { "new_file", NULL }, + { "\xe8\xbf\x99", NULL }, + { "staged_changes_file_deleted", NULL }, + { "staged_changes_modified_file", NULL }, + { "staged_delete_modified_file", NULL }, + { "staged_new_file_deleted_file", NULL }, + { "staged_new_file_modified_file", NULL }, + { "subdir/deleted_file", NULL }, + { "subdir/modified_file", NULL }, + { "subdir/new_file", NULL }, + { NULL, NULL } + }; + + test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 13); +} + +void test_diff_notify__notify_catchall(void) +{ + char *searched_pathspecs[] = { + "*", + }; + notify_expected expected_matched_pathspecs[] = { + { "file_deleted", "*" }, + { "ignored_file", "*" }, + { "modified_file", "*" }, + { "new_file", "*" }, + { "\xe8\xbf\x99", "*" }, + { "staged_changes_file_deleted", "*" }, + { "staged_changes_modified_file", "*" }, + { "staged_delete_modified_file", "*" }, + { "staged_new_file_deleted_file", "*" }, + { "staged_new_file_modified_file", "*" }, + { "subdir/deleted_file", "*" }, + { "subdir/modified_file", "*" }, + { "subdir/new_file", "*" }, + { NULL, NULL } + }; + + test_notify(searched_pathspecs, 1, expected_matched_pathspecs, 13); +} + +static int abort_diff( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload) +{ + GIT_UNUSED(diff_so_far); + GIT_UNUSED(delta_to_add); + GIT_UNUSED(matched_pathspec); + GIT_UNUSED(payload); + + return -42; +} + +void test_diff_notify__notify_cb_can_abort_diff(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + char *pathspec = NULL; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.notify_cb = abort_diff; + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + + pathspec = "file_deleted"; + cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); + + pathspec = "staged_changes_modified_file"; + cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); +} + +static int filter_all( + const git_diff_list *diff_so_far, + const git_diff_delta *delta_to_add, + const char *matched_pathspec, + void *payload) +{ + GIT_UNUSED(diff_so_far); + GIT_UNUSED(delta_to_add); + GIT_UNUSED(matched_pathspec); + GIT_UNUSED(payload); + + return 42; +} + +void test_diff_notify__notify_cb_can_be_used_as_filtering_function(void) +{ + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_list *diff = NULL; + char *pathspec = NULL; + diff_expects exp; + + g_repo = cl_git_sandbox_init("status"); + + opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; + opts.notify_cb = filter_all; + opts.pathspec.strings = &pathspec; + opts.pathspec.count = 1; + + pathspec = "*_deleted"; + memset(&exp, 0, sizeof(exp)); + + 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(0, exp.files); + + git_diff_list_free(diff); +} diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c index fc95cf8b419..9d92d8d601f 100644 --- a/tests-clar/diff/workdir.c +++ b/tests-clar/diff/workdir.c @@ -307,169 +307,6 @@ void test_diff_workdir__to_index_with_pathspec(void) git_diff_list_free(diff); } -static int assert_called_notifications( - const git_diff_list *diff_so_far, - const git_diff_delta *delta_to_add, - const char *matched_pathspec, - void *payload) -{ - bool found = false; - notify_expected *exp = (notify_expected*)payload; - notify_expected *e;; - - GIT_UNUSED(diff_so_far); - - for (e = exp; e->path != NULL; e++) { - if (strcmp(e->path, delta_to_add->new_file.path)) - continue; - - cl_assert_equal_s(e->matched_pathspec, matched_pathspec); - - found = true; - break; - } - - cl_assert(found); - return 0; -} - -void test_diff_workdir__to_index_notify(void) -{ - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - git_diff_list *diff = NULL; - diff_expects exp; - - char *searched_pathspecs_solo[] = { - "*_deleted", - }; - notify_expected expected_matched_pathspecs_solo[] = { - { "file_deleted", "*_deleted" }, - { "staged_changes_file_deleted", "*_deleted" }, - { NULL, NULL } - }; - - char *searched_pathspecs_multiple[] = { - "staged_changes_cant_find_me", - "subdir/modified_cant_find_me", - "subdir/*", - "staged*" - }; - notify_expected expected_matched_pathspecs_multiple[] = { - { "staged_changes_file_deleted", "staged*" }, - { "staged_changes_modified_file", "staged*" }, - { "staged_delete_modified_file", "staged*" }, - { "staged_new_file_deleted_file", "staged*" }, - { "staged_new_file_modified_file", "staged*" }, - { "subdir/deleted_file", "subdir/*" }, - { "subdir/modified_file", "subdir/*" }, - { "subdir/new_file", "subdir/*" }, - { NULL, NULL } - }; - - g_repo = cl_git_sandbox_init("status"); - - opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; - opts.notify_cb = assert_called_notifications; - opts.pathspec.strings = searched_pathspecs_solo; - opts.pathspec.count = 1; - - opts.notify_payload = &expected_matched_pathspecs_solo; - memset(&exp, 0, sizeof(exp)); - - 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(2, exp.files); - - git_diff_list_free(diff); - - opts.pathspec.strings = searched_pathspecs_multiple; - opts.pathspec.count = 4; - opts.notify_payload = &expected_matched_pathspecs_multiple; - memset(&exp, 0, sizeof(exp)); - - 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(8, exp.files); - - git_diff_list_free(diff); -} - -static int abort_diff( - const git_diff_list *diff_so_far, - const git_diff_delta *delta_to_add, - const char *matched_pathspec, - void *payload) -{ - GIT_UNUSED(diff_so_far); - GIT_UNUSED(delta_to_add); - GIT_UNUSED(matched_pathspec); - GIT_UNUSED(payload); - - return -42; -} - -void test_diff_workdir__to_index_notify_can_be_aborted_by_callback(void) -{ - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - git_diff_list *diff = NULL; - char *pathspec = NULL; - - g_repo = cl_git_sandbox_init("status"); - - opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; - opts.notify_cb = abort_diff; - opts.pathspec.strings = &pathspec; - opts.pathspec.count = 1; - - pathspec = "file_deleted"; - cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); - - pathspec = "staged_changes_modified_file"; - cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); -} - -static int filter_all( - const git_diff_list *diff_so_far, - const git_diff_delta *delta_to_add, - const char *matched_pathspec, - void *payload) -{ - GIT_UNUSED(diff_so_far); - GIT_UNUSED(delta_to_add); - GIT_UNUSED(matched_pathspec); - GIT_UNUSED(payload); - - return 42; -} - -void test_diff_workdir__to_index_notify_can_be_used_as_filtering_function(void) -{ - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - git_diff_list *diff = NULL; - char *pathspec = NULL; - diff_expects exp; - - g_repo = cl_git_sandbox_init("status"); - - opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; - opts.notify_cb = filter_all; - opts.pathspec.strings = &pathspec; - opts.pathspec.count = 1; - - pathspec = "*_deleted"; - memset(&exp, 0, sizeof(exp)); - - 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(0, exp.files); - - git_diff_list_free(diff); -} - - void test_diff_workdir__filemode_changes(void) { git_diff_list *diff = NULL; From d59942c2aba2fa5f9570b37e3bc9eaf34f16d671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 30 Mar 2013 04:27:42 +0100 Subject: [PATCH 029/181] branch: add more upstream configuration management Add functions to set and unset the upstream configuration to complement the getter we already have. --- include/git2/branch.h | 12 +++ src/branch.c | 116 +++++++++++++++++++++++++++- tests-clar/refs/branches/upstream.c | 35 +++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) diff --git a/include/git2/branch.h b/include/git2/branch.h index 28bb1f5f074..4df2d353a56 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -177,6 +177,18 @@ GIT_EXTERN(int) git_branch_upstream( git_reference **out, git_reference *branch); +/** + * Set the upstream configuration for a given local branch + * + * @param branch the branch to configure + * + * @param upstream_name remote-tracking or local branch to set as + * upstream. Pass NULL to unset. + * + * @return 0 or an error code + */ +GIT_EXTERN(int) git_branch_set_upstream(git_reference *branch, const char *upstream_name); + /** * Return the name of the reference supporting the remote tracking branch, * given the name of a local branch reference. diff --git a/src/branch.c b/src/branch.c index 3b5d1d3c761..e7088790e6f 100644 --- a/src/branch.c +++ b/src/branch.c @@ -331,7 +331,7 @@ static int remote_name(git_buf *buf, git_repository *repo, const char *canonical /* Find matching remotes */ for (i = 0; i < remote_list.count; i++) { if ((error = git_remote_load(&remote, repo, remote_list.strings[i])) < 0) - goto cleanup; + continue; fetchspec = git_remote_fetchspec(remote); @@ -439,6 +439,120 @@ int git_branch_upstream( return error; } +static int unset_upstream(git_config *config, const char *shortname) +{ + git_buf buf = GIT_BUF_INIT; + + if (git_buf_printf(&buf, "branch.%s.remote", shortname) < 0) + return -1; + + if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) + goto on_error; + + git_buf_clear(&buf); + if (git_buf_printf(&buf, "branch.%s.merge", shortname) < 0) + goto on_error; + + if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) + goto on_error; + + git_buf_free(&buf); + return 0; + +on_error: + git_buf_free(&buf); + return -1; +} + +int git_branch_set_upstream(git_reference *branch, const char *upstream_name) +{ + git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT; + git_reference *upstream; + git_repository *repo; + git_remote *remote = NULL; + git_config *config; + const char *name, *shortname; + int local; + const git_refspec *fetchspec; + + name = git_reference_name(branch); + if (!git_reference__is_branch(name)) + return not_a_local_branch(name); + + if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) + return -1; + + shortname = name + strlen(GIT_REFS_HEADS_DIR); + + if (upstream_name == NULL) + return unset_upstream(config, shortname); + + repo = git_reference_owner(branch); + + /* First we need to figure out whether it's a branch or remote-tracking */ + if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0) + local = 1; + else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0) + local = 0; + else + return GIT_ENOTFOUND; + + /* + * If it's local, the remote is "." and the branch name is + * simply the refname. Otherwise we need to figure out what + * the remote-tracking branch's name on the remote is and use + * that. + */ + if (local) + git_buf_puts(&value, "."); + else + remote_name(&value, repo, git_reference_name(upstream)); + + if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0) + goto on_error; + + if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) + goto on_error; + + if (local) { + if (git_buf_puts(&value, git_reference_name(branch)) < 0) + goto on_error; + } else { + /* Get the remoe-tracking branch's refname in its repo */ + if (git_remote_load(&remote, repo, git_buf_cstr(&value)) < 0) + goto on_error; + + fetchspec = git_remote_fetchspec(remote); + git_buf_clear(&value); + if (git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0) + goto on_error; + + git_remote_free(remote); + remote = NULL; + } + + git_buf_clear(&key); + if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0) + goto on_error; + + if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) + goto on_error; + + git_reference_free(upstream); + git_buf_free(&key); + git_buf_free(&value); + + return 0; + +on_error: + git_reference_free(upstream); + git_buf_free(&key); + git_buf_free(&value); + git_remote_free(remote); + + return -1; +} + int git_branch_is_head( git_reference *branch) { diff --git a/tests-clar/refs/branches/upstream.c b/tests-clar/refs/branches/upstream.c index fca25416190..2d0ebd24042 100644 --- a/tests-clar/refs/branches/upstream.c +++ b/tests-clar/refs/branches/upstream.c @@ -93,3 +93,38 @@ void test_refs_branches_upstream__retrieve_a_remote_tracking_reference_from_a_br cl_git_sandbox_cleanup(); } + +void test_refs_branches_upstream__set_unset_upstream(void) +{ + git_reference *branch; + git_repository *repository; + const char *value; + git_config *config; + + repository = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/test")); + cl_git_pass(git_branch_set_upstream(branch, "test/master")); + + cl_git_pass(git_repository_config(&config, repository)); + cl_git_pass(git_config_get_string(&value, config, "branch.test.remote")); + cl_assert_equal_s(value, "test"); + cl_git_pass(git_config_get_string(&value, config, "branch.test.merge")); + cl_assert_equal_s(value, "refs/heads/master"); + + cl_git_pass(git_branch_set_upstream(branch, NULL)); + cl_git_fail_with(git_config_get_string(&value, config, "branch.test.merge"), GIT_ENOTFOUND); + cl_git_fail_with(git_config_get_string(&value, config, "branch.test.remote"), GIT_ENOTFOUND); + + git_reference_free(branch); + + cl_git_pass(git_reference_lookup(&branch, repository, "refs/heads/master")); + cl_git_pass(git_branch_set_upstream(branch, NULL)); + cl_git_fail_with(git_config_get_string(&value, config, "branch.master.merge"), GIT_ENOTFOUND); + cl_git_fail_with(git_config_get_string(&value, config, "branch.master.remote"), GIT_ENOTFOUND); + + git_reference_free(branch); + + git_config_free(config); + cl_git_sandbox_cleanup(); +} From 7ebc249c2225c1a9290b0981fcc7f37490b5b80c Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 4 Apr 2013 11:38:17 -0500 Subject: [PATCH 030/181] dec refcount on refdb instead of always freeing --- src/refdb.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/refdb.c b/src/refdb.c index 0d206434324..d9b73c6e79e 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -82,7 +82,7 @@ int git_refdb_compress(git_refdb *db) return 0; } -void git_refdb_free(git_refdb *db) +static void refdb_free(git_refdb *db) { if (db->backend) { if(db->backend->free) @@ -94,6 +94,14 @@ void git_refdb_free(git_refdb *db) git__free(db); } +void git_refdb_free(git_refdb *db) +{ + if (db == NULL) + return; + + GIT_REFCOUNT_DEC(db, refdb_free); +} + int git_refdb_exists(int *exists, git_refdb *refdb, const char *ref_name) { assert(exists && refdb && refdb->backend); From 0efae3b22e7472b95174632c323137a2b21b9c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 15 Apr 2013 12:24:08 +0200 Subject: [PATCH 031/181] commit: correctly detect the start of the commit message The end of the header is signaled by to consecutive LFs and the commit message starts immediately after. Jumping over LFs at the start of the message is a bug and leads to creating different commits if when rebuilding history. This also fixes an empty commit message being returned as "\n". --- src/commit.c | 4 ++-- tests-clar/commit/parse.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/commit.c b/src/commit.c index e2d3d346b5f..c7b83ed432b 100644 --- a/src/commit.c +++ b/src/commit.c @@ -189,8 +189,8 @@ int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) buffer = eoln; } - /* skip blank lines */ - while (buffer < buffer_end - 1 && *buffer == '\n') + /* buffer is now at the end of the header, double-check and move forward into the message */ + if (buffer < buffer_end && *buffer == '\n') buffer++; /* parse commit message */ diff --git a/tests-clar/commit/parse.c b/tests-clar/commit/parse.c index 95c62858856..b99d2799172 100644 --- a/tests-clar/commit/parse.c +++ b/tests-clar/commit/parse.c @@ -297,7 +297,7 @@ void test_commit_parse__entire_commit(void) ); if (!i) - cl_assert_equal_s("\n", git_commit_message(commit)); + cl_assert_equal_s("", git_commit_message(commit)); else cl_assert(git__prefixcmp( git_commit_message(commit), "a simple commit which works") == 0); @@ -366,3 +366,30 @@ void test_commit_parse__details0(void) { } } +void test_commit_parse__leading_lf(void) +{ + git_commit *commit; + const char *buffer = +"tree 1810dff58d8a660512d4832e740f692884338ccd\n\ +parent e90810b8df3e80c413d903f631643c716887138d\n\ +author Vicent Marti 1273848544 +0200\n\ +committer Vicent Marti 1273848544 +0200\n\ +\n\ +\n\ +\n\ +This commit has a few LF at the start of the commit message"; + const char *message = +"\n\ +\n\ +This commit has a few LF at the start of the commit message"; + + commit = (git_commit*)git__malloc(sizeof(git_commit)); + memset(commit, 0x0, sizeof(git_commit)); + commit->object.repo = g_repo; + + cl_git_pass(git_commit__parse_buffer(commit, buffer, strlen(buffer))); + + cl_assert_equal_s(message, git_commit_message(commit)); + + git_commit__free(commit); +} From 872ca1d302c571d47d9685179cbc6af84130f703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 15 Apr 2013 20:00:42 +0200 Subject: [PATCH 032/181] Fix compilation on OpenBSD --- src/unix/realpath.c | 2 +- src/util.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/realpath.c b/src/unix/realpath.c index f382c2b73e0..15601bd2285 100644 --- a/src/unix/realpath.c +++ b/src/unix/realpath.c @@ -22,7 +22,7 @@ char *p_realpath(const char *pathname, char *resolved) /* Figure out if the file exists */ if (!access(ret, F_OK)) - ret; + return ret; return NULL; } diff --git a/src/util.c b/src/util.c index 44ac1af7368..8e83d298e42 100644 --- a/src/util.c +++ b/src/util.c @@ -672,7 +672,7 @@ static int GIT_STDLIB_CALL git__qsort_r_glue_cmp( void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) { -#if defined(__MINGW32__) +#if defined(__MINGW32__) || defined(__OpenBSD__) git__insertsort_r(els, nel, elsize, NULL, cmp, payload); #elif defined(GIT_WIN32) git__qsort_r_glue glue = { cmp, payload }; From 4a3f69b5b23efd123b3730ee999443b38cb11419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 15 Apr 2013 20:20:14 +0200 Subject: [PATCH 033/181] refdb tests: use the right variable size Mixing int and size_t through pointers leads to problems in big-endian machines. --- tests-clar/refdb/inmemory.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests-clar/refdb/inmemory.c b/tests-clar/refdb/inmemory.c index 6ee09c0c753..6f565196416 100644 --- a/tests-clar/refdb/inmemory.c +++ b/tests-clar/refdb/inmemory.c @@ -124,8 +124,8 @@ int foreach_test(const char *ref_name, void *payload) { git_reference *ref; git_oid expected; - int *i = payload; - + size_t *i = payload; + cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); if (*i == 0) @@ -136,7 +136,7 @@ int foreach_test(const char *ref_name, void *payload) cl_git_pass(git_oid_fromstr(&expected, "763d71aadf09a7951596c9746c024e7eece7c7af")); cl_assert(git_oid_cmp(&expected, &ref->target.oid) == 0); - + ++(*i); git_reference_free(ref); @@ -159,8 +159,8 @@ void test_refdb_inmemory__foreach(void) 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(i == 3); + cl_git_pass(git_reference_foreach(repo, GIT_REF_LISTALL, foreach_test, &i)); + cl_assert_equal_i(i, 3); git_reference_free(write1); git_reference_free(write2); @@ -171,8 +171,8 @@ int delete_test(const char *ref_name, void *payload) { git_reference *ref; git_oid expected; - int *i = payload; - + size_t *i = payload; + cl_git_pass(git_reference_lookup(&ref, repo, ref_name)); cl_git_pass(git_oid_fromstr(&expected, "e90810b8df3e80c413d903f631643c716887138d")); @@ -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(i == 1); + cl_assert_equal_i(i, 1); git_reference_free(write2); } From 4291ad078128003ad6d4ac6fb58244f3343ad87a Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 15 Apr 2013 11:42:34 -0700 Subject: [PATCH 034/181] Reintroduce git_revparse_single. --- include/git2/revparse.h | 14 ++++++++++++++ src/revparse.c | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 7fe910b4514..2bbbaa5e191 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -20,6 +20,20 @@ */ GIT_BEGIN_DECL +/** + * + * Find a single object, as specified by a revision string. See `man gitrevisions`, + * or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for + * information on the syntax accepted. + * + * @param out pointer to output object + * @param repo the repository to search in + * @param spec the textual specification for an object + * @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, GIT_EINVALIDSPEC or an error code + */ +GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, + const char *spec); + /** * Revparse flags. These indicate the intended behavior of the spec passed to diff --git a/src/revparse.c b/src/revparse.c index 7842c49b7e6..5f591406e00 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -722,7 +722,7 @@ static int ensure_left_hand_identifier_is_not_known_yet(git_object *object, git_ return GIT_EINVALIDSPEC; } -static int git_revparse_single(git_object **out, git_repository *repo, const char *spec) +int git_revparse_single(git_object **out, git_repository *repo, const char *spec) { size_t pos = 0, identifier_len = 0; int error = -1, n; From 2ebc3c66c292539786b6ec1538f740c5e444fe16 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 15 Apr 2013 11:57:24 -0700 Subject: [PATCH 035/181] Redeploy git_revparse_single. --- src/push.c | 5 +- src/transports/local.c | 7 +- tests-clar/checkout/tree.c | 53 ++++----------- tests-clar/checkout/typechange.c | 8 +-- tests-clar/clone/nonetwork.c | 9 +-- tests-clar/refs/revparse.c | 111 ++++++++++++++----------------- 6 files changed, 77 insertions(+), 116 deletions(-) diff --git a/src/push.c b/src/push.c index dcd8122d17e..ce7af3598b1 100644 --- a/src/push.c +++ b/src/push.c @@ -96,8 +96,9 @@ static int check_rref(char *ref) static int check_lref(git_push *push, char *ref) { /* lref must be resolvable to an existing object */ - git_oid oid; - int error = git_revparse(&oid, NULL, NULL, push->repo, ref); + git_object *obj; + int error = git_revparse_single(&obj, push->repo, ref); + git_object_free(obj); if (!error) return 0; diff --git a/src/transports/local.c b/src/transports/local.c index 1e27fc38c28..ce89bb213e5 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -236,13 +236,14 @@ static int local_negotiate_fetch( /* Fill in the loids */ git_vector_foreach(&t->refs, i, rhead) { - git_oid oid; + git_object *obj; - int error = git_revparse(&oid, NULL, NULL, repo, rhead->name); + int error = git_revparse_single(&obj, repo, rhead->name); if (!error) - git_oid_cpy(&rhead->loid, &oid); + git_oid_cpy(&rhead->loid, git_object_id(obj)); else if (error != GIT_ENOTFOUND) return error; + git_object_free(obj); giterr_clear(); } diff --git a/tests-clar/checkout/tree.c b/tests-clar/checkout/tree.c index ae4087f4167..0748b22e029 100644 --- a/tests-clar/checkout/tree.c +++ b/tests-clar/checkout/tree.c @@ -28,25 +28,19 @@ void test_checkout_tree__cleanup(void) void test_checkout_tree__cannot_checkout_a_non_treeish(void) { - git_oid oid; - /* blob */ - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); - + cl_git_pass(git_revparse_single(&g_object, g_repo, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd")); cl_git_fail(git_checkout_tree(g_repo, g_object, NULL)); } void test_checkout_tree__can_checkout_a_subdirectory_from_a_commit(void) { char *entries[] = { "ab/de/" }; - git_oid oid; g_opts.paths.strings = entries; g_opts.paths.count = 1; - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "subtrees")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees")); cl_assert_equal_i(false, git_path_isdir("./testrepo/ab/")); @@ -58,15 +52,12 @@ void test_checkout_tree__can_checkout_a_subdirectory_from_a_commit(void) void test_checkout_tree__can_checkout_and_remove_directory(void) { - git_oid oid; - cl_assert_equal_i(false, git_path_isdir("./testrepo/ab/")); /* Checkout brach "subtrees" and update HEAD, so that HEAD matches the * current working tree */ - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "subtrees")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/subtrees")); @@ -81,8 +72,7 @@ void test_checkout_tree__can_checkout_and_remove_directory(void) /* Checkout brach "master" and update HEAD, so that HEAD matches the * current working tree */ - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "master")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, "master")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/master")); @@ -94,13 +84,11 @@ void test_checkout_tree__can_checkout_and_remove_directory(void) void test_checkout_tree__can_checkout_a_subdirectory_from_a_subtree(void) { char *entries[] = { "de/" }; - git_oid oid; g_opts.paths.strings = entries; g_opts.paths.count = 1; - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "subtrees:ab")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, "subtrees:ab")); cl_assert_equal_i(false, git_path_isdir("./testrepo/de/")); @@ -120,13 +108,11 @@ static void progress(const char *path, size_t cur, size_t tot, void *payload) void test_checkout_tree__calls_progress_callback(void) { bool was_called = 0; - git_oid oid; g_opts.progress_cb = progress; g_opts.progress_payload = &was_called; - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "master")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, "master")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); @@ -290,16 +276,13 @@ void test_checkout_tree__can_update_only(void) void test_checkout_tree__can_checkout_with_pattern(void) { char *entries[] = { "[l-z]*.txt" }; - git_oid oid; /* reset to beginning of history (i.e. just a README file) */ g_opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, - "8496071c1b46c854b31185ea97743be6a8774479")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass( @@ -319,8 +302,7 @@ void test_checkout_tree__can_checkout_with_pattern(void) g_opts.paths.strings = entries; g_opts.paths.count = 1; - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "refs/heads/master")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); @@ -333,16 +315,13 @@ void test_checkout_tree__can_checkout_with_pattern(void) void test_checkout_tree__can_disable_pattern_match(void) { char *entries[] = { "b*.txt" }; - git_oid oid; /* reset to beginning of history (i.e. just a README file) */ g_opts.checkout_strategy = GIT_CHECKOUT_FORCE | GIT_CHECKOUT_REMOVE_UNTRACKED; - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, - "8496071c1b46c854b31185ea97743be6a8774479")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); cl_git_pass( @@ -360,8 +339,7 @@ void test_checkout_tree__can_disable_pattern_match(void) g_opts.paths.strings = entries; g_opts.paths.count = 1; - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "refs/heads/master")); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, "refs/heads/master")); cl_git_pass(git_checkout_tree(g_repo, g_object, &g_opts)); @@ -386,13 +364,11 @@ void assert_conflict( git_object *hack_tree; git_reference *branch, *head; git_buf file_path = GIT_BUF_INIT; - git_oid oid; cl_git_pass(git_repository_index(&index, g_repo)); /* Create a branch pointing at the parent */ - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, parent_sha)); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, parent_sha)); cl_git_pass(git_branch_create(&branch, g_repo, "potential_conflict", (git_commit *)g_object, 0)); @@ -421,8 +397,7 @@ void assert_conflict( git_buf_free(&file_path); /* Trying to checkout the original commit */ - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, commit_sha)); - cl_git_pass(git_object_lookup(&g_object, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&g_object, g_repo, commit_sha)); g_opts.checkout_strategy = GIT_CHECKOUT_SAFE; cl_assert_equal_i( @@ -509,7 +484,6 @@ void test_checkout_tree__issue_1397(void) git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; const char *partial_oid = "8a7ef04"; git_object *tree = NULL; - git_oid oid; test_checkout_tree__cleanup(); /* cleanup default checkout */ @@ -517,8 +491,7 @@ void test_checkout_tree__issue_1397(void) cl_repo_set_bool(g_repo, "core.autocrlf", true); - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, partial_oid)); - cl_git_pass(git_object_lookup(&tree, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&tree, g_repo, partial_oid)); opts.checkout_strategy = GIT_CHECKOUT_FORCE; diff --git a/tests-clar/checkout/typechange.c b/tests-clar/checkout/typechange.c index 74521312aca..b92cc23fa52 100644 --- a/tests-clar/checkout/typechange.c +++ b/tests-clar/checkout/typechange.c @@ -107,12 +107,10 @@ void test_checkout_typechange__checkout_typechanges_safe(void) { int i; git_object *obj; - git_oid oid; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; for (i = 0; g_typechange_oids[i] != NULL; ++i) { - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, g_typechange_oids[i])); - cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i])); opts.checkout_strategy = GIT_CHECKOUT_FORCE; @@ -196,7 +194,6 @@ void test_checkout_typechange__checkout_with_conflicts(void) { int i; git_object *obj; - git_oid oid; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; notify_counts cts = {0}; @@ -206,8 +203,7 @@ void test_checkout_typechange__checkout_with_conflicts(void) opts.notify_payload = &cts; for (i = 0; g_typechange_oids[i] != NULL; ++i) { - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, g_typechange_oids[i])); - cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&obj, g_repo, g_typechange_oids[i])); force_create_file("typechanges/a/blocker"); force_create_file("typechanges/b"); diff --git a/tests-clar/clone/nonetwork.c b/tests-clar/clone/nonetwork.c index d86c1f4c920..c4b482234b2 100644 --- a/tests-clar/clone/nonetwork.c +++ b/tests-clar/clone/nonetwork.c @@ -214,22 +214,23 @@ void test_clone_nonetwork__can_checkout_given_branch(void) void test_clone_nonetwork__can_detached_head(void) { - git_oid oid; + git_object *obj; git_repository *cloned; git_reference *cloned_head; cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); - cl_git_pass(git_revparse(&oid, NULL, NULL, g_repo, "master~1")); - cl_git_pass(git_repository_set_head_detached(g_repo, &oid)); + cl_git_pass(git_revparse_single(&obj, g_repo, "master~1")); + cl_git_pass(git_repository_set_head_detached(g_repo, git_object_id(obj))); cl_git_pass(git_clone(&cloned, "./foo", "./foo1", &g_options)); cl_assert(git_repository_head_detached(cloned)); cl_git_pass(git_repository_head(&cloned_head, cloned)); - cl_assert(!git_oid_cmp(&oid, git_reference_target(cloned_head))); + cl_assert(!git_oid_cmp(git_object_id(obj), git_reference_target(cloned_head))); + git_object_free(obj); git_reference_free(cloned_head); git_repository_free(cloned); diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 39e77c8eb8b..8c3e5e43a38 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -6,22 +6,25 @@ #include "path.h" static git_repository *g_repo; +static git_object *g_obj; /* Helpers */ static void test_object_inrepo(const char *spec, const char *expected_oid, git_repository *repo) { char objstr[64] = {0}; - git_oid oid; + git_object *obj = NULL; int error; - error = git_revparse(&oid, NULL, NULL, repo, spec); + error = git_revparse_single(&obj, repo, spec); if (expected_oid != NULL) { cl_assert_equal_i(0, error); - git_oid_fmt(objstr, &oid); + git_oid_fmt(objstr, git_object_id(obj)); cl_assert_equal_s(objstr, expected_oid); } else cl_assert_equal_i(GIT_ENOTFOUND, error); + + git_object_free(obj); } static void test_id_inrepo( @@ -110,18 +113,17 @@ void test_refs_revparse__nonexistant_object(void) test_object("this-does-not-exist~2", NULL); } -static void assert_invalid_spec(const char *invalid_spec) +static void assert_invalid_single_spec(const char *invalid_spec) { - git_oid oid; cl_assert_equal_i( - GIT_EINVALIDSPEC, git_revparse(&oid, NULL, NULL, g_repo, invalid_spec)); + GIT_EINVALIDSPEC, git_revparse_single(&g_obj, g_repo, invalid_spec)); } void test_refs_revparse__invalid_reference_name(void) { - assert_invalid_spec("this doesn't make sense"); - assert_invalid_spec("Inv@{id"); - assert_invalid_spec(""); + assert_invalid_single_spec("this doesn't make sense"); + assert_invalid_single_spec("Inv@{id"); + assert_invalid_single_spec(""); } void test_refs_revparse__shas(void) @@ -160,11 +162,11 @@ void test_refs_revparse__describe_output(void) void test_refs_revparse__nth_parent(void) { - assert_invalid_spec("be3563a^-1"); - assert_invalid_spec("^"); - assert_invalid_spec("be3563a^{tree}^"); - assert_invalid_spec("point_to_blob^{blob}^"); - assert_invalid_spec("this doesn't make sense^1"); + assert_invalid_single_spec("be3563a^-1"); + assert_invalid_single_spec("^"); + assert_invalid_single_spec("be3563a^{tree}^"); + assert_invalid_single_spec("point_to_blob^{blob}^"); + assert_invalid_single_spec("this doesn't make sense^1"); test_object("be3563a^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("be3563a^", "9fd738e8f7967c078dceed8190330fc8648ee56a"); @@ -191,12 +193,10 @@ void test_refs_revparse__not_tag(void) void test_refs_revparse__to_type(void) { - git_oid oid; - - assert_invalid_spec("wrapped_tag^{trip}"); + assert_invalid_single_spec("wrapped_tag^{trip}"); test_object("point_to_blob^{commit}", NULL); cl_assert_equal_i( - GIT_EAMBIGUOUS, git_revparse(&oid, NULL, NULL, g_repo, "wrapped_tag^{blob}")); + GIT_EAMBIGUOUS, git_revparse_single(&g_obj, g_repo, "wrapped_tag^{blob}")); test_object("wrapped_tag^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("wrapped_tag^{tree}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); @@ -206,15 +206,15 @@ void test_refs_revparse__to_type(void) void test_refs_revparse__linear_history(void) { - assert_invalid_spec("~"); + assert_invalid_single_spec("~"); test_object("foo~bar", NULL); - assert_invalid_spec("master~bar"); - assert_invalid_spec("master~-1"); - assert_invalid_spec("master~0bar"); - assert_invalid_spec("this doesn't make sense~2"); - assert_invalid_spec("be3563a^{tree}~"); - assert_invalid_spec("point_to_blob^{blob}~"); + assert_invalid_single_spec("master~bar"); + assert_invalid_single_spec("master~-1"); + assert_invalid_single_spec("master~0bar"); + assert_invalid_single_spec("this doesn't make sense~2"); + assert_invalid_single_spec("be3563a^{tree}~"); + assert_invalid_single_spec("point_to_blob^{blob}~"); test_object("master~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("master~1", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); @@ -225,10 +225,10 @@ void test_refs_revparse__linear_history(void) void test_refs_revparse__chaining(void) { - assert_invalid_spec("master@{0}@{0}"); - assert_invalid_spec("@{u}@{-1}"); - assert_invalid_spec("@{-1}@{-1}"); - assert_invalid_spec("@{-3}@{0}"); + assert_invalid_single_spec("master@{0}@{0}"); + assert_invalid_single_spec("@{u}@{-1}"); + assert_invalid_single_spec("@{-1}@{-1}"); + assert_invalid_single_spec("@{-3}@{0}"); test_object("master@{0}~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); test_object("@{u}@{0}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); @@ -244,8 +244,8 @@ void test_refs_revparse__chaining(void) void test_refs_revparse__upstream(void) { - assert_invalid_spec("e90810b@{u}"); - assert_invalid_spec("refs/tags/e90810b@{u}"); + assert_invalid_single_spec("e90810b@{u}"); + assert_invalid_single_spec("refs/tags/e90810b@{u}"); test_object("refs/heads/e90810b@{u}", NULL); test_object("master@{upstream}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); @@ -257,11 +257,10 @@ void test_refs_revparse__upstream(void) void test_refs_revparse__ordinal(void) { - assert_invalid_spec("master@{-2}"); + assert_invalid_single_spec("master@{-2}"); /* TODO: make the test below actually fail - * git_oid oid; - * cl_git_fail(git_revparse(&oid, NULL, NULL, g_repo, "master@{1a}")); + * cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{1a}")); */ test_object("nope@{0}", NULL); @@ -280,9 +279,9 @@ void test_refs_revparse__ordinal(void) void test_refs_revparse__previous_head(void) { - assert_invalid_spec("@{-xyz}"); - assert_invalid_spec("@{-0}"); - assert_invalid_spec("@{-1b}"); + assert_invalid_single_spec("@{-xyz}"); + assert_invalid_single_spec("@{-0}"); + assert_invalid_single_spec("@{-1b}"); test_object("@{-42}", NULL); @@ -342,7 +341,7 @@ void test_refs_revparse__revwalk(void) { test_object("master^{/not found in any commit}", NULL); test_object("master^{/merge}", NULL); - assert_invalid_spec("master^{/((}"); + assert_invalid_single_spec("master^{/((}"); test_object("master^{/anoth}", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("master^{/Merge}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); @@ -423,11 +422,9 @@ void test_refs_revparse__date(void) void test_refs_revparse__colon(void) { - git_oid oid; - - assert_invalid_spec(":/"); - assert_invalid_spec("point_to_blob:readme.txt"); - cl_git_fail(git_revparse(&oid, NULL, NULL, g_repo, ":2:README")); /* Not implemented */ + assert_invalid_single_spec(":/"); + assert_invalid_single_spec("point_to_blob:readme.txt"); + cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); /* Not implemented */ test_object(":/not found in any commit", NULL); test_object("subtrees:ab/42.txt", NULL); @@ -517,9 +514,8 @@ void test_refs_revparse__disambiguation(void) void test_refs_revparse__a_too_short_objectid_returns_EAMBIGUOUS(void) { - git_oid oid; cl_assert_equal_i( - GIT_EAMBIGUOUS, git_revparse(&oid, NULL, NULL, g_repo, "e90")); + GIT_EAMBIGUOUS, git_revparse_single(&g_obj, g_repo, "e90")); } void test_refs_revparse__issue_994(void) @@ -527,15 +523,14 @@ void test_refs_revparse__issue_994(void) git_repository *repo; git_reference *head, *with_at; git_object *target; - git_oid oid; repo = cl_git_sandbox_init("testrepo.git"); cl_assert_equal_i(GIT_ENOTFOUND, - git_revparse(&oid, NULL, NULL, repo, "origin/bim_with_3d@11296")); + git_revparse_single(&target, repo, "origin/bim_with_3d@11296")); cl_assert_equal_i(GIT_ENOTFOUND, - git_revparse(&oid, NULL, NULL, repo, "refs/remotes/origin/bim_with_3d@11296")); + git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296")); cl_git_pass(git_repository_head(&head, repo)); @@ -546,12 +541,10 @@ void test_refs_revparse__issue_994(void) git_reference_target(head), 0)); - cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "origin/bim_with_3d@11296")); - cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); + cl_git_pass(git_revparse_single(&target, repo, "origin/bim_with_3d@11296")); git_object_free(target); - cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "refs/remotes/origin/bim_with_3d@11296")); - cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); + cl_git_pass(git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296")); git_object_free(target); git_reference_free(with_at); @@ -577,14 +570,12 @@ void test_refs_revparse__try_to_retrieve_branch_before_described_tag(void) git_reference *branch; git_object *target; char sha[GIT_OID_HEXSZ + 1]; - git_oid oid; repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("blah-7-gc47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd", repo); - cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "HEAD~3")); - cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); + cl_git_pass(git_revparse_single(&target, repo, "HEAD~3")); cl_git_pass(git_branch_create(&branch, repo, "blah-7-gc47800c", (git_commit *)target, 0)); git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target)); @@ -617,14 +608,12 @@ void test_refs_revparse__try_to_retrieve_sha_before_branch(void) git_reference *branch; git_object *target; char sha[GIT_OID_HEXSZ + 1]; - git_oid oid; repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); - cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "HEAD~3")); - cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); + cl_git_pass(git_revparse_single(&target, repo, "HEAD~3")); cl_git_pass(git_branch_create(&branch, repo, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", (git_commit *)target, 0)); git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target)); @@ -655,14 +644,12 @@ void test_refs_revparse__try_to_retrieve_branch_before_abbrev_sha(void) git_reference *branch; git_object *target; char sha[GIT_OID_HEXSZ + 1]; - git_oid oid; repo = cl_git_sandbox_init("testrepo.git"); test_object_inrepo("c47800", "c47800c7266a2be04c571c04d5a6614691ea99bd", repo); - cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "HEAD~3")); - cl_git_pass(git_object_lookup(&target, repo, &oid, GIT_OBJ_COMMIT)); + cl_git_pass(git_revparse_single(&target, repo, "HEAD~3")); cl_git_pass(git_branch_create(&branch, repo, "c47800", (git_commit *)target, 0)); git_oid_tostr(sha, GIT_OID_HEXSZ + 1, git_object_id(target)); @@ -677,6 +664,8 @@ void test_refs_revparse__try_to_retrieve_branch_before_abbrev_sha(void) void test_refs_revparse__range(void) { + assert_invalid_single_spec("be3563a^1..be3563a"); + test_rangelike("be3563a^1..be3563a", "9fd738e8f7967c078dceed8190330fc8648ee56a", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", From 299a224be16368dc36bef4dc3f5e711ce35300cd Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 15 Apr 2013 12:00:04 -0700 Subject: [PATCH 036/181] Change git_revparse to output git_object pointers This will probably prevent many lookup/free operations in calling code. --- examples/diff.c | 6 ++---- examples/rev-list.c | 16 ++++++++++------ include/git2/revparse.h | 4 ++-- src/revparse.c | 21 ++++++++------------- src/revwalk.c | 8 +++++--- tests-clar/refs/revparse.c | 19 ++++++++++++------- tests-clar/repo/head.c | 8 ++------ tests-clar/reset/default.c | 12 +++--------- tests-clar/stash/drop.c | 15 +++++++-------- tests-clar/stash/save.c | 11 +++-------- 10 files changed, 54 insertions(+), 66 deletions(-) diff --git a/examples/diff.c b/examples/diff.c index 6fa0fee5271..a977abd3fca 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -15,12 +15,10 @@ static int resolve_to_tree( git_repository *repo, const char *identifier, git_tree **tree) { int err = 0; - git_oid oid; git_object *obj = NULL; - if (git_revparse(&oid, NULL, NULL, repo, identifier) < 0 || - git_object_lookup(&obj, repo, &oid, GIT_OBJ_ANY) < 0) - return GIT_ENOTFOUND; + if ((err =git_revparse(&obj, NULL, NULL, repo, identifier)) < 0) + return err; switch (git_object_type(obj)) { case GIT_OBJ_TREE: diff --git a/examples/rev-list.c b/examples/rev-list.c index 71a8180f75d..1747f204103 100644 --- a/examples/rev-list.c +++ b/examples/rev-list.c @@ -25,16 +25,18 @@ static int push_commit(git_revwalk *walk, git_oid *oid, int hide) static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, int hide) { int error; - git_oid oid; + git_object *obj; - if ((error = git_revparse(&oid, NULL, NULL, repo, spec))) + if ((error = git_revparse(&obj, NULL, NULL, repo, spec)) < 0) return error; - return push_commit(walk, &oid, hide); + error = push_commit(walk, git_object_id(obj), hide); + git_object_free(obj); + return error; } static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide) { - git_oid left, right; + git_object left, right; git_revparse_flag_t flags; int error = 0; @@ -45,11 +47,13 @@ static int push_range(git_repository *repo, git_revwalk *walk, const char *range return GIT_EINVALIDSPEC; } - if ((error = push_commit(walk, &left, !hide))) + if ((error = push_commit(walk, git_object_id(left), !hide))) goto out; - error = push_commit(walk, &right, hide); + error = push_commit(walk, git_object_id(right), hide); out: + git_object_free(left); + git_object_free(right); return error; } diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 2bbbaa5e191..4f8c274a467 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -66,8 +66,8 @@ typedef enum { * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code */ GIT_EXTERN(int) git_revparse( - git_oid *left, - git_oid *right, + git_object **left, + git_object **right, unsigned int *flags, git_repository *repo, const char *spec); diff --git a/src/revparse.c b/src/revparse.c index 5f591406e00..62be3128a7a 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -870,8 +870,8 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec int git_revparse( - git_oid *left, - git_oid *right, + git_object **left, + git_object **right, unsigned int *flags, git_repository *repo, const char *spec) @@ -879,7 +879,6 @@ int git_revparse( unsigned int lflags = 0; const char *dotdot; int error = 0; - git_object *obj = NULL; assert(left && repo && spec); @@ -895,22 +894,18 @@ int git_revparse( rstr++; } - if (!(error = git_revparse_single(&obj, repo, lstr))) { - git_oid_cpy(left, git_object_id(obj)); - git_object_free(obj); + if ((error = git_revparse_single(left, repo, lstr)) < 0) { + return error; } - if (right && !(error = git_revparse_single(&obj, repo, rstr))) { - git_oid_cpy(right, git_object_id(obj)); - git_object_free(obj); + if (right && + (error = git_revparse_single(right, repo, rstr)) < 0) { + return error; } git__free((void*)lstr); } else { lflags = GIT_REVPARSE_SINGLE; - if (!(error = git_revparse_single(&obj, repo, spec))) { - git_oid_cpy(left, git_object_id(obj)); - git_object_free(obj); - } + error = git_revparse_single(left, repo, spec); } if (flags) diff --git a/src/revwalk.c b/src/revwalk.c index b22fef07f3b..05e99c0b637 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -231,7 +231,7 @@ int git_revwalk_push_ref(git_revwalk *walk, const char *refname) int git_revwalk_push_range(git_revwalk *walk, const char *range) { - git_oid left, right; + git_object *left, *right; git_revparse_flag_t revparseflags; int error = 0; @@ -243,11 +243,13 @@ int git_revwalk_push_range(git_revwalk *walk, const char *range) return GIT_EINVALIDSPEC; } - if ((error = push_commit(walk, &left, 1))) + if ((error = push_commit(walk, git_object_id(left), 1))) goto out; - error = push_commit(walk, &right, 0); + error = push_commit(walk, git_object_id(right), 0); out: + git_object_free(left); + git_object_free(right); return error; } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 8c3e5e43a38..c1cfc58af23 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -34,7 +34,7 @@ static void test_id_inrepo( git_revparse_flag_t expected_flags, git_repository *repo) { - git_oid l = {{0}}, r = {{0}}; + git_object *l, *r; git_revparse_flag_t flags = 0; int error = git_revparse(&l, &r, &flags, repo, spec); @@ -42,16 +42,18 @@ static void test_id_inrepo( if (expected_left) { char str[64] = {0}; cl_assert_equal_i(0, error); - git_oid_fmt(str, &l); + git_oid_fmt(str, git_object_id(l)); cl_assert_equal_s(str, expected_left); + git_object_free(l); } else { cl_assert_equal_i(GIT_ENOTFOUND, error); } if (expected_right) { char str[64] = {0}; - git_oid_fmt(str, &r); + git_oid_fmt(str, git_object_id(r)); cl_assert_equal_s(str, expected_right); + git_object_free(r); } if (expected_flags) @@ -69,7 +71,7 @@ static void test_rangelike(const char *rangelike, git_revparse_flag_t expected_revparseflags) { char objstr[64] = {0}; - git_oid left = {{0}}, right = {{0}}; + git_object *left = NULL, *right = NULL; git_revparse_flag_t revparseflags; int error; @@ -78,12 +80,15 @@ static void test_rangelike(const char *rangelike, if (expected_left != NULL) { cl_assert_equal_i(0, error); cl_assert_equal_i(revparseflags, expected_revparseflags); - git_oid_fmt(objstr, &left); + git_oid_fmt(objstr, git_object_id(left)); cl_assert_equal_s(objstr, expected_left); - git_oid_fmt(objstr, &right); + git_oid_fmt(objstr, git_object_id(right)); cl_assert_equal_s(objstr, expected_right); } else cl_assert(error != 0); + + git_object_free(left); + git_object_free(right); } @@ -681,7 +686,7 @@ void test_refs_revparse__range(void) void test_refs_revparse__validates_args(void) { - git_oid l={{0}}, r={{0}}; + git_object *l, *r; git_revparse_flag_t flags = 0; cl_git_pass(git_revparse(&l,&r,NULL, g_repo, "HEAD")); diff --git a/tests-clar/repo/head.c b/tests-clar/repo/head.c index bb81bb087d4..a9f5cfc58d7 100644 --- a/tests-clar/repo/head.c +++ b/tests-clar/repo/head.c @@ -120,11 +120,9 @@ void test_repo_head__set_head_detached_Return_ENOTFOUND_when_the_object_doesnt_e void test_repo_head__set_head_detached_Fails_when_the_object_isnt_a_commitish(void) { - git_oid oid; git_object *blob; - cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "point_to_blob")); - cl_git_pass(git_object_lookup(&blob, repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&blob, repo, "point_to_blob")); cl_git_fail(git_repository_set_head_detached(repo, git_object_id(blob))); @@ -133,11 +131,9 @@ void test_repo_head__set_head_detached_Fails_when_the_object_isnt_a_commitish(vo void test_repo_head__set_head_detached_Detaches_HEAD_and_make_it_point_to_the_peeled_commit(void) { - git_oid oid; git_object *tag; - cl_git_pass(git_revparse(&oid, NULL, NULL, repo, "tags/test")); - cl_git_pass(git_object_lookup(&tag, repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&tag, repo, "tags/test")); cl_assert_equal_i(GIT_OBJ_TAG, git_object_type(tag)); cl_git_pass(git_repository_set_head_detached(repo, git_object_id(tag))); diff --git a/tests-clar/reset/default.c b/tests-clar/reset/default.c index bc8da739204..506d971ffba 100644 --- a/tests-clar/reset/default.c +++ b/tests-clar/reset/default.c @@ -95,7 +95,6 @@ void test_reset_default__resetting_filepaths_against_a_null_target_removes_them_ void test_reset_default__resetting_filepaths_replaces_their_corresponding_index_entries(void) { git_strarray before, after; - git_oid oid; char *paths[] = { "staged_changes", "staged_changes_file_deleted" }; char *before_shas[] = { "55d316c9ba708999f1918e9677d01dfcae69c6b9", @@ -110,8 +109,7 @@ void test_reset_default__resetting_filepaths_replaces_their_corresponding_index_ after.strings = after_shas; after.count = 2; - cl_git_pass(git_revparse(&oid, NULL, NULL, _repo, "0017bd4")); - cl_git_pass(git_object_lookup(&_target, _repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&_target, _repo, "0017bd4")); assert_content_in_index(&_pathspecs, true, &before); cl_git_pass(git_reset_default(_repo, _target, &_pathspecs)); @@ -137,7 +135,6 @@ void test_reset_default__resetting_filepaths_clears_previous_conflicts(void) { git_index_entry *conflict_entry[3]; git_strarray after; - git_oid oid; char *paths[] = { "conflicts-one.txt" }; char *after_shas[] = { "1f85ca51b8e0aac893a621b61a9c2661d6aa6d81" }; @@ -153,8 +150,7 @@ void test_reset_default__resetting_filepaths_clears_previous_conflicts(void) cl_git_pass(git_index_conflict_get(&conflict_entry[0], &conflict_entry[1], &conflict_entry[2], _index, "conflicts-one.txt")); - cl_git_pass(git_revparse(&oid, NULL, NULL, _repo, "9a05ccb")); - cl_git_pass(git_object_lookup(&_target, _repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&_target, _repo, "9a05ccb")); cl_git_pass(git_reset_default(_repo, _target, &_pathspecs)); assert_content_in_index(&_pathspecs, true, &after); @@ -171,15 +167,13 @@ Unstaged changes after reset: void test_reset_default__resetting_unknown_filepaths_does_not_fail(void) { char *paths[] = { "I_am_not_there.txt", "me_neither.txt" }; - git_oid oid; _pathspecs.strings = paths; _pathspecs.count = 2; assert_content_in_index(&_pathspecs, false, NULL); - cl_git_pass(git_revparse(&oid, NULL, NULL, _repo, "HEAD")); - cl_git_pass(git_object_lookup(&_target, _repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_revparse_single(&_target, _repo, "HEAD")); cl_git_pass(git_reset_default(_repo, _target, &_pathspecs)); assert_content_in_index(&_pathspecs, false, NULL); diff --git a/tests-clar/stash/drop.c b/tests-clar/stash/drop.c index da9e676a977..12f92263065 100644 --- a/tests-clar/stash/drop.c +++ b/tests-clar/stash/drop.c @@ -140,30 +140,29 @@ void test_stash_drop__dropping_the_last_entry_removes_the_stash(void) void retrieve_top_stash_id(git_oid *out) { - git_oid top_stash_id; + git_object *top_stash; - cl_git_pass(git_revparse(&top_stash_id, NULL, NULL, repo, "stash@{0}")); + cl_git_pass(git_revparse_single(&top_stash, repo, "stash@{0}")); cl_git_pass(git_reference_name_to_id(out, repo, GIT_REFS_STASH_FILE)); - cl_assert_equal_i(true, git_oid_cmp(out, &top_stash_id) == 0); + cl_assert_equal_i(true, git_oid_cmp(out, git_object_id(top_stash)) == 0); } void test_stash_drop__dropping_the_top_stash_updates_the_stash_reference(void) { - git_oid next_top_stash_id; + git_object *next_top_stash; git_oid oid; push_three_states(); retrieve_top_stash_id(&oid); - cl_git_pass(git_revparse(&next_top_stash_id, NULL, NULL, repo, "stash@{1}")); - cl_assert_equal_i(false, git_oid_cmp(&oid, &next_top_stash_id) == 0); + cl_git_pass(git_revparse_single(&next_top_stash, repo, "stash@{1}")); + cl_assert_equal_i(false, git_oid_cmp(&oid, git_object_id(next_top_stash)) == 0); cl_git_pass(git_stash_drop(repo, 0)); retrieve_top_stash_id(&oid); - cl_assert_equal_i( - true, git_oid_cmp(&oid, &next_top_stash_id) == 0); + cl_git_pass(git_oid_cmp(&oid, git_object_id(next_top_stash))); } diff --git a/tests-clar/stash/save.c b/tests-clar/stash/save.c index 4185e549c54..eae116ac5b2 100644 --- a/tests-clar/stash/save.c +++ b/tests-clar/stash/save.c @@ -37,11 +37,10 @@ void test_stash_save__cleanup(void) static void assert_object_oid(const char* revision, const char* expected_oid, git_otype type) { - git_oid oid; int result; git_object *obj; - result = git_revparse(&oid, NULL, NULL, repo, revision); + result = git_revparse_single(&obj, repo, revision); if (!expected_oid) { cl_assert_equal_i(GIT_ENOTFOUND, result); @@ -49,9 +48,7 @@ static void assert_object_oid(const char* revision, const char* expected_oid, gi } else cl_assert_equal_i(0, result); - cl_git_pass(git_oid_streq(&oid, expected_oid)); - - cl_git_pass(git_object_lookup(&obj, repo, &oid, GIT_OBJ_ANY)); + cl_git_pass(git_oid_streq(git_object_id(obj), expected_oid)); cl_assert_equal_i(type, git_object_type(obj)); git_object_free(obj); } @@ -147,11 +144,9 @@ void test_stash_save__can_keep_index(void) static void assert_commit_message_contains(const char *revision, const char *fragment) { - git_oid oid; git_commit *commit; - cl_git_pass(git_revparse(&oid, NULL, NULL, repo, revision)); - cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_revparse_single((git_object**)&commit, repo, revision)); cl_assert(strstr(git_commit_message(commit), fragment) != NULL); From 5961d5ea7f77cc442ec7d7c9f698f8c96c050298 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 15 Apr 2013 12:10:18 -0700 Subject: [PATCH 037/181] Clean up example code. --- examples/rev-list.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rev-list.c b/examples/rev-list.c index 1747f204103..f309207b042 100644 --- a/examples/rev-list.c +++ b/examples/rev-list.c @@ -14,7 +14,7 @@ static void check_error(int error_code, const char *action) exit(1); } -static int push_commit(git_revwalk *walk, git_oid *oid, int hide) +static int push_commit(git_revwalk *walk, const git_oid *oid, int hide) { if (hide) return git_revwalk_hide(walk, oid); @@ -27,7 +27,7 @@ static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, int error; git_object *obj; - if ((error = git_revparse(&obj, NULL, NULL, repo, spec)) < 0) + if ((error = git_revparse_single(&obj, repo, spec)) < 0) return error; error = push_commit(walk, git_object_id(obj), hide); git_object_free(obj); @@ -36,7 +36,7 @@ static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide) { - git_object left, right; + git_object *left, *right; git_revparse_flag_t flags; int error = 0; From 201566539f38874b4e93c6a36593bd0d10e6352c Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 15 Apr 2013 13:29:40 -0700 Subject: [PATCH 038/181] Clean up minor details --- examples/diff.c | 2 +- include/git2/revparse.h | 4 +--- include/git2/revwalk.h | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/diff.c b/examples/diff.c index a977abd3fca..2ef405665d1 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -17,7 +17,7 @@ static int resolve_to_tree( int err = 0; git_object *obj = NULL; - if ((err =git_revparse(&obj, NULL, NULL, repo, identifier)) < 0) + if ((err = git_revparse_single(&obj, repo, identifier)) < 0) return err; switch (git_object_type(obj)) { diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 4f8c274a467..a992d2c48e1 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -21,7 +21,6 @@ GIT_BEGIN_DECL /** - * * Find a single object, as specified by a revision string. See `man gitrevisions`, * or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for * information on the syntax accepted. @@ -31,8 +30,7 @@ GIT_BEGIN_DECL * @param spec the textual specification for an object * @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, GIT_EINVALIDSPEC or an error code */ -GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, - const char *spec); +GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, const char *spec); /** diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index c9f7372e9df..8bfe0b502da 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -221,7 +221,7 @@ GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode); * * The range should be of the form * .. - * where each is in the form accepted by 'git_revparse'. + * where each is in the form accepted by 'git_revparse_single'. * The left-hand commit will be hidden and the right-hand commit pushed. * * @param walk the walker being used for the traversal From 67ba7d2031f1eef63d66db6ce3ecaceddb06a4f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 15 Apr 2013 22:53:57 +0200 Subject: [PATCH 039/181] Allow git_remote_ls after disconnecting from the remote Keep the data around until free, as expected by our own fetch example --- src/remote.c | 5 ----- src/transports/local.c | 26 ++++++++++++++------------ src/transports/smart.c | 14 ++++++++------ tests-clar/online/fetch.c | 27 +++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/remote.c b/src/remote.c index 896361e3081..54f0a8ac28d 100644 --- a/src/remote.c +++ b/src/remote.c @@ -586,11 +586,6 @@ int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload) { assert(remote); - if (!git_remote_connected(remote)) { - giterr_set(GITERR_NET, "The remote is not connected"); - return -1; - } - return remote->transport->ls(remote->transport, list_cb, payload); } diff --git a/src/transports/local.c b/src/transports/local.c index ce89bb213e5..8af970eaca1 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -36,7 +36,8 @@ typedef struct { git_atomic cancelled; git_repository *repo; git_vector refs; - unsigned connected : 1; + unsigned connected : 1, + have_refs : 1; } transport_local; static int add_ref(transport_local *t, const char *name) @@ -139,6 +140,7 @@ static int store_refs(transport_local *t) goto on_error; } + t->have_refs = 1; git_strarray_free(&ref_names); return 0; @@ -208,8 +210,8 @@ static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *pay unsigned int i; git_remote_head *head = NULL; - if (!t->connected) { - giterr_set(GITERR_NET, "The transport is not connected"); + if (!t->have_refs) { + giterr_set(GITERR_NET, "The transport has not yet loaded the refs"); return -1; } @@ -569,8 +571,6 @@ static void local_cancel(git_transport *transport) static int local_close(git_transport *transport) { transport_local *t = (transport_local *)transport; - size_t i; - git_remote_head *head; t->connected = 0; @@ -579,13 +579,6 @@ static int local_close(git_transport *transport) t->repo = NULL; } - git_vector_foreach(&t->refs, i, head) { - git__free(head->name); - git__free(head); - } - - git_vector_free(&t->refs); - if (t->url) { git__free(t->url); t->url = NULL; @@ -597,10 +590,19 @@ static int local_close(git_transport *transport) static void local_free(git_transport *transport) { transport_local *t = (transport_local *)transport; + size_t i; + git_remote_head *head; /* Close the transport, if it's still open. */ local_close(transport); + git_vector_foreach(&t->refs, i, head) { + git__free(head->name); + git__free(head); + } + + git_vector_free(&t->refs); + /* Free the transport */ git__free(t); } diff --git a/src/transports/smart.c b/src/transports/smart.c index bfcce0c08d4..416eb221fe5 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -253,7 +253,6 @@ static int git_smart__read_flags(git_transport *transport, int *flags) static int git_smart__close(git_transport *transport) { transport_smart *t = (transport_smart *)transport; - git_vector *refs = &t->refs; git_vector *common = &t->common; unsigned int i; git_pkt *p; @@ -261,11 +260,6 @@ static int git_smart__close(git_transport *transport) ret = git_smart__reset_stream(t, true); - git_vector_foreach(refs, i, p) - git_pkt_free(p); - - git_vector_free(refs); - git_vector_foreach(common, i, p) git_pkt_free(p); @@ -284,6 +278,9 @@ static int git_smart__close(git_transport *transport) static void git_smart__free(git_transport *transport) { transport_smart *t = (transport_smart *)transport; + git_vector *refs = &t->refs; + unsigned int i; + git_pkt *p; /* Make sure that the current stream is closed, if we have one. */ git_smart__close(transport); @@ -291,6 +288,11 @@ static void git_smart__free(git_transport *transport) /* Free the subtransport */ t->wrapped->free(t->wrapped); + git_vector_foreach(refs, i, p) + git_pkt_free(p); + + git_vector_free(refs); + git__free(t); } diff --git a/tests-clar/online/fetch.c b/tests-clar/online/fetch.c index a0ee7aac815..bfa1eb9721f 100644 --- a/tests-clar/online/fetch.c +++ b/tests-clar/online/fetch.c @@ -134,3 +134,30 @@ void test_online_fetch__can_cancel(void) git_remote_disconnect(remote); git_remote_free(remote); } + +int ls_cb(git_remote_head *rhead, void *payload) +{ + int *nr = payload; + GIT_UNUSED(rhead); + + (*nr)++; + + return 0; +} + +void test_online_fetch__ls_disconnected(void) +{ + git_remote *remote; + int nr_before = 0, nr_after = 0; + + cl_git_pass(git_remote_create(&remote, _repo, "test", + "http://github.com/libgit2/TestGitRepository.git")); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH)); + cl_git_pass(git_remote_ls(remote, ls_cb, &nr_before)); + git_remote_disconnect(remote); + cl_git_pass(git_remote_ls(remote, ls_cb, &nr_after)); + + cl_assert_equal_i(nr_before, nr_after); + + git_remote_free(remote); +} From 36c2dfed696f80a20ca1352f32ec8b136b800c30 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 15 Apr 2013 23:32:40 +0200 Subject: [PATCH 040/181] Is this crazy? --- include/git2/revparse.h | 14 ++++++--- src/revparse.c | 32 +++++++++------------ src/revwalk.c | 19 ++++++------ tests-clar/refs/revparse.c | 59 +++++++++++++++++--------------------- 4 files changed, 60 insertions(+), 64 deletions(-) diff --git a/include/git2/revparse.h b/include/git2/revparse.h index a992d2c48e1..3e334b4bb1d 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -44,8 +44,16 @@ typedef enum { GIT_REVPARSE_RANGE = 1 << 1, /** The spec used the '...' operator, which invokes special semantics. */ GIT_REVPARSE_MERGE_BASE = 1 << 2, -} git_revparse_flag_t; +} git_revparse_mode_t; +/** + * Git Revision: output of a `git_revparse` operation + */ +typedef struct { + git_object *from; + git_object *to; + unsigned int flags; +} git_revision; /** * Parse a revision string for left, right, and intent. See `man gitrevisions` or @@ -64,9 +72,7 @@ typedef enum { * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code */ GIT_EXTERN(int) git_revparse( - git_object **left, - git_object **right, - unsigned int *flags, + git_revision *revision, git_repository *repo, const char *spec); diff --git a/src/revparse.c b/src/revparse.c index d2c14ccbb07..a4fedd27cb5 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -870,47 +870,43 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec int git_revparse( - git_object **left, - git_object **right, - unsigned int *flags, - git_repository *repo, - const char *spec) + git_revision *revision, + git_repository *repo, + const char *spec) { - unsigned int lflags = 0; const char *dotdot; int error = 0; - assert(left && repo && spec); + assert(revision && repo && spec); + + memset(revision, 0x0, sizeof(*revision)); if ((dotdot = strstr(spec, "..")) != NULL) { char *lstr; const char *rstr; - lflags = GIT_REVPARSE_RANGE; + revision->flags = GIT_REVPARSE_RANGE; - lstr = git__substrdup(spec, dotdot-spec); + lstr = git__substrdup(spec, dotdot - spec); rstr = dotdot + 2; if (dotdot[2] == '.') { - lflags |= GIT_REVPARSE_MERGE_BASE; + revision->flags |= GIT_REVPARSE_MERGE_BASE; rstr++; } - if ((error = git_revparse_single(left, repo, lstr)) < 0) { + if ((error = git_revparse_single(&revision->from, repo, lstr)) < 0) { return error; } - if (right && - (error = git_revparse_single(right, repo, rstr)) < 0) { + + if ((error = git_revparse_single(&revision->to, repo, rstr)) < 0) { return error; } git__free((void*)lstr); } else { - lflags = GIT_REVPARSE_SINGLE; - error = git_revparse_single(left, repo, spec); + revision->flags = GIT_REVPARSE_SINGLE; + error = git_revparse_single(&revision->from, repo, spec); } - if (flags) - *flags = lflags; - return error; } diff --git a/src/revwalk.c b/src/revwalk.c index 05e99c0b637..9e32198fc53 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -231,25 +231,26 @@ int git_revwalk_push_ref(git_revwalk *walk, const char *refname) int git_revwalk_push_range(git_revwalk *walk, const char *range) { - git_object *left, *right; - git_revparse_flag_t revparseflags; + git_revision revision; int error = 0; - if ((error = git_revparse(&left, &right, &revparseflags, walk->repo, range))) + if ((error = git_revparse(&revision, walk->repo, range))) return error; - if (revparseflags & GIT_REVPARSE_MERGE_BASE) { + + if (revision.flags & GIT_REVPARSE_MERGE_BASE) { /* TODO: support "..." */ giterr_set(GITERR_INVALID, "Symmetric differences not implemented in revwalk"); return GIT_EINVALIDSPEC; } - if ((error = push_commit(walk, git_object_id(left), 1))) + if ((error = push_commit(walk, git_object_id(revision.from), 1))) goto out; - error = push_commit(walk, git_object_id(right), 0); - out: - git_object_free(left); - git_object_free(right); + error = push_commit(walk, git_object_id(revision.to), 0); + +out: + git_object_free(revision.from); + git_object_free(revision.to); return error; } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index c1cfc58af23..ad520067b7b 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -31,33 +31,31 @@ static void test_id_inrepo( const char *spec, const char *expected_left, const char *expected_right, - git_revparse_flag_t expected_flags, + git_revparse_mode_t expected_flags, git_repository *repo) { - git_object *l, *r; - git_revparse_flag_t flags = 0; - - int error = git_revparse(&l, &r, &flags, repo, spec); + git_revision revision; + int error = git_revparse(&revision, repo, spec); if (expected_left) { char str[64] = {0}; cl_assert_equal_i(0, error); - git_oid_fmt(str, git_object_id(l)); + git_oid_fmt(str, git_object_id(revision.from)); cl_assert_equal_s(str, expected_left); - git_object_free(l); + git_object_free(revision.from); } else { cl_assert_equal_i(GIT_ENOTFOUND, error); } if (expected_right) { char str[64] = {0}; - git_oid_fmt(str, git_object_id(r)); + git_oid_fmt(str, git_object_id(revision.to)); cl_assert_equal_s(str, expected_right); - git_object_free(r); + git_object_free(revision.to); } if (expected_flags) - cl_assert_equal_i(expected_flags, flags); + cl_assert_equal_i(expected_flags, revision.flags); } static void test_object(const char *spec, const char *expected_oid) @@ -68,27 +66,26 @@ static void test_object(const char *spec, const char *expected_oid) static void test_rangelike(const char *rangelike, const char *expected_left, const char *expected_right, - git_revparse_flag_t expected_revparseflags) + git_revparse_mode_t expected_revparseflags) { char objstr[64] = {0}; - git_object *left = NULL, *right = NULL; - git_revparse_flag_t revparseflags; + git_revision revision; int error; - error = git_revparse(&left, &right, &revparseflags, g_repo, rangelike); + error = git_revparse(&revision, g_repo, rangelike); if (expected_left != NULL) { cl_assert_equal_i(0, error); - cl_assert_equal_i(revparseflags, expected_revparseflags); - git_oid_fmt(objstr, git_object_id(left)); + cl_assert_equal_i(revision.flags, expected_revparseflags); + git_oid_fmt(objstr, git_object_id(revision.from)); cl_assert_equal_s(objstr, expected_left); - git_oid_fmt(objstr, git_object_id(right)); + git_oid_fmt(objstr, git_object_id(revision.to)); cl_assert_equal_s(objstr, expected_right); } else cl_assert(error != 0); - git_object_free(left); - git_object_free(right); + git_object_free(revision.from); + git_object_free(revision.to); } @@ -96,7 +93,7 @@ static void test_id( const char *spec, const char *expected_left, const char *expected_right, - git_revparse_flag_t expected_flags) + git_revparse_mode_t expected_flags) { test_id_inrepo(spec, expected_left, expected_right, expected_flags, g_repo); } @@ -684,21 +681,17 @@ void test_refs_revparse__range(void) test_rangelike("be3563a^1.be3563a", NULL, NULL, 0); } -void test_refs_revparse__validates_args(void) -{ - git_object *l, *r; - git_revparse_flag_t flags = 0; - - cl_git_pass(git_revparse(&l,&r,NULL, g_repo, "HEAD")); - cl_git_pass(git_revparse(&l,NULL,&flags, g_repo, "HEAD")); - cl_assert_equal_i(GIT_EINVALIDSPEC, git_revparse(&l,&r,&flags, g_repo, "^&*(")); -} - void test_refs_revparse__parses_range_operator(void) { test_id("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, GIT_REVPARSE_SINGLE); - test_id("HEAD~3..HEAD", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_REVPARSE_RANGE); - test_id("HEAD~3...HEAD", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", - GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); + test_id("HEAD~3..HEAD", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE); + + test_id("HEAD~3...HEAD", + "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", + "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", + GIT_REVPARSE_RANGE | GIT_REVPARSE_MERGE_BASE); } From cbda09d00bb2aa703f90251b231c74d7acc6d21c Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 15 Apr 2013 23:40:46 +0200 Subject: [PATCH 041/181] git_revision -> git_revspec --- include/git2/revparse.h | 4 ++-- src/revparse.c | 18 +++++++++--------- src/revwalk.c | 14 +++++++------- tests-clar/refs/revparse.c | 28 ++++++++++++++-------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/include/git2/revparse.h b/include/git2/revparse.h index 3e334b4bb1d..c0479c3534a 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -53,7 +53,7 @@ typedef struct { git_object *from; git_object *to; unsigned int flags; -} git_revision; +} git_revspec; /** * Parse a revision string for left, right, and intent. See `man gitrevisions` or @@ -72,7 +72,7 @@ typedef struct { * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code */ GIT_EXTERN(int) git_revparse( - git_revision *revision, + git_revspec *revspec, git_repository *repo, const char *spec); diff --git a/src/revparse.c b/src/revparse.c index a4fedd27cb5..74635ed04c7 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -870,41 +870,41 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec int git_revparse( - git_revision *revision, + git_revspec *revspec, git_repository *repo, const char *spec) { const char *dotdot; int error = 0; - assert(revision && repo && spec); + assert(revspec && repo && spec); - memset(revision, 0x0, sizeof(*revision)); + memset(revspec, 0x0, sizeof(*revspec)); if ((dotdot = strstr(spec, "..")) != NULL) { char *lstr; const char *rstr; - revision->flags = GIT_REVPARSE_RANGE; + revspec->flags = GIT_REVPARSE_RANGE; lstr = git__substrdup(spec, dotdot - spec); rstr = dotdot + 2; if (dotdot[2] == '.') { - revision->flags |= GIT_REVPARSE_MERGE_BASE; + revspec->flags |= GIT_REVPARSE_MERGE_BASE; rstr++; } - if ((error = git_revparse_single(&revision->from, repo, lstr)) < 0) { + if ((error = git_revparse_single(&revspec->from, repo, lstr)) < 0) { return error; } - if ((error = git_revparse_single(&revision->to, repo, rstr)) < 0) { + if ((error = git_revparse_single(&revspec->to, repo, rstr)) < 0) { return error; } git__free((void*)lstr); } else { - revision->flags = GIT_REVPARSE_SINGLE; - error = git_revparse_single(&revision->from, repo, spec); + revspec->flags = GIT_REVPARSE_SINGLE; + error = git_revparse_single(&revspec->from, repo, spec); } return error; diff --git a/src/revwalk.c b/src/revwalk.c index 9e32198fc53..16f06624d80 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -231,26 +231,26 @@ int git_revwalk_push_ref(git_revwalk *walk, const char *refname) int git_revwalk_push_range(git_revwalk *walk, const char *range) { - git_revision revision; + git_revspec revspec; int error = 0; - if ((error = git_revparse(&revision, walk->repo, range))) + if ((error = git_revparse(&revspec, walk->repo, range))) return error; - if (revision.flags & GIT_REVPARSE_MERGE_BASE) { + if (revspec.flags & GIT_REVPARSE_MERGE_BASE) { /* TODO: support "..." */ giterr_set(GITERR_INVALID, "Symmetric differences not implemented in revwalk"); return GIT_EINVALIDSPEC; } - if ((error = push_commit(walk, git_object_id(revision.from), 1))) + if ((error = push_commit(walk, git_object_id(revspec.from), 1))) goto out; - error = push_commit(walk, git_object_id(revision.to), 0); + error = push_commit(walk, git_object_id(revspec.to), 0); out: - git_object_free(revision.from); - git_object_free(revision.to); + git_object_free(revspec.from); + git_object_free(revspec.to); return error; } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index ad520067b7b..74472b17587 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -34,28 +34,28 @@ static void test_id_inrepo( git_revparse_mode_t expected_flags, git_repository *repo) { - git_revision revision; - int error = git_revparse(&revision, repo, spec); + git_revspec revspec; + int error = git_revparse(&revspec, repo, spec); if (expected_left) { char str[64] = {0}; cl_assert_equal_i(0, error); - git_oid_fmt(str, git_object_id(revision.from)); + git_oid_fmt(str, git_object_id(revspec.from)); cl_assert_equal_s(str, expected_left); - git_object_free(revision.from); + git_object_free(revspec.from); } else { cl_assert_equal_i(GIT_ENOTFOUND, error); } if (expected_right) { char str[64] = {0}; - git_oid_fmt(str, git_object_id(revision.to)); + git_oid_fmt(str, git_object_id(revspec.to)); cl_assert_equal_s(str, expected_right); - git_object_free(revision.to); + git_object_free(revspec.to); } if (expected_flags) - cl_assert_equal_i(expected_flags, revision.flags); + cl_assert_equal_i(expected_flags, revspec.flags); } static void test_object(const char *spec, const char *expected_oid) @@ -69,23 +69,23 @@ static void test_rangelike(const char *rangelike, git_revparse_mode_t expected_revparseflags) { char objstr[64] = {0}; - git_revision revision; + git_revspec revspec; int error; - error = git_revparse(&revision, g_repo, rangelike); + error = git_revparse(&revspec, g_repo, rangelike); if (expected_left != NULL) { cl_assert_equal_i(0, error); - cl_assert_equal_i(revision.flags, expected_revparseflags); - git_oid_fmt(objstr, git_object_id(revision.from)); + cl_assert_equal_i(revspec.flags, expected_revparseflags); + git_oid_fmt(objstr, git_object_id(revspec.from)); cl_assert_equal_s(objstr, expected_left); - git_oid_fmt(objstr, git_object_id(revision.to)); + git_oid_fmt(objstr, git_object_id(revspec.to)); cl_assert_equal_s(objstr, expected_right); } else cl_assert(error != 0); - git_object_free(revision.from); - git_object_free(revision.to); + git_object_free(revspec.from); + git_object_free(revspec.to); } From e13a0647a062073fee9ec26f0f3101b50b620c8b Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 15 Apr 2013 23:54:28 +0200 Subject: [PATCH 042/181] Update docs --- include/git2/revparse.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/include/git2/revparse.h b/include/git2/revparse.h index c0479c3534a..e155c701296 100644 --- a/include/git2/revparse.h +++ b/include/git2/revparse.h @@ -47,26 +47,24 @@ typedef enum { } git_revparse_mode_t; /** - * Git Revision: output of a `git_revparse` operation + * Git Revision Spec: output of a `git_revparse` operation */ typedef struct { + /** The left element of the revspec; must be freed by the user */ git_object *from; + /** The right element of the revspec; must be freed by the user */ git_object *to; + /** The intent of the revspec */ unsigned int flags; } git_revspec; /** - * Parse a revision string for left, right, and intent. See `man gitrevisions` or + * Parse a revision string for `from`, `to`, and intent. See `man gitrevisions` or * http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for information * on the syntax accepted. * - * @param left buffer that receives the target of the left side of a range operator. If - * there is no range operator, this buffer receives the single target. - * @param right buffer that receives the target of the right side of a range operator. - * This is only filled in if `spec` specifies a range of commits. May - * be NULL. - * @param flags buffer that receives a bitwise combination of `git_revparse_flag_t` values. - * May be NULL. + * @param revspec Pointer to an user-allocated git_revspec struct where the result + * of the rev-parse will be stored * @param repo the repository to search in * @param spec the rev-parse spec to parse * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code From 404eadb089f5757842d2703ab1de849dd1f79a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 16 Apr 2013 00:11:59 +0200 Subject: [PATCH 043/181] remote: don't try to update FETCH_HEAD if no extra heads exist Don't try to update anything if there are no heads to update. This saves us from trying to look into a fetch refspec when there is none. A better fix for compatibility with git when using remotes without refspecs is still needed, but this stops us from segfaulting. --- src/remote.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/remote.c b/src/remote.c index 54f0a8ac28d..56853834b68 100644 --- a/src/remote.c +++ b/src/remote.c @@ -731,6 +731,10 @@ static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_hea assert(remote); + /* no heads, nothing to do */ + if (update_heads->length == 0) + return 0; + spec = &remote->fetch; if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0) From 32ef1d1c7cc8c603ab78416262cc421b80a8c2df Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 16 Apr 2013 00:17:40 +0200 Subject: [PATCH 044/181] Fix examples --- examples/rev-list.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/examples/rev-list.c b/examples/rev-list.c index f309207b042..d9ec15f7639 100644 --- a/examples/rev-list.c +++ b/examples/rev-list.c @@ -29,6 +29,7 @@ static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, if ((error = git_revparse_single(&obj, repo, spec)) < 0) return error; + error = push_commit(walk, git_object_id(obj), hide); git_object_free(obj); return error; @@ -36,24 +37,25 @@ static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide) { - git_object *left, *right; - git_revparse_flag_t flags; + git_revspec revspec; int error = 0; - if ((error = git_revparse(&left, &right, &flags, repo, range))) + if ((error = git_revparse(&revspec, repo, range))) return error; - if (flags & GIT_REVPARSE_MERGE_BASE) { + + if (revspec.flags & GIT_REVPARSE_MERGE_BASE) { /* TODO: support "..." */ return GIT_EINVALIDSPEC; } - if ((error = push_commit(walk, git_object_id(left), !hide))) + if ((error = push_commit(walk, git_object_id(revspec.from), !hide))) goto out; - error = push_commit(walk, git_object_id(right), hide); - out: - git_object_free(left); - git_object_free(right); + error = push_commit(walk, git_object_id(revspec.to), hide); + +out: + git_object_free(revspec.from); + git_object_free(revspec.to); return error; } From f124ebd457bfbf43de3516629aaba5a279636e04 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 16 Apr 2013 17:39:43 +0200 Subject: [PATCH 045/181] libgit2 0.18.0 "Big Ben" This is the last minor release before 1.0preview1. Highlights of this release include: - Branch API - Checkout head, index and tree - Finished clone support - Abstracted reference API to use custom backends - Full diff support - New (faster) packbuilder - Push support - New Remotes API - Revparse support (single and range commits) - Stash support - Submodules support As always, the full changelog is available at: http://libgit2.github.com/libgit2/#p/changelog Yeah, it's a huge release. Releasing stuff sucks. Expect 1.0 and API freeze in less than a month. Your faithful maintainer, vmg Signed-off-by: Vicent Marti --- include/git2/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/version.h b/include/git2/version.h index bc03e85d6c8..630d5152655 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,9 +7,9 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.17.0" +#define LIBGIT2_VERSION "0.18.0" #define LIBGIT2_VER_MAJOR 0 -#define LIBGIT2_VER_MINOR 17 +#define LIBGIT2_VER_MINOR 18 #define LIBGIT2_VER_REVISION 0 #endif From 5d7c940b07bfd2bc14ef67ef8a00fb03de59b97c Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Tue, 16 Apr 2013 13:25:38 -0700 Subject: [PATCH 046/181] /mailmap me --- .mailmap | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index 582dae0b99b..fb44eb82685 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 047/181] 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 e75c8b136f9..e3320975c76 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 0ad7449ba07..64ab2f4dba3 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 048/181] Add mailmap entries for me --- .mailmap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mailmap b/.mailmap index fb44eb82685..a8b17190875 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 049/181] Update link to Perl bindings --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 790e202d7de..fdddc5ca1c7 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 050/181] refs: Add `git_referene_target_peel` --- include/git2/refdb.h | 7 +- include/git2/refs.h | 11 +++ src/refdb_fs.c | 7 +- src/refs.c | 167 ++++++++++++++++++++++++------------ src/refs.h | 7 +- tests-clar/refdb/inmemory.c | 4 +- tests-clar/refdb/testdb.c | 16 ++-- 7 files changed, 148 insertions(+), 71 deletions(-) diff --git a/include/git2/refdb.h b/include/git2/refdb.h index 0586b119e3f..76b8fda0dcb 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 e0451ba8214..1ff0d45447a 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 f00bd72a0c4..730148a8feb 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 b1f679632a4..290b89b4162 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); -git_reference *git_reference__alloc( + 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 git_oid *oid, - const char *symbolic) + const char *target) { git_reference *ref; - size_t namelen; - assert(refdb && name && ((oid && !symbolic) || (!oid && symbolic))); + assert(refdb && name && target); - 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_SYMBOLIC; - if ((ref->target.symbolic = git__strdup(symbolic)) == NULL) { - git__free(ref); - return NULL; - } + if ((ref->target.symbolic = git__strdup(target)) == NULL) { + git__free(ref); + return NULL; } - ref->db = refdb; - memcpy(ref->name, name, namelen + 1); + return ref; +} + +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); + + ref = alloc_ref(refdb, name); + if (!ref) + return NULL; + + ref->type = GIT_REF_OID; + git_oid_cpy(&ref->target.direct.oid, oid); + + 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 @@ int git_reference_rename( 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); + type1 = git_reference_type(ref1); + type2 = git_reference_type(ref2); + /* let's put symbolic refs before OIDs */ - if (ref1->type != ref2->type) - return (ref1->type == GIT_REF_SYMBOLIC) ? -1 : 1; + if (type1 != type2) + return (type1 == GIT_REF_SYMBOLIC) ? -1 : 1; - if (ref1->type == GIT_REF_SYMBOLIC) + 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 (!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 = reference_target(&target, resolved)) < 0) { + 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 7d63c3fbdae..b0aa56a5412 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 6f565196416..2cccd8eb2e7 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 a8e7ba5fef7..e60f6790ef4 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 051/181] 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 24fa2102414..81dc5e3da85 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 052/181] 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 290b89b4162..982cd05b78e 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 053/181] 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 730148a8feb..784749fd3d2 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 982cd05b78e..29d1c4fa9bf 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 b0aa56a5412..97d4d2eb592 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 054/181] 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 e3320975c76..ed837b35910 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 055/181] 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 b92cc23fa52..6cf99ac1571 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 056/181] 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 164e8eb678b..649dbcd3d15 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 057/181] 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 17b3c378d9e..d2db8405502 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 058/181] 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 5b5ed95259f..dd8a6133ddf 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 4a4e6a9d850..7998f7c6bdf 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 00c46d6b10a..ef9bfc33d6c 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 059/181] 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 | 545 ++++++++++++++----------------------------------- 1 file changed, 154 insertions(+), 391 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index dd8a6133ddf..6eee5a805d9 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,389 +1105,141 @@ 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; } -int git_iterator_for_filesystem( - git_iterator **out, - const char *root, - git_iterator_flag_t flags, - const char *start, - const char *end) +static int fs_iterator__initialize( + git_iterator **out, fs_iterator *fi, const char *root) { 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; + 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 0; - -fail: - git_iterator_free((git_iterator *)fi); return error; } +int git_iterator_for_filesystem( + git_iterator **out, + const char *root, + git_iterator_flag_t flags, + const char *start, + const char *end) +{ + fs_iterator *fi = git__calloc(1, sizeof(fs_iterator)); + GITERR_CHECK_ALLOC(fi); -#define WORKDIR_MAX_DEPTH 100 + ITERATOR_BASE_INIT(fi, fs, FS, NULL); + + if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0) + fi->base.flags |= GIT_ITERATOR_IGNORE_CASE; + + return fs_iterator__initialize(out, fi, root); +} -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) - 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] == '/'); - } -} - -static workdir_iterator_frame *workdir_iterator__alloc_frame( - workdir_iterator *wi) -{ - 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); -} + size_t len; -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); -} + if (!path || (len = path->size) < 4) + return false; -static void workdir_iterator__seek_frame_start( - workdir_iterator *wi, workdir_iterator_frame *wf) -{ - if (!wf) - return; + if (path->ptr[len - 1] == '/') + len--; - if (wi->base.start) - git_vector_bsearch2( - &wf->index, &wf->entries, workdir_iterator__entry_cmp, wi); - else - wf->index = 0; + 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; - if (path_is_dotgit(git_vector_get(&wf->entries, wf->index))) - wf->index++; + return (len == 4 || path->ptr[len - 5] == '/'); } -static int workdir_iterator__expand_dir(workdir_iterator *wi) +static int workdir_iterator__frame_added(fs_iterator *fi) { - 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]); - } - - wf->next = wi->stack; - wi->stack = wf; + if (fi->stack->next != NULL) { + workdir_iterator *wi = (workdir_iterator *)fi; + ssize_t slash_pos = git_buf_rfind_next(&fi->path, '/'); - return workdir_iterator__update_entry(wi); -} + (void)git_ignore__push_dir(&wi->ignores, &fi->path.ptr[slash_pos + 1]); + } -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; - - iterator__clear_entry(entry); - - /* 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); + workdir_iterator *wi = (workdir_iterator *)fi; - if (!error && entry) - error = workdir_iterator__current(entry, iter); - - return error; -} + /* skip over .git entries */ + if (workdir_path_is_dotgit(&fi->path)) + return GIT_ENOTFOUND; -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; + /* reset is_ignored since we haven't checked yet */ + wi->is_ignored = -1; - /* 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); + /* check if apparent tree entries are actually submodules */ + if (fi->entry.mode != GIT_FILEMODE_TREE) + return 0; - /* 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; - } - - 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); + /* 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'; } - 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 060/181] 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 6eee5a805d9..a72f97eca5d 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; + } + + if (fi->leave_dir_cb) + (void)fi->leave_dir_cb(fi); - fi->stack = ff_next; - fi->depth--; + fi->stack = ff->next; + fi->depth--; + } - if (fi->frame_removed) - fi->frame_removed(fi); + 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 061/181] 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 | 134 ++++++++++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 31 deletions(-) diff --git a/tests-clar/repo/iterator.c b/tests-clar/repo/iterator.c index ef9bfc33d6c..2e53c48d727 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; - 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)); + char buf[64], sub[64]; + for (i = 0; i < dirs; ++i) { if (i % 2 == 0) { - p_snprintf(buf, sizeof(buf), "icase/dir%02d/file", i); + 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 < 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)); + 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) { - p_snprintf( - buf, sizeof(buf), "icase/dir%02d/sub%02d/file", i, j); - cl_git_mkfile(buf, buf); + size_t sublen = strlen(sub); + memcpy(&sub[sublen], "/file", sizeof("/file")); + cl_git_mkfile(sub, sub); + sub[sublen] = '\0'; } } } +} - 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)); +void test_repo_iterator__workdir_depth(void) +{ + git_iterator *iter; - if (j % 2 == 0) { - p_snprintf(buf, sizeof(buf), - "icase/dir%02d/sub01/moar%02d/file", i, j); - cl_git_mkfile(buf, buf); - } - } - } + 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); /* 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 062/181] 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 6290ec4e8e3..2afd28158cf 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 74635ed04c7..8a22a04f37d 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 2e53c48d727..9118dd17e62 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 063/181] 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 9118dd17e62..ab460735ce8 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 064/181] 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 e7088790e6f..956286b74ce 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 2cccd8eb2e7..ca721e97741 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 065/181] 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 a72f97eca5d..ff08c1ce005 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); - - assert(out && repo); + workdir_iterator *wi; - 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 066/181] Fix some minor issues --- README.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fdddc5ca1c7..a2a18765af6 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 067/181] 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 c98df247c94..1c7969fcb49 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 068/181] 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 6f36a3999d8..9494a8b018c 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 069/181] 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 76b8fda0dcb..0e3ec5eaf95 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 bf33817d6cd..20eb6a9ddcf 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 d9b73c6e79e..2a0fd702cfd 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 784749fd3d2..56b2b6a99f3 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 29d1c4fa9bf..5b5812aaedf 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 ca721e97741..ea76172cfdf 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 e60f6790ef4..4bca39878e8 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 ac517d8691f..053f412295c 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 973abae305e..412c4c5fd18 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 e39abeb051c..5ab84c48ecc 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 070/181] 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 12f92263065..60b3c72e0ce 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 071/181] 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 8b51ab21bec..01559221e9b 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 26537e20a5d..0bda6bcec62 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 072/181] 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 | 385 +++++++++++++++++----------- 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, 336 insertions(+), 205 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 9494a8b018c..7a161796f72 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 956286b74ce..88f05252923 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 0bbccd44b09..cb4053736e1 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 b60a95232ef..8ae34bddf7b 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 cec4c64af05..b6be1a4e123 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 a51b0cfab2b..0ed02f48bec 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 a7a4dd83423..339d10eb2ad 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 56853834b68..1c4b22bb9ed 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); + + 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 git_refspec__parse(refspec, val, is_fetch); + 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 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) 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) - goto cleanup; + if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0) + return -1; - if (git_refspec__serialize(&value, refspec) < 0) - goto cleanup; + /* Clear out the existing config */ + do { + error = git_config_delete_entry(config, git_buf_cstr(&name)); + } while (!error); - error = git_config_set_string( - config, - git_buf_cstr(&name), - git_buf_cstr(&value)); + 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; + } + } + + 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 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_ve 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 @@ static int git_remote_write_fetchhead(git_remote *remote, git_vector *update_hea 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 @@ int git_remote_update_tips(git_remote *remote) } +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); + if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0) + goto cleanup; - /* Is there a refspec to deal with? */ - if (fetch_refspec->src == NULL && - fetch_refspec->dst == NULL) - return 0; + git_vector_foreach(&remote->refspec_strings, i, refspec) { + git_refspec *spec = git_vector_get(&remote->refspecs, i); + assert(spec); - if (git_refspec__serialize(&serialized, fetch_refspec) < 0) - goto cleanup; + if (spec->push) + continue; - /* Is it an in-memory remote? */ - if (!remote->name) { - error = (callback(git_buf_cstr(&serialized), payload) < 0) ? GIT_EUSER : 0; - goto cleanup; - } + /* Every refspec is a problem refspec for an in-memory remote */ + if (!remote->name) { + if (callback(refspec, payload) < 0) { + error = GIT_EUSER; + goto cleanup; + } - if (git_buf_printf(&dst_prefix, ":refs/remotes/%s/", remote->name) < 0) - goto cleanup; + continue; + } - pos = strstr(git_buf_cstr(&serialized), git_buf_cstr(&dst_prefix)); + /* 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; + } - /* 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) + /* 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 4c1a18aa7f8..b1f33f0e76a 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 c4b482234b2..02066e07d11 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 a5ff7415fcb..92c9d8ac11d 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 a8a5bb91867..3cbdc7e93c4 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 907d6d29ff3..5dc7974c7d2 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 2beef372440..475fa54a86e 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 073/181] 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 7a161796f72..5dcd9309974 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 cb4053736e1..8f10ca819cb 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 1c4b22bb9ed..8b7e66e53b5 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 92c9d8ac11d..7b6e6aa853c 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 3cbdc7e93c4..e14ae0926cb 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 475fa54a86e..6043828b30c 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 074/181] 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 ec7830b7c6e..3e1b502ef75 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 0ed02f48bec..fbdea9d93e8 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 339d10eb2ad..29f4d53545f 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 8b7e66e53b5..ffce2b6e29e 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 b1f33f0e76a..c9c26b77dd9 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 7b6e6aa853c..908e17d9636 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 075/181] mailmap: Coalesce some identities --- .mailmap | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.mailmap b/.mailmap index a8b17190875..3f5a087eaf0 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 076/181] 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 19d4cb78db1..5a2f956fd64 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 00000000000..c9039e96e4e --- /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 5379b0ec5e5..1283522ca57 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 8b51ab21bec..a4ff8bb9481 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 2fdaf2f7770..0a22e3b13e5 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 28502a8babd..3fd6eb11478 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 077/181] 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 dfe6ae5aa7d..262dcd154dc 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 8fd1a95be57..b64436c4d67 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 dbc3981f69e..d38005d1572 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. - */ -typedef int (*git_odb_foreach_cb)(const git_oid *id, void *payload); - /** - * An instance for a custom backend + * Constructors for in-box ODB backends. */ -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 c9039e96e4e..1c9deba7cbd 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 00000000000..3cd2734c043 --- /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 bc15050ce64..aca9ed927e1 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 c0514fc1310..11e1f4d7750 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 c98df247c94..ecdaf7ac271 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 68083f7fd35..e78172cf69d 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 7240a4ac712..773e1497444 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 735ba7e1d5f..c82decbe36e 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 8acedeb4970..90851980c4b 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 1b28d0df7e4..60aa31f6a2e 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 e9d246c234a..4f9bde9ed1d 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 b4f9e44bca4..147a160c873 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 078/181] 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 ed837b35910..f55ab798fe1 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 64ab2f4dba3..72b5a079a44 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 079/181] 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 f55ab798fe1..08024cd89f5 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 00000000000..34bc175167b --- /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 72b5a079a44..a16f69da459 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 4d17da468fe..d41f3f12dff 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 7e482dee19f..063d76c8daa 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 b67107aec07..296c27c866b 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 080/181] 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 764053eaa38..e7ef51816f8 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 c7b83ed432b..e6bfd95ce63 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 ", git_object_id((const git_object *)tree)); + git_oid__writebuf(&commit, "tree ", 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 @@ int git_commit_create( 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 081/181] 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 e7ef51816f8..0f7601252c0 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 00000000000..096e028c56d --- /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 e6bfd95ce63..dd416920d9b 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 @@ int git_commit_create_oid( } 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 082/181] 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 0e3ec5eaf95..9278b11160c 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 20eb6a9ddcf..dcdf7bcb851 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 2a0fd702cfd..0675be63893 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 56b2b6a99f3..4d5d6006d76 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 5b5812aaedf..d9291e56f36 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 c0f27199706..af3ef0b4621 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 ea76172cfdf..2c76d419255 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 4bca39878e8..627254e4451 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 e38abd96704..49d1cb1d042 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 083/181] 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 9278b11160c..a315876aefd 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 dcdf7bcb851..d5f599fecb2 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 00000000000..85963258cd6 --- /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 0675be63893..33a1934d15d 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); - - *out = NULL; + assert(db && db->backend && out && ref_name); - 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 0969711b92d..047113ac847 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 4d5d6006d76..443871005da 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 d9291e56f36..9c6684a5a00 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 2c76d419255..243b5bb3758 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 49d1cb1d042..a0d1bbc48bd 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 084/181] 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 f4886c5d13f..9c9f837b9c7 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 085/181] 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 1c7969fcb49..8249c5adc2a 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 086/181] lol this worked first try wtf --- src/cache.c | 169 ++++++++++++++++++++++++++--------------- 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, 184 insertions(+), 139 deletions(-) diff --git a/src/cache.c b/src/cache.c index e7f33357722..6eb18dae59d 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) -{ - 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; +GIT__USE_OIDMAP +int git_cache_init(git_cache *cache) +{ + 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; + return true; +} - memcpy(&hash, oid->id, sizeof(hash)); +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)) { - giterr_set(GITERR_THREAD, "unable to lock cache mutex"); + if (git_mutex_lock(&cache->lock) < 0) return NULL; - } - { - 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); - if (node != NULL && git_oid_cmp(&node->oid, oid) == 0) { - git_cached_obj_incref(node); - result = node; + if (flags && entry->flags != flags) { + entry = NULL; + } else { + git_cached_obj_incref(entry); } } + git_mutex_unlock(&cache->lock); - return result; + return entry; } -void *git_cache_try_store(git_cache *cache, void *_entry) +static void *cache_store(git_cache *cache, git_cached_obj *entry) { - git_cached_obj *entry = _entry; - uint32_t hash; + khiter_t pos; - memcpy(&hash, &entry->oid, sizeof(uint32_t)); + git_cached_obj_incref(entry); - if (git_mutex_lock(&cache->lock)) { - giterr_set(GITERR_THREAD, "unable to lock cache mutex"); - return NULL; - } + if (!cache_should_store(entry)) + return entry; + + if (git_mutex_lock(&cache->lock) < 0) + return entry; - { - git_cached_obj *node = cache->nodes[hash & cache->size_mask]; + pos = kh_get(oid, cache->map, &entry->oid); - /* increase the refcount on this object, because - * the cache now owns it */ - git_cached_obj_incref(entry); + /* not found */ + if (pos == kh_end(cache->map)) { + int rval; - 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; + 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 { - git_cached_obj_decref(node, cache->free_obj); - cache->nodes[hash & cache->size_mask] = entry; + /* NO OP */ } - - /* increase the refcount again, because we are - * returning it to the user */ - git_cached_obj_incref(entry); - } - git_mutex_unlock(&cache->lock); + 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 7034ec26819..f30af9c3ef3 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 80fe5115218..5542ebc8e09 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 d6ea8c29aba..821fbd70c07 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 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) 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 @@ int git_odb_read_prefix( 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 7c018cc5041..9abf594e8fe 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 40274cd194f..dfa951af315 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 a16f69da459..cda75b85f5d 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 8e83d298e42..c4a8c786d9e 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 907339d512b..3173c648b2a 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 087/181] 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 6eb18dae59d..a0925a1883b 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 f30af9c3ef3..3461ff7d53e 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 088/181] 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 a0925a1883b..f49515ef34c 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 3461ff7d53e..f952830c519 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 5542ebc8e09..54ceea33cbe 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 089/181] 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 11e1f4d7750..7dce4f7eec7 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 f49515ef34c..316007bdf97 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 f952830c519..3633f62a787 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 81dc5e3da85..bb2f9060690 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 dd416920d9b..2057364b501 100644 --- a/src/commit.c +++ b/src/commit.c @@ -244,7 +244,7 @@ int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) 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 603dd754a35..baabbbafb8a 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 54ceea33cbe..2667fcaf146 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 821fbd70c07..16a842aa8aa 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 9abf594e8fe..22c6e166851 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 c82decbe36e..3095d1287ad 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 d2db8405502..6ffb07c6945 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 9d92d8d601f..435bd4f2c09 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 60aa31f6a2e..9709c0302cd 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 f95dc28d4db..9539bb24c7a 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 90e9f3abdab..b4f549b58f9 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 4f9bde9ed1d..0c6ed387b4d 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 090/181] 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 3633f62a787..d57f244dd4b 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 2667fcaf146..80b765ef982 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 c1e50593c0f..d187c55b734 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 091/181] 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 316007bdf97..c6e98359790 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 d57f244dd4b..65a6e5766d9 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 092/181] Some stats --- src/cache.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/cache.c b/src/cache.c index c6e98359790..f3ab8a68422 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 093/181] 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 5318e66b792..b8c3e42ce9a 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 094/181] 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 f3ab8a68422..9f3290f01a3 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 095/181] 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 b8c3e42ce9a..80d83d345b8 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 9f3290f01a3..f8cddeaca6f 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 65a6e5766d9..8b2aa1f79b6 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 c4a8c786d9e..0b5fbdc5a61 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 096/181] 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 7dce4f7eec7..732b0f3de26 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 bb2f9060690..62a73d6d0a0 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 2057364b501..2cee44cd2ac 100644 --- a/src/commit.c +++ b/src/commit.c @@ -244,7 +244,8 @@ int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) 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 baabbbafb8a..bd5b5201a46 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 3095d1287ad..b76895d0c80 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 6ffb07c6945..cc43b920ccf 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 097/181] 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 f8cddeaca6f..263f736fa3b 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 8b2aa1f79b6..13b630e89f3 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 0b5fbdc5a61..1ed5d5d16c7 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 098/181] 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 75ac9818657..1bffb4778ac 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 8d7e33dfe51..b734ac1636d 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 099/181] 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 00000000000..ec4b5e77564 --- /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 00000000000..8121247c9bc --- /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 100/181] 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 732b0f3de26..501c13d1a48 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 524734b1f69..4873505fdf0 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 263f736fa3b..c51be895ebb 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 13b630e89f3..e95d521fe60 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 2cee44cd2ac..3eca5b3412c 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 @@ int git_commit__parse_buffer(git_commit *commit, const void *data, size_t len) 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 1ab164c0b65..0c2c3ab5d91 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 80b765ef982..3698808c3bc 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; - - 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; + /* Parse raw object data */ + def = &git_objects_table[odb_obj->cached.type]; + assert(def->free && (def->from_odb || def->parse)); - 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 16a842aa8aa..53630dddc2b 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 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) 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 @@ int git_odb_read_prefix( 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 22c6e166851..0d9f9e2ea15 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 dfa951af315..a29c7cd35ff 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 b76895d0c80..7dadc7e60cf 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 c8e421ee63b..fb01a6f75e0 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 cc43b920ccf..e66fa2370d3 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 b77bfd9616f..cf47fb47865 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 b99d2799172..792b5762694 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 101/181] 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 501c13d1a48..a68c4cc3e2f 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 4873505fdf0..22e37cc3a16 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 3eca5b3412c..46c02c292c9 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 0c2c3ab5d91..d0981b125ba 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 3698808c3bc..b87a074043b 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 7dadc7e60cf..b9a806cd19c 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 @@ static int git_tag_create__internal( } 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 fb01a6f75e0..d0cd393c728 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 e66fa2370d3..d6d4b77d3e8 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 cf47fb47865..7cb2dd36c2d 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 792b5762694..ad2c746cab7 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 102/181] 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 d6d4b77d3e8..58eb92f3522 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 103/181] 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 | 218 ++++++++++++++++++++++++++++------------------- src/repository.h | 1 + src/util.h | 21 ++++- 8 files changed, 168 insertions(+), 102 deletions(-) diff --git a/src/global.c b/src/global.c index b7fd8e257e2..a0571d1270e 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 b35503d4676..7e5fcdfbc71 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 1bffb4778ac..3a2e7fb5ae9 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 b734ac1636d..b8014b1ea16 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 443871005da..742ac6260ed 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 cda75b85f5d..8744b91e609 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 @@ static int load_config( return error; } -int git_repository_config__weakptr(git_config **out, git_repository *repo) +static const char *path_unless_empty(git_buf *buf) { - if (repo->_config == NULL) { - git_buf global_buf = GIT_BUF_INIT, xdg_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT; - int res; - - const char *global_config_path = NULL; - const char *xdg_config_path = NULL; - const char *system_config_path = NULL; - - if (git_config_find_global_r(&global_buf) == 0) - global_config_path = global_buf.ptr; + return git_buf_len(buf) > 0 ? git_buf_cstr(buf) : NULL; +} - if (git_config_find_xdg_r(&xdg_buf) == 0) - xdg_config_path = xdg_buf.ptr; +int git_repository_config__weakptr(git_config **out, git_repository *repo) +{ + int error = 0; - if (git_config_find_system_r(&system_buf) == 0) - system_config_path = system_buf.ptr; + if (repo->_config == NULL) { + git_buf global_buf = GIT_BUF_INIT; + git_buf xdg_buf = GIT_BUF_INIT; + git_buf system_buf = GIT_BUF_INIT; + git_config *config; - res = load_config(&repo->_config, repo, global_config_path, xdg_config_path, system_config_path); + git_config_find_global_r(&global_buf); + git_config_find_xdg_r(&xdg_buf); + git_config_find_system_r(&system_buf); + + 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); + + 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); + + config = repo_swap_ptr(repo, &repo->_config, config); + if (config != NULL) { + GIT_REFCOUNT_OWN(config, NULL); + git_config_free(config); + } - repo->_config = config; - GIT_REFCOUNT_OWN(repo->_config, repo); - GIT_REFCOUNT_INC(repo->_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); - - if (res < 0) - return -1; + error = git_refdb_open(&refdb, repo); + if (!error) { + GIT_REFCOUNT_OWN(refdb, repo); - 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 cc2f8c2b8c1..873498de0c0 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 af3ef0b4621..a2233a7e831 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 104/181] 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 f0ad1df29d7..badbc0883ce 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 8744b91e609..59479dc923b 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 873498de0c0..cc2f8c2b8c1 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 2ca290adfaf..7b663182d7c 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 a2233a7e831..82435aee87c 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 105/181] 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 7b663182d7c..e53a60c0572 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 105f4b89e33..c78213f150a 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 106/181] 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 2cfbd3a5a35..50a9d3a37ea 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); - - memcpy(pack->pack_name, filename, namelen + 1); - - if (p_stat(filename, &st) < 0) { - giterr_set(GITERR_OS, "Failed to stat packfile."); - goto cleanup; - } + if (git_packfile_check(&pack, filename) < 0) + return -1; - 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 3a2e7fb5ae9..8e8a01aa952 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 + root_len, ".keep", sizeof(".keep")); + if (git_path_exists(p->pack_name) == true) + p->pack_keep = 1; - 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, ".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 e53a60c0572..dafe70ad6dc 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 c78213f150a..232709e54af 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 a219a013701..8277ecf6e8d 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 8121247c9bc..ed13a6fa878 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 107/181] 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 | 79 +++++++++++++++++++++++--------------------------- src/pack.c | 2 +- src/pack.h | 3 +- 4 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/indexer.c b/src/indexer.c index 50a9d3a37ea..60677192765 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 773e1497444..eec79259b85 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,80 +527,75 @@ 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; + struct pack_backend *backend = git__calloc(1, sizeof(struct pack_backend)); + GITERR_CHECK_ALLOC(backend); - if (git_packfile_check(&packfile, idx) < 0) + if (git_vector_init(&backend->packs, initial_size, packfile_sort__cb) < 0) { + git__free(backend); return -1; + } - 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.writepack = &pack_backend__writepack; backend->parent.free = &pack_backend__free; - *backend_out = (git_odb_backend *)backend; - + *out = 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) +int git_odb_backend_one_pack(git_odb_backend **backend_out, const char *idx) { struct pack_backend *backend = NULL; - git_buf path = GIT_BUF_INIT; + struct git_pack_file *packfile = NULL; - backend = git__calloc(1, sizeof(struct pack_backend)); - GITERR_CHECK_ALLOC(backend); - backend->parent.version = GIT_ODB_BACKEND_VERSION; + if (pack_backend__alloc(&backend, 1) < 0) + return -1; - if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < 0 || - git_buf_joinpath(&path, objects_dir, "pack") < 0) + if (git_packfile_alloc(&packfile, idx) < 0 || + git_vector_insert(&backend->packs, packfile) < 0) { - git__free(backend); + pack_backend__free((git_odb_backend *)backend); return -1; } - if (git_path_isdir(git_buf_cstr(&path)) == true) { - int error; + *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) - return 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.writepack = &pack_backend__writepack; - backend->parent.free = &pack_backend__free; + 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 8e8a01aa952..33cdf760a1e 100644 --- a/src/pack.c +++ b/src/pack.c @@ -885,7 +885,7 @@ static int packfile_open(struct git_pack_file *p) 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 b8014b1ea16..aeeac9ce15e 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 108/181] 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 ad2c746cab7..8de4401dcf6 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 109/181] 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 ed13a6fa878..b36bf2726fa 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 110/181] 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 80d83d345b8..ccd252fdad3 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 c51be895ebb..ca122fb77ec 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 e95d521fe60..1715c72200d 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 1ed5d5d16c7..c3fc69756a7 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 b36bf2726fa..a3eba873779 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 111/181] 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 82435aee87c..687afe084f6 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 b372f5b7098..b8ede126c1d 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 063d76c8daa..f34f1e471cf 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 112/181] 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 dafe70ad6dc..28ecd297e82 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 113/181] 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 ca122fb77ec..4b26d43513c 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 1715c72200d..f74fddfc91d 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 c3fc69756a7..2dec49f17bc 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 114/181] 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 4b26d43513c..b462af408f5 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 115/181] 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 742ac6260ed..2f2e671048f 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -240,7 +240,7 @@ static int packed_load(refdb_fs_backend *backend) 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 116/181] 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 ecb16630b65..5b32ac809a0 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 117/181] 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 2f033bef666..118b8d55442 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 459201f5844..56240125b99 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 118/181] 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 56240125b99..1329a9bc153 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 119/181] 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 d38005d1572..4c2493a253c 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 120/181] 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 5dcd9309974..f02b956780c 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 121/181] 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 ccd252fdad3..6101e13bcce 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 b462af408f5..88f643b35df 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 f74fddfc91d..1fb87dceae3 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 2dec49f17bc..ce67c7e62ce 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 122/181] 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 02066e07d11..50667373706 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 123/181] 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 8f10ca819cb..0665576e39c 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 50667373706..02066e07d11 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 124/181] 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 37c89f3f108..e6f5374e72c 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 125/181] 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 e6f5374e72c..d9348bba82b 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 126/181] 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 1283522ca57..cb9d4014c94 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 2f36df7d168..84de3a5ed34 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 cc2f8c2b8c1..f7f9ecb1fff 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 127/181] 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 | 38 ++++++++++---------------------------- src/ignore.h | 2 +- src/index.c | 17 ++++++++--------- 4 files changed, 27 insertions(+), 53 deletions(-) diff --git a/src/checkout.c b/src/checkout.c index 62a73d6d0a0..e29fccd057b 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 17779522c48..e150b958512 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; - - /* 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) { - 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); + int ignore_case = false; - git_config_free(cfg); - } + /* 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 (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 5af8e8e7d18..e00e4a8c862 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 2afd28158cf..d8ca78e5297 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 128/181] 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 cb9d4014c94..3c0bbe9a72d 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 129/181] 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 d9348bba82b..bce2914d182 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(opts->flags & GIT_DIFF_IGNORE_FILEMODE) - diff->diffcaps = diff->diffcaps & ~GIT_DIFFCAPS_TRUST_MODE_BITS; - - /* pathspec init will do nothing for empty pathspec */ - if (git_pathspec_init(&diff->pathspec, &opts->pathspec, &diff->pool) < 0) - goto fail; + /* 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; - /* TODO: handle config diff.mnemonicprefix, diff.noprefix */ + 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); + } - 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 34a3e506c6a..b8bb73bf73b 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 d41f3f12dff..40b191dd502 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 850feefde29..f05c7869e5a 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 130/181] 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 bce2914d182..881173cdeab 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 131/181] 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 34bc175167b..ba3d65ae567 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 88f643b35df..be4b037a33c 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 1fb87dceae3..16470e9c8be 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 59479dc923b..2161aa697d9 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 132/181] docs: formatting fixes --- include/git2/attr.h | 2 +- include/git2/common.h | 54 +++++++++++++++++++++---------------- include/git2/cred_helpers.h | 4 +-- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/include/git2/attr.h b/include/git2/attr.h index dea44f0e318..f099245b0ca 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 6101e13bcce..f9e9929eaa0 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_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. + * * 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_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 e3eb91d6c30..5d93cf4ddbf 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 133/181] 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 6bd25aacc99..1831c871778 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 be4b037a33c..1360cc97699 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 16470e9c8be..53fbcf4e99b 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 28ecd297e82..49b5f3b5e7b 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 ce67c7e62ce..8c8bc1a6ceb 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 134/181] 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 1ff0d45447a..e1d425352c3 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 9c6684a5a00..2faa4cb835f 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 fbdea9d93e8..256540819e2 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 b3d80fb858b..676a1fa996a 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 135/181] 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 29f4d53545f..44d484c7b96 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 ffce2b6e29e..1183137a6c0 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 7e847e654c8..74ef63dc95f 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 136/181] 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 90851980c4b..a5ad1e422e7 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 137/181] 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 ad1172dfa09..0d5746f2eda 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 138/181] 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 862f4b202b5..c35acdcdc24 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 ab69eeb1782..59c1546d779 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 139/181] 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 59c1546d779..4b6699009cf 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 08791cce651..d863a3e8519 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 140/181] 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 c35acdcdc24..8d93e79cfd9 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 4b6699009cf..c7ce6ee503c 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 d863a3e8519..7ee6fb67dab 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 141/181] 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 1831c871778..9f6b06bf12d 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 142/181] 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 53630dddc2b..64e1232f5f2 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 143/181] 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 8d93e79cfd9..288e90bc859 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 979fecc147c..6dd2c7e2fa7 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 e29fccd057b..96e15093c56 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 0665576e39c..aeb7bbf5cf0 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 881173cdeab..6612abf063d 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 b8bb73bf73b..4ce01bc62ed 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 efcb19d9551..5c1a86cb972 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 d8ca78e5297..2e2d373b553 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 60677192765..91b7ba5d980 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 53630dddc2b..2574c678970 100644 --- a/src/odb.c +++ b/src/odb.c @@ -764,7 +764,7 @@ int git_odb_read_prefix( 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 c7ce6ee503c..e74640c5776 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 33cdf760a1e..f8b621ef8f5 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 b6be1a4e123..9b1e78c8eca 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 9c6684a5a00..f3a5041472c 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 97d4d2eb592..908e86f29e3 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 ffce2b6e29e..306bc7356fa 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 8af970eaca1..8b4d50c14ac 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 144/181] 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 0a2aa9d364a..8fca48966b5 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 84c954c27f6..469b1d72bea 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 73bfc86f42e..6ad72204842 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 a68c4cc3e2f..d656576b8f9 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 d187c55b734..906d4073601 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 b9a806cd19c..ad3a8fd361a 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 58eb92f3522..67c9a068d52 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 145/181] 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 00000000000..077d0a4c8f6 --- /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 146/181] 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 288e90bc859..b20bb221aee 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 d656576b8f9..25ea0df3086 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 906d4073601..7b25fc342ac 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 ad3a8fd361a..a0ecce176ec 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 67c9a068d52..0a94aec10c9 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 147/181] 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 3e1b502ef75..89ab81b02f1 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 256540819e2..a907df84c67 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 148/181] 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 89ab81b02f1..c0b410cbfdc 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 f02b956780c..2aa384a54f3 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 1183137a6c0..153c934703c 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 02066e07d11..545fe3a06d8 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 908e17d9636..4c24db8eb9c 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 149/181] 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 153c934703c..08f56cd5163 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 150/181] 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 3c0bbe9a72d..2e1268ef373 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 7f93ae91a0e..6b52537975e 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 151/181] 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 0f7601252c0..f536ac7c8d9 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 25ea0df3086..a68c4cc3e2f 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 7b25fc342ac..d187c55b734 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 00000000000..620617dfd32 --- /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 a0ecce176ec..a4f2e2581fa 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 0a94aec10c9..79cbcffcbe5 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 152/181] 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 620617dfd32..838bba3233e 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 153/181] 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 6612abf063d..58c7eacc6f6 100644 --- a/src/diff.c +++ b/src/diff.c @@ -530,24 +530,30 @@ int git_diff__oid_for_file( 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 154/181] 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 | 203 ++++++++++++++++++++--------- 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, 199 insertions(+), 83 deletions(-) diff --git a/include/git2/diff.h b/include/git2/diff.h index d9ceadf207f..cc16d01b65f 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 40934b3ed4d..004665050d0 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 58c7eacc6f6..cea3fdb22a1 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)); - - /* 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; - } + git_buf base = GIT_BUF_INIT; + bool is_ignored; - /* 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; - } + *delta_type = GIT_DELTA_IGNORED; + git_buf_sets(&base, info->nitem->path); - if (contains_oitem || recurse_into_dir) { - /* advance into directory */ - error = git_iterator_advance_into(&info->nitem, info->new_iter); + /* advance into untracked directory */ + if ((error = git_iterator_advance_into(&info->nitem, info->new_iter)) < 0) { - /* 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 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; } - /* return UNMODIFIED to tell caller not to create a new record */ - *delta = GIT_DELTA_UNMODIFIED; + 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); + + /* 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); + } if (S_ISDIR(nitem->mode)) { - error = handle_unmatched_new_directory(diff, info, &delta_type); + 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; + } - if (error || delta_type == GIT_DELTA_UNMODIFIED) - return error; + /* 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 "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. + /* 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 f4a818ed287..5ba2fab182e 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 24546d45c65..f073c249127 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 1aa0263eec1..ae1469e79e2 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 a9b8a12ed01..0138b1712ef 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 282e827580a..fca84af634b 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 155/181] 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 19c005e2e0c..e7f97c034fb 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 674fd8e195a..b39a69d1d81 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 435bd4f2c09..94fd7165d11 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 156/181] 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 cc16d01b65f..0ef47c018b5 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 157/181] 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 cea3fdb22a1..a154e67e8f5 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 4ce01bc62ed..64ff6b5be27 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 158/181] 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 08024cd89f5..cd238e17c2d 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 2f2e671048f..5228cb811d5 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 2161aa697d9..e6eaf753c79 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 f7f9ecb1fff..bd5f63dac04 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 159/181] merge! --- docs/merge-df_conflicts.txt | 41 + include/git2/index.h | 6 +- include/git2/merge.h | 64 +- src/index.c | 19 +- src/merge.c | 846 +++++++++++++++++- 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, 3099 insertions(+), 34 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 00000000000..09780ee2d22 --- /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 3d4bd15a83f..fcfe4be3d76 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 f4c5d988117..43a61f0e4ce 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 2e2d373b553..fe3a2104b31 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 e0010d6a4d7..8df156abee6 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 "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 "commit_list.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 @@ int git_repository_merge_cleanup(git_repository *repo) 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 @@ int git_repository_mergehead_foreach(git_repository *repo, 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 22c644270da..6307d1569ea 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 + +/** 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); -int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_list_node *one, git_vector *twos); +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 00000000000..4b3f3730b75 --- /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 00000000000..1aa34893d05 --- /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 00000000000..b10e9ec3200 --- /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 00000000000..1a0b8921bf4 --- /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 00000000000..7592a926e21 --- /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 00000000000..0661ce5b3e7 --- /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 00000000000..b2554f8be3b --- /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 00000000000..54b07e74a1f --- /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 946c67e7bc1..6ae9dbb147c 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 00000000000..245b18a2c50 --- /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 00000000000..cb089cd89a7 --- /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 00000000000..4092d428f13 --- /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 00000000000..af107929f2d --- /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 00000000000..498b267a8c7 --- /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 00000000000..8b0acb7020e --- /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 00000000000..df7695a66dd --- /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 00000000000..a504ad610bd --- /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 00000000000..27d833eda29 --- /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 00000000000..c4706175d1c --- /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 00000000000..60475992a29 --- /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 00000000000..0b6c9214a3d --- /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 00000000000..5392a4f8652 --- /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 00000000000..7db5617c800 --- /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 00000000000..b0f9e42ef14 --- /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 00000000000..614563edfe3 --- /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 00000000000..4c812eaccb2 --- /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 00000000000..58a7e0565bf --- /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 00000000000..5645ecee730 --- /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 00000000000..b6bd247e751 --- /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 00000000000..14ce9e545e9 --- /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 00000000000..3e6b7743707 --- /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 00000000000..30d5ec7a34b --- /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 00000000000..3a7302dea28 --- /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 00000000000..bb260424483 --- /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 00000000000..4b70d2898af --- /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 00000000000..8e491ca6844 --- /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 00000000000..a2a28d40121 --- /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 00000000000..a0a48ae3519 --- /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 00000000000..4374d3888b4 --- /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 00000000000..7a2e6f8223c --- /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 00000000000..3ee6d250333 --- /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 00000000000..51f8a9290df --- /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 00000000000..14497029aa9 --- /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 00000000000..4cff8352654 --- /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 00000000000..3ca077b2969 --- /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 00000000000..e7bb901f27d --- /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 00000000000..7c717a2105e --- /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 00000000000..715f3ae1c2c --- /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 00000000000..a014f1722b2 --- /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 00000000000..22331d78ccf --- /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 00000000000..7670c35066a --- /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 00000000000..c4d68edcf8b --- /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 00000000000..09a343bdb52 --- /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 00000000000..1b126fb7bed --- /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 00000000000..a83ffc26a56 --- /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 00000000000..65fa6894fe2 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/05/1ffd7901a442faf56b226161649074f15c7c47 @@ -0,0 +1 @@ +x+)JMU06·`040031QH,-ÉÏM-JOMLÊIÕ+©(aH:,»:ÎCÉýúô:ÞË ²o>ZC'g$楧¦èfæé&%æ%g€5¬ÎqYôÂeÒZoÇÝÙkÚMíæ2­éÆÔ›X\’ZDPC~^ZNfrIf^:Xéõ›ZHÙŠž1O(_œ,'º× jvn~JfZ&Ä5†&ȚؽùÁ„ +gÆz¬Ÿ¥•4íú3Ž^¨¦¢ÔÜü2 ÜüI{•|þ¹÷ 2m»gÜ˾‹©É1ÖËåüŠ5Ó¿Ü,\“µ})TC)0XÀ¡vÿ‰ùzÖ›¦9–¤×Mü°úÕ…'6óbó#— \ 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 00000000000..6555194cb0e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/11/f4f3c08b737f5fd896cbefa1425ee63b21b2fa @@ -0,0 +1 @@ +x¥ŽQ Dýæ\ fw)cüñ^` Û´‰-Q¯/oàßÌ›Ìdb^×¥j²´«EDC²$†­u‚>Œ ¡÷,Ö z@Œ8¢’ºq‘­jk<Ù©GŽ>¹Òz2Lva2)¸VeÅ:ç¢ÏéÅ%éËœ×{ÞôAý¨“|ƒŸÛǼ5K@ˆº mg«ü9£jYž _;„n,¼ÅY½y²P” \ 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 00000000000..064423d0c9e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/15/8dc7bedb202f5b26502bf3574faa7f4238d56c @@ -0,0 +1,2 @@ +x¥ŽK!D]sùCbŒoà i2. b¼¾£ñîªÞK*E½µÛep73UƒÓ¾*NYYôI²Ô”)–j¼ŠL:8§<‹{¼NˆÞ“‹ÎÊH6iDC¶Ê"mqH!–Ì9T¥mé9—>àR^i¸.½=ú +GÞè'ù+~í@½@j+ƒ7ÑØ£EÝÎNþsFtš]‰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 00000000000..82d65253bf9 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/16/f825815cfd20a07a75c71554e82d8eede0b061 @@ -0,0 +1 @@ +x¥ŽK!D]sšObŒoà Œ ƒ¯ïh¼»ª÷’Jqoí6A¹›£°JÙ€ˆ¬“T1h¢3§£·Î'LÕ ó.‰{eœc,a`ŠZJÃT1#e+Ù‡œJòUiª">çÒ\ò+Ž ×¥·G_áX6úIçò¿vàÞN€šÐ;ÈÀ^’”b£ÛÙYþœgGñ—MMµ \ 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 00000000000..83253f81c68 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/2d/a538570bc1e5b2c3e855bf702f35248ad0735f @@ -0,0 +1,2 @@ +x¥ŽK +1D]ç¹€ÒùN"n¼{ét:Œ‹L$ñúŽâ ÜU½EQ«õ>¤¶~7:³L ðÙD [´±5—¬É‡,Øy2e®ÐTت@”¦z*.û(ë´Àç˜[——üžåunum‹<òF?éÌ_ñkjõ$•qNå'#÷àÄF·³ƒÿœ¹Üp!^Gëâ 9+Q. \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/2f/2e37b7ebbae467978610896ca3aafcdad2ee67 b/tests-clar/resources/merge-resolve/.gitted/objects/2f/2e37b7ebbae467978610896ca3aafcdad2ee67 new file mode 100644 index 0000000000000000000000000000000000000000..7adffb165a09cdd027d1c4d38f98908e2e1fc65a GIT binary patch literal 52 zcmV-40L%Y)0ZYosPf{>3VhBpj%`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%hò•aãJYÁÕ®Aâ8Õ©í› fçà²ûN©ì¦¯4À;œ”h[º%cÍO¦ÆÎÕÑuJÑ÷çWÖyÎ \ 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 00000000000..1d9f226e2cb --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/2f/598248eeccfc27e5ca44d9d96383f6dfea7b16 @@ -0,0 +1 @@ +x+)JMU067c040031QH,-ÉÏM-JOMLÊIÕ+©(aH:,»:ÎCÉýúô:ÞË ²o>ZC'g$楧¦èfæé&%æ%g€5¬ÎqYôÂeÒZoÇÝÙkÚMíæ2­éÆÔ›X\’ZDPC~^ZNfrIf^:Xéõ›ZHÙŠž1O(_œ,'º× jvQjn~Ä1–ÈÎÑ×3ßþzדôém9‹Wý¹ué]:¦$÷ßüI{•|þ¹÷ 2m»gÜ˾‹©Éý1ÖËåüŠ5Ó¿Ü,\“µ})TC)0PÀavý‰ùzÖ›¦9–¤×Mü°úÕ…'6óbˆ—¢ \ 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 00000000000..2de1c5a791f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/31/68dca1a561889b045a6441909f4c56145e666d @@ -0,0 +1,2 @@ +x¥ŽQ +Â0DýÎ)rJ²›MñÇxM²¥ÛHŒz}«xÿfÞƒaRY–¹ip´kUD $Ï1f¢Q2qê-Ó=Y£ëÁ3R7®²6äÄ¡·Œgàâ9e7 bæ¡w ‚âG›JÕçüâšõe*˽¬ú ý¤“|ůíSYŽÚ"5&Ðñƨng›ü9£ZŸ3_;kÕ¬dO¼ \ 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 pcmbÕy­‹>çî隿ï¤ÎmŒŠú 6ºÉöüç*¼öRÛn¢>úå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 00000000000..c653cec50ce --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/34/bfafff88eaf118402b44e6f3e2dbbf1a582b05 @@ -0,0 +1 @@ +x•ŽKj1D½Ö)ú úµ>`Œ7¾A. µ$<`MŒ¯orlŠ¢ ¸÷m‚¶þ4G­›·&údVdƒ[j2ÖµËJÉâ›C«ÑŠgu_GuÒ%ÅÚ2:ƒ3XúزÅàQ‘'Ì"½æÜÊ;?wîïp®kým×¾ÑàƒÛü&îPf!¢ ð%QJ±Ö%:ëûCˆeœzâ½=6šÀ¯qˆ;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 00000000000..be7684f1913 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/35/632e43612c06a3ea924bfbacd48333da874c29 @@ -0,0 +1 @@ +x¥NË !õLÓÀšd–MŒñb60ÀÝă¨í‹Æ¼½^,ëº40;·iUFf+)›³ˆ1vòBÁ939fG–(ôDIݸʵA$s´è½k]’l|Lä{IgŠ™Ñ$‰Šm.NéÅ5Áy.ë½\a/]ý £|ÛÆ²@[g4âä< Hˆª«ýl“?gT«ËsáË µzCøP˜ \ 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 00000000000..e95ff3a88f0 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/38/5c8a0f26ddf79e9041e15e17dc352ed2c4cced @@ -0,0 +1,2 @@ +x-MK +1 uS¼YÍRÄ…ñ™6C±…6Ò뛪ð¼okn÷ÇåYt àEpª iÅDûØCd§Éœ³dLõB+8ø%¨q‚±ƒk µÿú+Þe™Þ6¢ï‡©fHüBü·¯1J©ÕÓ4ùFà1l \ 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@"n¼èt:Œ‹™‰x}£xwU¯ xÜj½um'»ë«ˆ.®Ì9»=y 6Ø$@T8ÌÀ‰&Lhf4êA«Ü»f¡0BŒ(ˆ.K±‘³>9S<›À +zö¥­ú’_´f}]ZÝÚ]eÐO:Ëwøµ·zÒš†‹ÞƒPƒÙ.Þ¨aNU6õÎOÖ \ 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#0²’cTôhS©úÌ/ª¬/SYîeÕÙè'ä+~mŸÊrÔh\c‡QwàÔF·³MþœQ­ÎÏ™®]èb¥5Mê ¨Ú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)8QiyZHoJkvÏmy´›ÞËJ?é(_ñk»Ü–ƒ6è-$ç#è-€ZézvÈŸ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È$Ñ^•‘R²bâÏØ[‡{þ=Ãcoõj'|褯õUéíje¼K«Ÿ°¬Ln¡•n–¬5“ÎСÿP˜Y«‚´³|2`ìzôËü—zQ{ \ 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 00000000000..bc2d7384d25 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/63/247125386de9ec90a27ad36169307bf8a11a38 @@ -0,0 +1 @@ +xÝ;1 D©}Šé¶A‹Vâô\ÀÙ8¬¥àHIVp|²?‰‚ÐLãyO“ÃuN7C] Í¥ƒËlãt¦:iAÐ(xiŒp‚,ÆOñÄæ¡;•æo†7 …UYZ B‡½ß÷ý]ÆdUmÔyk©ô[…½Ú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 00000000000..ffda698f046 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/67/18a45909532d1fcf5600d0877f7fe7e78f0b86 @@ -0,0 +1 @@ +x¥ŽÑM1 DùNi`‘ǹDBè~è€ǧ]‰Ý ƒöYð7óž4íû¾M8<ÌaæF䬵@Ò˜r*‹Ü85ÆV«±eV÷.Î鉋”0($!“b½UÑ35É—¨¡8¹ÏµÿÒ¾d4ÿºöý£þÉNú“®ö+þÚ£öýÙ#q@€rÉ~àNzžöÏ7Çö¹ÉÛ‚¸Ô!‡®î÷uQu \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/68/c6c84b091926c7d90aa6a79b2bc3bb6adccd8e b/tests-clar/resources/merge-resolve/.gitted/objects/68/c6c84b091926c7d90aa6a79b2bc3bb6adccd8e new file mode 100644 index 0000000000000000000000000000000000000000..1e4b0757413ab8f3a4fe2dbf2ecec68a159d0bfc GIT binary patch literal 55 zcmV-70LcG%0ZYosPf{?mG-fEtNG(cL$ShXK%U4LwNX$zIa`F^PGJqm!nK`L?T%!s` N!(p(c2LRAl@fd*X7ajlr literal 0 HcmV?d00001 diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/69/f570c57b24ea7c086e94c5e574964798321435 b/tests-clar/resources/merge-resolve/.gitted/objects/69/f570c57b24ea7c086e94c5e574964798321435 new file mode 100644 index 0000000000000000000000000000000000000000..6975f0bab187889e713dbe5de4f82142ae7896e6 GIT binary patch literal 266 zcmV+l0rmcP0V^p=O;s>9H)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 zyOÈJ?é$_ñk[ªóQ,ìÑë"€Zéz¶ËŸ3ª·é9¥ë€ê LŽOÊ \ 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 00000000000..67271ac5095 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/84/9619b03ae540acee4d1edec96b86993da6b497 @@ -0,0 +1,3 @@ +x¥ŽK +1D]ç¹€Òùv7ÞÀ½t’3‹L$ñúŽâ ÜU½E¥Vë<¤¶v7:³"xç¥K@›R¶ +rÌŠ#Ç"Ôy2[ Xµ5 r2ÆQ´ˆå¨5–”£bŠ=ÇÔº¼æõ,oS«k[ä‰7úIþŠ_;¤VÏRç”?ú`ä<€ØèvvðŸ3"¶1ÝóÜWñEÇP \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/84/de84f8f3a6d63e636ee9ad81f4b80512fa9bbe b/tests-clar/resources/merge-resolve/.gitted/objects/84/de84f8f3a6d63e636ee9ad81f4b80512fa9bbe new file mode 100644 index 0000000000000000000000000000000000000000..32f1461d40d08014636f37123dd8c6aaac836984 GIT binary patch literal 41 zcmV+^0M`F_0ZYosPf{>4X9&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æé&%æ%g€5¬ÎqYôÂeÒZoÇÝÙkÚMíæ2­éÆÔ›X\’ZDPC~^ZNfrIf^:Xéõ›ZHÙŠž1O(_œ,'º× jv^j9È!Ɖ9%`¥<sBÞ§ÝHrèSæ¼3§d ã ¨Ò¢ÔÜü2 wßüI{•|þ¹÷ 2m»gÜ˾‹©ÉÝ1ÖËåüŠ5Ó¿Ü,\“µ})TC)00ÀavʉùzÖ›¦9–¤×Mü°úÕ…'6óbÊå’G \ 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 00000000000..f4249c23df4 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/8b/5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a @@ -0,0 +1 @@ +xí± À0 S{Š"2ŽŒd,0²‘^?&S¤HóÕÝŸ[Ï8ï눪E›`Ñ„ËrƒZŠ*êdŒ¥­ÆrlŒ,©± Ù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 00000000000..e42393cf71e --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/8c/749d9968d4b10dcfb06c9f97d0e5d92d337071 @@ -0,0 +1,2 @@ +x¥ŽAB!C]s +. a€ùcÜx÷f`†|_ b¼¾h¼»ö5mšëº^»¶ÞmzÑÙL“`ð”}$26#"8°ÅÆ`s.`Ԛܺ.!bH\<» i´"Á,K¦œ8¯èÙ—Úô‰_ÔXŸ—º>êMïeÐ:Ê7ø¹]®ëAƒC40ÏÞë­™Œ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 00000000000..de9ba2894a8 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/95/646149ab6b6ba6edc83cff678582538b457b2b @@ -0,0 +1,3 @@ +x•ŽM …]s +. ™ÃObŒoàÞ eH»h1ãõEÓ ¸{?y_ÞX–enR}h•Y* üHFS +€S ž!$À1…¨Å“*¯M’³˜£wUv4ôIt:ª„è²ÏÞ8KFEA¯6•*oéM5ÉûT–­¬òÌ=ýª+ÿŠÝƲ\ä Ñ CVÁˆžö³ÿÆà`ƒnLj”ÛœX‰iO\ \ 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 00000000000..6f5e9797842 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/98/ba4205fcf31f5dd93c916d35fe3f3b3d0e6714 @@ -0,0 +1 @@ +x-ŒÁ Ã0 ûÖ ÐþºG% È…­"ë×Mú!@yÉjÂýñ¼½Šv¬j‚¢:ïAÜÁ‹ÂAÇèM~dú¹­ãÐ{.3Ñ);ÔlÂç]vi›ú6Á„D%þ «¯¦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 00000000000..c8d636e8be9 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/98/d52d07c0b0bbf2b46548f6aa521295c2cb55db @@ -0,0 +1,3 @@ +xíA +€0=÷y„}NË®taÝJ[ï +ú/^r“’´$ŒÓ<ô, ‡¨"1*[\™ †žYj Ñ‹(;Ôóm£9ƒ oNŒxcëz"1ï(»7„áy÷Û—.øõ®þ \ 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 00000000000..67126c90b78 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/a7/dbfcbfc1a60709cb80b5ca24539008456531d0 @@ -0,0 +1 @@ +x¥NË !õL4 a˜ÀÄ/vàÝð²{`1,ÆöEcÞÞ?/ÖR–.õ„»Þ˜%3$“ÁL15fe53'4Á2ÅÃ7^G1yBGV…LAGä Ù*‘ôä|R) ÿìsmòš^¾%y›kÙê*O<Ôºð×ø±C¬å,‰À’{e”Cg;ÿ9#R¾oKboœ³NÀ \ 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æé&%æ%g€5¬ÎqYôÂeÒZoÇÝÙkÚMíæ2­éÆÔ›X\’ZDPC~^ZNfrIf^:Xéõ›ZHÙŠž1O(_œ,'º× jv^j¹nb^ŠnJfZZjQj^ XÃû#3ƒ|>²^Uó:þ'äAÝÔ2¿†R¨†¢ÔÜü2 ×ßüI{•|þ¹÷ 2m»gÜ˾‹©Éõ1ÖËåüŠ5Ó¿Ü,\“µ})TC)0HÀ!vʉùzÖ›¦9–¤×Mü°úÕ…'6óbG–x \ 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 00000000000..91113ee8e52 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/a9/0bc3fb6f15181972a2959a921429efbd81a473 @@ -0,0 +1,2 @@ +x¥ŽK +1D]ç}¥;ÿ7ÞÀ½dÒ=Œ‹‰¯ooà®^UQT®¥\;hk6½‰@¦™Â‰gŒ §5r’èƒÑ“–Œ]uOMnòdgÄz›&ÒècÆåœˆõ¨'•ž}­ NüJá¼Öò¨7ØËp?ê(ßàG»\ËÈ8‡¼CØ¢GTÃg»ü9£x¹$faõxN" \ 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 00000000000..3091b8f3d87 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/ad/a55a45d14527dc3dfc714ea1c65d2e1e6fbe87 @@ -0,0 +1 @@ +x+)JMU067d040031QH,-ÉÏM-JOMLÊIÕ+©(aH:,»:ÎCÉýúô:ÞË ²o>ZC'g$楧¦èfæé&%æ%g€5¬ÎqYôÂeÒZoÇÝÙkÚMíæ2­éÆÔ›X\’ZDPC~^ZNfrIf^:Xéõ›ZHÙŠž1O(_œ,'º× jvn~JfZ&Ä5†Æ`ÕÆnלU7Ï V.6™t6ôÇL/•R¨ê¢ÔÜü2 §ßüI{•|þ¹÷ 2m»gÜ˾‹©Éé1ÖËåüŠ5Ó¿Ü,\“µ})TC)0<ÀÁvʉùzÖ›¦9–¤×Mü°úÕ…'6ób±N’* \ 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 00000000000..20fa838f203 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/b2/d399ae15224e1d58066e3c8df70ce37de7a656 @@ -0,0 +1,2 @@ +xíQA1ôÌ+x€ÙÄ‹‰Ï¡-kI*5”f¿/»zõîÁ af˜!¤Ö^/·“W¸Jcܤ5LŒÆ›‰;+ŠBŸ6ÎHZP|`îóh>\(óÙ$“sà´î•íX·@š¢75€}57¹K +¯µ+= ;g—® @нÒ!¬4Úè!Œ,\$\ \Âb/±ÉHsø©#þa¾¼÷QÄß \ 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 00000000000..2820b46ccc1 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/b4/2712cfe99a1a500b2a51fe984e0b8a7702ba11 @@ -0,0 +1,5 @@ +xíA +À {öû†Bé{M1  ¨¥ß¯>£PØËË–‹3ŽýÜFÖŽ7Á¥E02 †Ûý¶‹XŽ0üš¹Ì’ê,)ë$;:¯‚­Ü·îþÍÆ(óä: \ 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 00000000000..a1d5321e842 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/c5/0d0f1cb60b8b0fe1615ad20ace557e9d68d7bd @@ -0,0 +1 @@ +x¥ŽKj1D³Ö)t˜–4ê–À˜l|ï>-f ‚¯9äÞU½‚â¥Vë6¤¶ô1:³Ì¸èè‰ !ÆüÀå>Z.¼P…0“x„Îû‘ ²¡h˜ÑèhQÖ+tÎ`1NÎZe¢,ÂÏX[—×ü =ËÛÚêÑvyæI_é‹ÿ†ÿvJ­^¤2 í$?ÁˆI§ìà7oÄ4•ï©íå{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,‚aò¢ìf<EZÈÍÉȳ¯µÁ5½¤%¸­µ<ê'ô“.ú¿vˆµœ,;ë]€=2¢tœwýsÆä-÷,wóÊ8@° \ 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 00000000000..da8dba2445f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/c9/174cef549ec94ecbc43ef03cdc775b4950becb @@ -0,0 +1,2 @@ +x¥ŽQ +Â0DýÎ)rÊf“nSñÇxífCÛHŒx}«xÿfÞÀc¤,˵Y ´kUÕbïò8‚pÔu`%—|@rä3GtBÀ™;W]›‚!‹‡½zß'Í%Q¤iÓdœ€T ?Û\ª=§×d/sYeµÝè'ô;üÚ^Êr´Î÷#l`6ºmú§Æ ßZ7U^e6oVòO´ \ 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 00000000000..9a0cb7a0c92 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/cc/3e3009134cb88014129fc8858d1101359e5e2f @@ -0,0 +1,2 @@ +x¥Ž] +Â0„}Î)ö•Íß&_¼H“ -ØFbÔë[Åø6ó}0LªË2wPÆìzc†’­Ë*“sXbö‚ Rt”®#Gë$‰[l¼vH„®$ÞkÖÚf.ʧLžF+ ¥QHœD|ô©68çWl.S]îu…oô“Nü¿¶Ou9‚ÔVa0^ZÅF·³ÿœ½ÍÏ9^#Þ Ø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 00000000000..8f9ae1fc64f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/d6/cf6c7741b3316826af1314042550c97ded1d50 @@ -0,0 +1,2 @@ +x¥Q +1 Dýî)r%µ¦i@Äoàj›e»…ÚÅë[Åø7ó̤Zʽƒ¿éMSLB‘­Nl°ìm öÑBºÉ~×>×—üŠ-Ãu®åY8ê ŸtÖ¯øµ]ªåÖQaǶèÍ ã¼ëŸ3f]š>b×lÞ(„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 00000000000..04dda4a758f --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/de/872ee3618b894992e9d1e18ba2ebe256a112f9 @@ -0,0 +1 @@ +xí± À S3Å‚…ŒlK–A†ˆõƒ²BÚ4W®¸b­ Ÿù˜—T5Á¢:§8ÔS»c€œ±Ô Ô»P`KäI¥Ë†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 00000000000..7b84ce966db --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/e2/c6abbd55fed5ac71a5f2751e29b4a34726a595 @@ -0,0 +1 @@ +x+)JMU067f040031QH,-ÉÏM-JOMLÊIÕ+©(aH:,»:ÎCÉýúô:ÞË ²o>ZC'g$楧¦èfæé&%æ%g€5¬ÎqYôÂeÒZoÇÝÙkÚMíæ2­éÆÔ›X\’ZDPC~^ZNfrIf^:Xéõ›ZHÙŠž1O(_œ,'º× jvn~JfZ&Ô5ù%·˜º³\N´º¢ÔçÞö§,5[ðe“Ù¨ú¢ÔÜü2 ÇßüI{•|þ¹÷ 2m»gÜ˾‹©Éñ1ÖËåüŠ5Ó¿Ü,\“µ})TC)0DÀvú‰ùzÖ›¦9–¤×Mü°úÕ…'6ób‹” \ 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 00000000000..8da234114d7 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/e3/76fbdd06ebf021c92724da9f26f44212734e3e @@ -0,0 +1,3 @@ +xíAÂ@E]s +`ö@Ì uHš)M=¾Scô®Üþü’zÂé:¢Êг(ãN+6Þ›D°¡Feð­­˜Y®g$+GˆÞä&F +Ÿ½ì‹p‡þâG —4”mQÉ\±á85Æ#FìCð¥ï~QEóÀÄÀÚR—š½u)£;cáàâ6ü­öë'Í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äÄÉ—Ecñ9ÖÖå%¿bÏòº¶úh›<ò¤Ÿtæ¯øµµz’J£òÁ(¹“γƒÿœFCñ_‹NŒ \ No newline at end of file diff --git a/tests-clar/resources/merge-resolve/.gitted/objects/e6/5a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 b/tests-clar/resources/merge-resolve/.gitted/objects/e6/5a9bb2af9f4c2d1c375dd0f8f8a46cf9c68812 new file mode 100644 index 0000000000000000000000000000000000000000..72f1cbcd94fe8fff56a40d8bb8ab02ec0ee4c41c GIT binary patch literal 160 zcmV;R0AK%j0i}*h4gw(%L|t37z~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 00000000000..55f79e0668c --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/ef/58fdd8086c243bdc81f99e379acacfd21d32d6 @@ -0,0 +1,2 @@ +x ÉÁ À0Оâï:JŠB¢ÝŸæôOV +Þñ´yáó5éê†5jã†q!’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 00000000000..f748743b846 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/f3/293571dcd708b6a3faf03818cd2844d000e198 @@ -0,0 +1 @@ +x¥ŽKjÄ0³Ö)údµZ!›¹Á\@nIعƒ,3×Ͳ{¼¢XZÛë?F/\Eã12zcó’©"#êX1§]µÚ[Ô_êå˜GŒ&™œ˜c©+9³‡”ùXWKÁÓžiUé›t¸çgê›´Sø*“¾×OÛ¹Ë)u|²´oXp*" pÓ¤µšt†Žò…šÅ©`9êïÎäê§zÅKO\ \ 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&xrJrf1’‰x}£xwU¯àQ±–²v kv½‰@`Oާ<çHˆd}œ%kŽA›‘CÒ>²ÑÄêá›Ü;$KÈ™ybhŒóÁ2癈sLA ±öÊ?ûR\ÒË·×¥–­Þá(ƒ~ÒY¾Ã¯b-'ÐÆYÇŽp‚=NˆjÐq¶ËŸ•òm[“zí O+ \ 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 00000000000..2f9d83b2610 --- /dev/null +++ b/tests-clar/resources/merge-resolve/.gitted/objects/fd/89f8cffb663ac89095a0f9764902e93ceaca6a @@ -0,0 +1,2 @@ +x¥ŽK!D]s +. ¡{` cÜx/À§É¸`0 ÆëËoà®êURy±–òèõ|èY`ÀdPÌA!±íÜäŒå4C2d=x#ž¾ñÚe`Bgr´™uôàbLÁ‡¬Ðf“fG @þÕ—Úä-½}Kò¾Ô²ÕUžyÐ=]ù;üÚ)Ör‘0 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 160/181] 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 fcfe4be3d76..01e3d2c29c4 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 43a61f0e4ce..8ca90b95f95 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 8e3cbcd4611..48e20d1e38b 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 5c1a86cb972..201a0e8967b 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 fe3a2104b31..656fb5bc596 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 9498907b683..2ad401741b4 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 8df156abee6..681f302f4c1 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 @@ static int merge_conflict_resolve( 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 00000000000..ffc9842498a --- /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 b10e9ec3200..7cb1e53da12 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 00000000000..dc0564bc4a0 --- /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 b2554f8be3b..afd8ac3ca91 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 161/181] 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 01e3d2c29c4..d23c3a8ea74 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 00000000000..f74637f84c8 --- /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 656fb5bc596..a935c00db65 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 681f302f4c1..3595eb058c7 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 ffc9842498a..68615531a78 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 4d5955a019e..0e38a92f35a 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 7cb1e53da12..b2c70bea7da 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 54b07e74a1f..7d8d2cbf50f 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 162/181] 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 5228cb811d5..6f2162e77dd 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 163/181] 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 96e15093c56..defc21d2d1b 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 a935c00db65..1771f29574b 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 3595eb058c7..320be005a6f 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 b2c70bea7da..5c3421e7e09 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 afd8ac3ca91..5da6f765879 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 164/181] 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 defc21d2d1b..21f32d89a47 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 0748b22e029..eb129f34e4a 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 165/181] 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 6f2162e77dd..85444b69246 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 166/181] 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 f8b621ef8f5..47534f1951e 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 167/181] 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 a3eba873779..e06760e2aed 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 168/181] 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 1771f29574b..d4aa475a99a 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 169/181] 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 47534f1951e..1ffad29aefc 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 170/181] 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 85444b69246..9ee3568dabd 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 34bd02ce0c4..f2fb6e25975 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 00000000000..cb089cd89a7 --- /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 00000000000..88300524a00 --- /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 00000000000..0d88b32e585 --- /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 00000000000..ad053d550bc --- /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 00000000000..76c15e203e3 --- /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 171/181] 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 1ffad29aefc..47534f1951e 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 (git_mutex_lock(&p->lock) < 0) - return packfile_error("failed to get lock for finding entry offset"); + if (index == NULL) { + int error; - assert(p->index_map.data); + if ((error = pack_index_open(p)) < 0) + return error; + 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 172/181] 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 9ee3568dabd..8a2d563279e 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 908e86f29e3..927bc83cea3 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 173/181] 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 8a2d563279e..00d1c4fd512 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 174/181] 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 00d1c4fd512..6a6f589f0ea 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 927bc83cea3..f487ee3fc39 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 175/181] 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 6a6f589f0ea..2c45eabb781 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 176/181] 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 2c45eabb781..c0a32bae747 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 177/181] 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 47534f1951e..417d225f309 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 178/181] 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 320be005a6f..56290bfadb2 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 5c3421e7e09..71bb9678180 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 1a0b8921bf4..cb718e01ab2 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 179/181] 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 5da6f765879..06ea94e0d30 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, }, }; From d80416384f67474cd98a8fafe2cc1e4f1f5fa38b Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 2 May 2013 17:22:13 -0500 Subject: [PATCH 180/181] fix some leaks --- src/diff.c | 3 ++- src/index.c | 1 + src/transports/smart_protocol.c | 6 ++++++ tests-clar/commit/parse.c | 4 ---- tests-clar/submodule/status.c | 2 ++ 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/diff.c b/src/diff.c index a154e67e8f5..fbff1a6fb02 100644 --- a/src/diff.c +++ b/src/diff.c @@ -716,7 +716,7 @@ static int diff_scan_inside_untracked_dir( error = git_iterator_advance(&info->nitem, info->new_iter); } - return error; + goto done; } /* look for actual untracked file */ @@ -747,6 +747,7 @@ static int diff_scan_inside_untracked_dir( break; } +done: git_buf_free(&base); return error; diff --git a/src/index.c b/src/index.c index d4aa475a99a..ee659f8ab73 100644 --- a/src/index.c +++ b/src/index.c @@ -349,6 +349,7 @@ static void index_free(git_index *index) { git_index_clear(index); git_vector_free(&index->entries); + git_vector_free(&index->names); git_vector_free(&index->reuc); git__free(index->index_file_path); diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index a5ad1e422e7..765b914b746 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -23,10 +23,16 @@ int git_smart__store_refs(transport_smart *t, int flushes) int error, flush = 0, recvd; const char *line_end; git_pkt *pkt; + git_pkt_ref *ref; + size_t i; /* Clear existing refs in case git_remote_connect() is called again * after git_remote_disconnect(). */ + git_vector_foreach(refs, i, ref) { + git__free(ref->head.name); + git__free(ref); + } git_vector_clear(refs); do { diff --git a/tests-clar/commit/parse.c b/tests-clar/commit/parse.c index 8de4401dcf6..415860a6e51 100644 --- a/tests-clar/commit/parse.c +++ b/tests-clar/commit/parse.c @@ -386,10 +386,6 @@ This commit has a few LF at the start of the commit message"; \n\ This commit has a few LF at the start of the commit message"; - commit = (git_commit*)git__malloc(sizeof(git_commit)); - memset(commit, 0x0, sizeof(git_commit)); - commit->object.repo = g_repo; - cl_git_pass(parse_commit(&commit, buffer)); cl_assert_equal_s(message, git_commit_message(commit)); git_commit__free(commit); diff --git a/tests-clar/submodule/status.c b/tests-clar/submodule/status.c index fca84af634b..88f38805260 100644 --- a/tests-clar/submodule/status.c +++ b/tests-clar/submodule/status.c @@ -409,4 +409,6 @@ void test_submodule_status__untracked_dirs_containing_ignored_files(void) GIT_SUBMODULE_STATUS_IN_WD; cl_assert(status == expected); + + git_buf_free(&path); } From b641c00eebb3c60e8719c0dfc55dde91ca30a5d2 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 3 May 2013 17:35:50 +0200 Subject: [PATCH 181/181] clar: Always generate the test suite --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f6b06bf12d..5a228e3429f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -337,7 +337,7 @@ IF (BUILD_CLAR) ADD_CUSTOM_COMMAND( OUTPUT ${CLAR_PATH}/clar.suite - COMMAND ${PYTHON_EXECUTABLE} generate.py -xonline . + COMMAND ${PYTHON_EXECUTABLE} generate.py -f -xonline . DEPENDS ${SRC_TEST} WORKING_DIRECTORY ${CLAR_PATH} )