diff options
author | Edward Thomson <ethomson@microsoft.com> | 2013-07-03 09:00:45 +0400 |
---|---|---|
committer | Edward Thomson <ethomson@microsoft.com> | 2013-11-05 19:00:39 +0400 |
commit | 039db728f3a0477129e664f0fd8c08316a9e8b62 (patch) | |
tree | ef86e21bc11aec3fe2a8c860a169c84ab7ccc875 /tests-clar | |
parent | ae26c4b80f6d144df0e7915f72c64c5daf73ca50 (diff) |
merge branch into current, updating workdir
Diffstat (limited to 'tests-clar')
-rw-r--r-- | tests-clar/merge/merge_helpers.c | 23 | ||||
-rw-r--r-- | tests-clar/merge/merge_helpers.h | 3 | ||||
-rw-r--r-- | tests-clar/merge/workdir/fastforward.c | 148 | ||||
-rw-r--r-- | tests-clar/merge/workdir/renames.c | 156 | ||||
-rw-r--r-- | tests-clar/merge/workdir/setup.c | 92 | ||||
-rw-r--r-- | tests-clar/merge/workdir/simple.c | 491 | ||||
-rw-r--r-- | tests-clar/merge/workdir/trivial.c | 341 |
7 files changed, 1252 insertions, 2 deletions
diff --git a/tests-clar/merge/merge_helpers.c b/tests-clar/merge/merge_helpers.c index ddcb93ff6..43619be0d 100644 --- a/tests-clar/merge/merge_helpers.c +++ b/tests-clar/merge/merge_helpers.c @@ -52,6 +52,29 @@ int merge_trees_from_branches( return 0; } +int merge_branches(git_merge_result **result, git_repository *repo, const char *ours_branch, const char *theirs_branch, git_merge_opts *opts) +{ + git_reference *head_ref, *theirs_ref; + git_merge_head *theirs_head; + git_checkout_opts head_checkout_opts = GIT_CHECKOUT_OPTS_INIT; + + head_checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + cl_git_pass(git_reference_symbolic_create(&head_ref, repo, "HEAD", ours_branch, 1)); + cl_git_pass(git_checkout_head(repo, &head_checkout_opts)); + + cl_git_pass(git_reference_lookup(&theirs_ref, repo, theirs_branch)); + cl_git_pass(git_merge_head_from_ref(&theirs_head, repo, theirs_ref)); + + cl_git_pass(git_merge(result, repo, (const git_merge_head **)&theirs_head, 1, opts)); + + git_reference_free(head_ref); + git_reference_free(theirs_ref); + git_merge_head_free(theirs_head); + + return 0; +} + void merge__dump_index_entries(git_vector *index_entries) { size_t i; diff --git a/tests-clar/merge/merge_helpers.h b/tests-clar/merge/merge_helpers.h index cb718e01a..ae3274437 100644 --- a/tests-clar/merge/merge_helpers.h +++ b/tests-clar/merge/merge_helpers.h @@ -44,6 +44,9 @@ int merge_trees_from_branches( const char *ours_name, const char *theirs_name, git_merge_tree_opts *opts); +int merge_branches(git_merge_result **result, git_repository *repo, + const char *ours_branch, const char *theirs_branch, git_merge_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); diff --git a/tests-clar/merge/workdir/fastforward.c b/tests-clar/merge/workdir/fastforward.c new file mode 100644 index 000000000..861f38354 --- /dev/null +++ b/tests-clar/merge/workdir/fastforward.c @@ -0,0 +1,148 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "git2/sys/index.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "refs.h" + +static git_repository *repo; +static git_index *repo_index; + +#define TEST_REPO_PATH "merge-resolve" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + +#define THEIRS_FASTFORWARD_BRANCH "ff_branch" +#define THEIRS_FASTFORWARD_OID "fd89f8cffb663ac89095a0f9764902e93ceaca6a" + +#define THEIRS_NOFASTFORWARD_BRANCH "branch" +#define THEIRS_NOFASTFORWARD_OID "7cb63eed597130ba4abb87b3e544b85021905520" + + +// Fixture setup and teardown +void test_merge_workdir_fastforward__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); + git_repository_index(&repo_index, repo); +} + +void test_merge_workdir_fastforward__cleanup(void) +{ + git_index_free(repo_index); + cl_git_sandbox_cleanup(); +} + +static git_merge_result *merge_fastforward_branch(int flags) +{ + git_reference *their_ref; + git_merge_head *their_heads[1]; + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + + opts.merge_flags = flags; + + cl_git_pass(git_reference_lookup(&their_ref, repo, GIT_REFS_HEADS_DIR THEIRS_FASTFORWARD_BRANCH)); + cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, their_ref)); + + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); + + git_merge_head_free(their_heads[0]); + git_reference_free(their_ref); + + return result; +} + +void test_merge_workdir_fastforward__fastforward(void) +{ + git_merge_result *result; + git_oid expected, ff_oid; + + cl_git_pass(git_oid_fromstr(&expected, THEIRS_FASTFORWARD_OID)); + + cl_assert(result = merge_fastforward_branch(0)); + cl_assert(git_merge_result_is_fastforward(result)); + cl_git_pass(git_merge_result_fastforward_oid(&ff_oid, result)); + cl_assert(git_oid_cmp(&ff_oid, &expected) == 0); + + git_merge_result_free(result); +} + +void test_merge_workdir_fastforward__fastforward_only(void) +{ + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + git_reference *their_ref; + git_merge_head *their_head; + int error; + + opts.merge_flags = GIT_MERGE_FASTFORWARD_ONLY; + + cl_git_pass(git_reference_lookup(&their_ref, repo, GIT_REFS_HEADS_DIR THEIRS_NOFASTFORWARD_BRANCH)); + cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref)); + + cl_git_fail((error = git_merge(&result, repo, (const git_merge_head **)&their_head, 1, &opts))); + cl_assert(error == GIT_ENONFASTFORWARD); + + git_merge_head_free(their_head); + git_reference_free(their_ref); +} + +void test_merge_workdir_fastforward__no_fastforward(void) +{ + git_merge_result *result; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, + { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, + { 0100644, "bd9cb4cd0a770cb9adcb5fce212142ef40ea1c35", 0, "changed-in-master.txt" }, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "conflicting.txt" }, + { 0100644, "364bbe4ce80c7bd31e6307dce77d46e3e1759fb3", 0, "new-in-ff.txt" }, + { 0100644, "dfe3f22baa1f6fce5447901c3086bae368de6bdd", 0, "removed-in-branch.txt" }, + { 0100644, "c8f06f2e3bb2964174677e91f0abead0e43c9e5d", 0, "unchanged.txt" }, + }; + + cl_assert(result = merge_fastforward_branch(GIT_MERGE_NO_FASTFORWARD)); + cl_assert(!git_merge_result_is_fastforward(result)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 8)); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + git_merge_result_free(result); +} + +void test_merge_workdir_fastforward__uptodate(void) +{ + git_reference *their_ref; + git_merge_head *their_heads[1]; + git_merge_result *result; + + cl_git_pass(git_reference_lookup(&their_ref, repo, GIT_HEAD_FILE)); + cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, their_ref)); + + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, NULL)); + + cl_assert(git_merge_result_is_uptodate(result)); + + git_merge_head_free(their_heads[0]); + git_reference_free(their_ref); + git_merge_result_free(result); +} + +void test_merge_workdir_fastforward__uptodate_merging_prev_commit(void) +{ + git_oid their_oid; + git_merge_head *their_heads[1]; + git_merge_result *result; + + cl_git_pass(git_oid_fromstr(&their_oid, "c607fc30883e335def28cd686b51f6cfa02b06ec")); + cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oid)); + + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, NULL)); + + cl_assert(git_merge_result_is_uptodate(result)); + + git_merge_head_free(their_heads[0]); + git_merge_result_free(result); +} + diff --git a/tests-clar/merge/workdir/renames.c b/tests-clar/merge/workdir/renames.c new file mode 100644 index 000000000..d38397983 --- /dev/null +++ b/tests-clar/merge/workdir/renames.c @@ -0,0 +1,156 @@ +#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" +#include "refs.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_workdir_renames__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); +} + +void test_merge_workdir_renames__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_merge_workdir_renames__renames(void) +{ + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_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, "8aac75de2a34b4d340bf62a6e58197269cb55797", 0, "0b-rewritten-in-ours.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, + { 0100644, "7edc726325da726751a4195e434e4377b0f67f9a", 0, "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", 0, "3a-newname-in-ours-deleted-in-theirs.txt" }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt" }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-newname-in-ours-added-in-theirs.txt~HEAD" }, + { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 0, "4a-newname-in-ours-added-in-theirs.txt~rename_conflict_theirs" }, + { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 0, "4b-newname-in-theirs-added-in-ours.txt~HEAD" }, + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-newname-in-theirs-added-in-ours.txt~rename_conflict_theirs" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 0, "5a-newname-in-ours-added-in-theirs.txt~HEAD" }, + { 0100644, "98ba4205fcf31f5dd93c916d35fe3f3b3d0e6714", 0, "5a-newname-in-ours-added-in-theirs.txt~rename_conflict_theirs" }, + { 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced", 0, "5b-newname-in-theirs-added-in-ours.txt~HEAD" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 0, "5b-newname-in-theirs-added-in-ours.txt~rename_conflict_theirs" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-theirs.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "7-both-renamed.txt~HEAD" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "7-both-renamed.txt~rename_conflict_theirs" }, + }; + + opts.merge_tree_opts.flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.merge_tree_opts.rename_threshold = 50; + + cl_git_pass(merge_branches(&result, repo, GIT_REFS_HEADS_DIR BRANCH_RENAME_OURS, GIT_REFS_HEADS_DIR BRANCH_RENAME_THEIRS, &opts)); + cl_assert(merge_test_workdir(repo, merge_index_entries, 24)); + + git_merge_result_free(result); +} + +void test_merge_workdir_renames__ours(void) +{ + git_index *index; + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_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, "e376fbdd06ebf021c92724da9f26f44212734e3e", 0, "0b-rewritten-in-ours.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, + { 0100644, "efc9121fdedaf08ba180b53ebfbcf71bd488ed09", 0, "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", 0, "3a-newname-in-ours-deleted-in-theirs.txt" }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt" }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 0, "4b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 0, "5a-newname-in-ours-added-in-theirs.txt" }, + { 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced", 0, "5b-newname-in-theirs-added-in-ours.txt" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 0, "5b-renamed-in-theirs-added-in-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-ours.txt" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "7-both-renamed-side-2.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "7-both-renamed.txt" }, + }; + + opts.merge_tree_opts.flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.merge_tree_opts.rename_threshold = 50; + opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS; + + cl_git_pass(merge_branches(&result, repo, GIT_REFS_HEADS_DIR BRANCH_RENAME_OURS, GIT_REFS_HEADS_DIR BRANCH_RENAME_THEIRS, &opts)); + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_index_write(index)); + cl_assert(merge_test_workdir(repo, merge_index_entries, 20)); + + git_merge_result_free(result); + git_index_free(index); +} + +void test_merge_workdir_renames__similar(void) +{ + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + + /* + * Note: this differs slightly from the core git merge result - there, 4a is + * tracked as a rename/delete instead of a rename/add and the theirs side + * is not placed in workdir in any form. + */ + struct merge_index_entry merge_index_entries[] = { + { 0100644, "68c6c84b091926c7d90aa6a79b2bc3bb6adccd8e", 0, "0a-no-change.txt" }, + { 0100644, "f0ce2b8e4986084d9b308fb72709e414c23eb5e6", 0, "0b-duplicated-in-ours.txt" }, + { 0100644, "8aac75de2a34b4d340bf62a6e58197269cb55797", 0, "0b-rewritten-in-ours.txt" }, + { 0100644, "2f56120107d680129a5d9791b521cb1e73a2ed31", 0, "0c-duplicated-in-theirs.txt" }, + { 0100644, "7edc726325da726751a4195e434e4377b0f67f9a", 0, "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", 0, "3a-newname-in-ours-deleted-in-theirs.txt" }, + { 0100644, "36219b49367146cb2e6a1555b5a9ebd4d0328495", 0, "3b-newname-in-theirs-deleted-in-ours.txt" }, + { 0100644, "227792b52aaa0b238bea00ec7e509b02623f168c", 0, "4a-newname-in-ours-added-in-theirs.txt~HEAD" }, + { 0100644, "8b5b53cb2aa9ceb1139f5312fcfa3cc3c5a47c9a", 0, "4a-newname-in-ours-added-in-theirs.txt~rename_conflict_theirs" }, + { 0100644, "de872ee3618b894992e9d1e18ba2ebe256a112f9", 0, "4b-newname-in-theirs-added-in-ours.txt~HEAD" }, + { 0100644, "98d52d07c0b0bbf2b46548f6aa521295c2cb55db", 0, "4b-newname-in-theirs-added-in-ours.txt~rename_conflict_theirs" }, + { 0100644, "d3719a5ae8e4d92276b5313ce976f6ee5af2b436", 0, "5a-newname-in-ours-added-in-theirs.txt~HEAD" }, + { 0100644, "98ba4205fcf31f5dd93c916d35fe3f3b3d0e6714", 0, "5a-newname-in-ours-added-in-theirs.txt~rename_conflict_theirs" }, + { 0100644, "385c8a0f26ddf79e9041e15e17dc352ed2c4cced", 0, "5b-newname-in-theirs-added-in-ours.txt~HEAD" }, + { 0100644, "63247125386de9ec90a27ad36169307bf8a11a38", 0, "5b-newname-in-theirs-added-in-ours.txt~rename_conflict_theirs" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-ours.txt" }, + { 0100644, "d8fa77b6833082c1ea36b7828a582d4c43882450", 0, "6-both-renamed-1-to-2-theirs.txt" }, + { 0100644, "b42712cfe99a1a500b2a51fe984e0b8a7702ba11", 0, "7-both-renamed.txt~HEAD" }, + { 0100644, "b69fe837e4cecfd4c9a40cdca7c138468687df07", 0, "7-both-renamed.txt~rename_conflict_theirs" }, + }; + + opts.merge_tree_opts.flags |= GIT_MERGE_TREE_FIND_RENAMES; + opts.merge_tree_opts.rename_threshold = 50; + + cl_git_pass(merge_branches(&result, repo, GIT_REFS_HEADS_DIR BRANCH_RENAME_OURS, GIT_REFS_HEADS_DIR BRANCH_RENAME_THEIRS, &opts)); + cl_assert(merge_test_workdir(repo, merge_index_entries, 24)); + + git_merge_result_free(result); +} + diff --git a/tests-clar/merge/workdir/setup.c b/tests-clar/merge/workdir/setup.c index 1c8403221..511106a58 100644 --- a/tests-clar/merge/workdir/setup.c +++ b/tests-clar/merge/workdir/setup.c @@ -71,7 +71,7 @@ static void write_file_contents(const char *filename, const char *output) git_buf_free(&file_path_buf); } -/* git merge --no-ff octo1 */ +/* git merge octo1 */ void test_merge_workdir_setup__one_branch(void) { git_oid our_oid; @@ -97,7 +97,33 @@ void test_merge_workdir_setup__one_branch(void) git_merge_head_free(their_heads[0]); } -/* git merge --no-ff 16f825815cfd20a07a75c71554e82d8eede0b061 */ +/* git merge --no-ff octo1 */ +void test_merge_workdir_setup__no_fastforward(void) +{ + git_oid our_oid; + git_reference *octo1_ref; + git_merge_head *our_head, *their_heads[1]; + + cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); + cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); + + cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); + cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + + cl_git_pass(git_merge__setup(repo, our_head, (const git_merge_head **)their_heads, 1, GIT_MERGE_NO_FASTFORWARD)); + + cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); + cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); + cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "'\n")); + + git_reference_free(octo1_ref); + + git_merge_head_free(our_head); + git_merge_head_free(their_heads[0]); +} + +/* git merge 16f825815cfd20a07a75c71554e82d8eede0b061 */ void test_merge_workdir_setup__one_oid(void) { git_oid our_oid; @@ -964,3 +990,65 @@ void test_merge_workdir_setup__head_foreach_octopus(void) cl_assert(cb_data.i == cb_data.len); } + +void test_merge_workdir_setup__retained_after_success(void) +{ + git_oid our_oid; + git_reference *octo1_ref; + git_merge_head *our_head, *their_heads[1]; + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + + opts.merge_flags |= GIT_MERGE_NO_FASTFORWARD; + + cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); + cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); + + cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); + + cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)&their_heads[0], 1, &opts)); + + cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); + cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); + cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "'\n")); + + git_reference_free(octo1_ref); + + git_merge_head_free(our_head); + git_merge_head_free(their_heads[0]); +} + +void test_merge_workdir_setup__removed_after_failure(void) +{ + git_oid our_oid; + git_reference *octo1_ref; + git_merge_head *our_head, *their_heads[1]; + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + + opts.merge_flags |= GIT_MERGE_NO_FASTFORWARD; + + cl_git_pass(git_oid_fromstr(&our_oid, ORIG_HEAD)); + cl_git_pass(git_merge_head_from_oid(&our_head, repo, &our_oid)); + + cl_git_pass(git_reference_lookup(&octo1_ref, repo, GIT_REFS_HEADS_DIR OCTO1_BRANCH)); + cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, octo1_ref)); + + cl_git_rewritefile("merge-resolve/new-in-octo1.txt", + "Conflicting file!\n\nMerge will fail!\n"); + + cl_git_fail(git_merge(&result, repo, &their_heads[0], 1, &opts)); + + cl_assert(!git_path_exists("merge-resolve/" GIT_MERGE_HEAD_FILE)); + cl_assert(!git_path_exists("merge-resolve/" GIT_ORIG_HEAD_FILE)); + cl_assert(!git_path_exists("merge-resolve/" GIT_MERGE_MODE_FILE)); + cl_assert(!git_path_exists("merge-resolve/" GIT_MERGE_MSG_FILE)); + + git_reference_free(octo1_ref); + + git_merge_head_free(our_head); + git_merge_head_free(their_heads[0]); +} diff --git a/tests-clar/merge/workdir/simple.c b/tests-clar/merge/workdir/simple.c new file mode 100644 index 000000000..4a3b86ee4 --- /dev/null +++ b/tests-clar/merge/workdir/simple.c @@ -0,0 +1,491 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "buffer.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "refs.h" +#include "fileops.h" + +static git_repository *repo; +static git_index *repo_index; + +#define TEST_REPO_PATH "merge-resolve" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + +#define THEIRS_SIMPLE_BRANCH "branch" +#define THEIRS_SIMPLE_OID "7cb63eed597130ba4abb87b3e544b85021905520" + +#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 "fc90237dc4891fa6c69827fc465632225e391618" + + +/* 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" } + +/* Unrelated files */ +#define UNRELATED_NEW1 \ + { 0100644, "ef58fdd8086c243bdc81f99e379acacfd21d32d6", 0, \ + "new-in-unrelated1.txt" } +#define UNRELATED_NEW2 \ + { 0100644, "948ba6e701c1edab0c2d394fb7c5538334129793", 0, \ + "new-in-unrelated2.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" + +#define CONFLICTING_DIFF3_FILE \ + "<<<<<<< HEAD\n" \ + "this file is changed in master and branch\n" \ + "=======\n" \ + "this file is changed in branch and master\n" \ + ">>>>>>> 7cb63eed597130ba4abb87b3e544b85021905520\n" + +// Fixture setup and teardown +void test_merge_workdir_simple__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); + git_repository_index(&repo_index, repo); +} + +void test_merge_workdir_simple__cleanup(void) +{ + git_index_free(repo_index); + cl_git_sandbox_cleanup(); +} + +static git_merge_result *merge_simple_branch(int automerge_flags, int checkout_strategy) +{ + git_oid their_oids[1]; + git_merge_head *their_heads[1]; + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + + cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_SIMPLE_OID)); + cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0])); + + opts.merge_tree_opts.automerge_flags = automerge_flags; + opts.checkout_opts.checkout_strategy = checkout_strategy; + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); + + git_merge_head_free(their_heads[0]); + + return result; +} + +static void set_core_autocrlf_to(git_repository *repo, bool value) +{ + git_config *cfg; + + cl_git_pass(git_repository_config(&cfg, repo)); + cl_git_pass(git_config_set_bool(cfg, "core.autocrlf", value)); + + git_config_free(cfg); +} + +void test_merge_workdir_simple__automerge(void) +{ + git_index *index; + const git_index_entry *entry; + git_merge_result *result; + git_buf automergeable_buf = GIT_BUF_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, "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 + }; + + + set_core_autocrlf_to(repo, false); + + cl_assert(result = merge_simple_branch(0, 0)); + cl_assert(!git_merge_result_is_fastforward(result)); + + cl_git_pass(git_futils_readbuffer(&automergeable_buf, + TEST_REPO_PATH "/automergeable.txt")); + cl_assert(strcmp(automergeable_buf.ptr, AUTOMERGEABLE_MERGED_FILE) == 0); + git_buf_free(&automergeable_buf); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 8)); + cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 3)); + + git_merge_result_free(result); + + git_repository_index(&index, repo); + + cl_assert((entry = git_index_get_bypath(index, "automergeable.txt", 0)) != NULL); + cl_assert(entry->file_size == strlen(AUTOMERGEABLE_MERGED_FILE)); + + git_index_free(index); +} + +void test_merge_workdir_simple__automerge_crlf(void) +{ +#ifdef GIT_WIN32 + git_index *index; + const git_index_entry *entry; + + git_merge_result *result; + git_buf automergeable_buf = GIT_BUF_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, "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 + }; + + set_core_autocrlf_to(repo, true); + + cl_assert(result = merge_simple_branch(0, 0)); + cl_assert(!git_merge_result_is_fastforward(result)); + + cl_git_pass(git_futils_readbuffer(&automergeable_buf, + TEST_REPO_PATH "/automergeable.txt")); + cl_assert(strcmp(automergeable_buf.ptr, AUTOMERGEABLE_MERGED_FILE_CRLF) == 0); + git_buf_free(&automergeable_buf); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 8)); + cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 3)); + + git_merge_result_free(result); + + git_repository_index(&index, repo); + + cl_assert((entry = git_index_get_bypath(index, "automergeable.txt", 0)) != NULL); + cl_assert(entry->file_size == strlen(AUTOMERGEABLE_MERGED_FILE_CRLF)); + + git_index_free(index); +#endif /* GIT_WIN32 */ +} + +void test_merge_workdir_simple__diff3(void) +{ + git_merge_result *result; + git_buf conflicting_buf = GIT_BUF_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, "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_assert(result = merge_simple_branch(0, 0)); + cl_assert(!git_merge_result_is_fastforward(result)); + + cl_git_pass(git_futils_readbuffer(&conflicting_buf, + TEST_REPO_PATH "/conflicting.txt")); + cl_assert(strcmp(conflicting_buf.ptr, CONFLICTING_DIFF3_FILE) == 0); + git_buf_free(&conflicting_buf); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 8)); + cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 3)); + + git_merge_result_free(result); +} + +void test_merge_workdir_simple__checkout_ours(void) +{ + git_merge_result *result; + + 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_assert(result = merge_simple_branch(0, GIT_CHECKOUT_SAFE | GIT_CHECKOUT_USE_OURS)); + cl_assert(!git_merge_result_is_fastforward(result)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 8)); + cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 3)); + + cl_assert(git_path_exists(TEST_REPO_PATH "/conflicting.txt")); + + git_merge_result_free(result); +} + +void test_merge_workdir_simple__favor_ours(void) +{ + git_merge_result *result; + + 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, + }; + + cl_assert(result = merge_simple_branch(GIT_MERGE_AUTOMERGE_FAVOR_OURS, 0)); + cl_assert(!git_merge_result_is_fastforward(result)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 6)); + cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 4)); + + git_merge_result_free(result); +} + +void test_merge_workdir_simple__favor_theirs(void) +{ + git_merge_result *result; + + 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, + }; + + cl_assert(result = merge_simple_branch(GIT_MERGE_AUTOMERGE_FAVOR_THEIRS, 0)); + cl_assert(!git_merge_result_is_fastforward(result)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 6)); + cl_assert(merge_test_reuc(repo_index, merge_reuc_entries, 4)); + + git_merge_result_free(result); +} + +void test_merge_workdir_simple__directory_file(void) +{ + git_reference *head; + git_oid their_oids[1], head_commit_id; + git_merge_head *their_heads[1]; + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + git_commit *head_commit; + + 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(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_DIR OURS_DIRECTORY_FILE, 1)); + cl_git_pass(git_reference_name_to_id(&head_commit_id, repo, GIT_HEAD_FILE)); + cl_git_pass(git_commit_lookup(&head_commit, repo, &head_commit_id)); + cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD)); + + cl_git_pass(git_oid_fromstr(&their_oids[0], THEIRS_DIRECTORY_FILE)); + cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0])); + + opts.merge_tree_opts.automerge_flags = 0; + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 20)); + + git_reference_free(head); + git_commit_free(head_commit); + git_merge_head_free(their_heads[0]); + git_merge_result_free(result); +} + +void test_merge_workdir_simple__unrelated(void) +{ + git_oid their_oids[1]; + git_merge_head *their_heads[1]; + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + + struct merge_index_entry merge_index_entries[] = { + { 0100644, "233c0919c998ed110a4b6ff36f353aec8b713487", 0, "added-in-master.txt" }, + { 0100644, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf", 0, "automergeable.txt" }, + { 0100644, "ab6c44a2e84492ad4b41bb6bac87353e9d02ac8b", 0, "changed-in-branch.txt" }, + { 0100644, "11deab00b2d3a6f5a3073988ac050c2d7b6655e2", 0, "changed-in-master.txt" }, + { 0100644, "4e886e602529caa9ab11d71f86634bd1b6e0de10", 0, "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(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_PARENT)); + cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0])); + + opts.merge_tree_opts.automerge_flags = 0; + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 9)); + + git_merge_head_free(their_heads[0]); + git_merge_result_free(result); +} + +void test_merge_workdir_simple__unrelated_with_conflicts(void) +{ + git_oid their_oids[1]; + git_merge_head *their_heads[1]; + git_merge_result *result; + git_merge_opts opts = GIT_MERGE_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(git_oid_fromstr(&their_oids[0], THEIRS_UNRELATED_OID)); + cl_git_pass(git_merge_head_from_oid(&their_heads[0], repo, &their_oids[0])); + + opts.merge_tree_opts.automerge_flags = 0; + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); + + cl_assert(merge_test_index(repo_index, merge_index_entries, 11)); + + git_merge_head_free(their_heads[0]); + git_merge_result_free(result); +} + diff --git a/tests-clar/merge/workdir/trivial.c b/tests-clar/merge/workdir/trivial.c new file mode 100644 index 000000000..d20d89879 --- /dev/null +++ b/tests-clar/merge/workdir/trivial.c @@ -0,0 +1,341 @@ +#include "clar_libgit2.h" +#include "git2/repository.h" +#include "git2/merge.h" +#include "git2/sys/index.h" +#include "merge.h" +#include "../merge_helpers.h" +#include "refs.h" +#include "fileops.h" + +static git_repository *repo; +static git_index *repo_index; + +#define TEST_REPO_PATH "merge-resolve" +#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index" + + +// Fixture setup and teardown +void test_merge_workdir_trivial__initialize(void) +{ + repo = cl_git_sandbox_init(TEST_REPO_PATH); + git_repository_index(&repo_index, repo); +} + +void test_merge_workdir_trivial__cleanup(void) +{ + git_index_free(repo_index); + cl_git_sandbox_cleanup(); +} + + +static int merge_trivial(const char *ours, const char *theirs, bool automerge) +{ + git_buf branch_buf = GIT_BUF_INIT; + git_checkout_opts checkout_opts = GIT_CHECKOUT_OPTS_INIT; + git_reference *our_ref, *their_ref; + git_merge_head *their_heads[1]; + git_merge_opts opts = GIT_MERGE_OPTS_INIT; + git_merge_result *result; + + checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + opts.merge_tree_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_symbolic_create(&our_ref, repo, "HEAD", branch_buf.ptr, 1)); + + cl_git_pass(git_checkout_head(repo, &checkout_opts)); + + git_buf_clear(&branch_buf); + git_buf_printf(&branch_buf, "%s%s", GIT_REFS_HEADS_DIR, theirs); + cl_git_pass(git_reference_lookup(&their_ref, repo, branch_buf.ptr)); + cl_git_pass(git_merge_head_from_ref(&their_heads[0], repo, their_ref)); + + cl_git_pass(git_merge(&result, repo, (const git_merge_head **)their_heads, 1, &opts)); + + git_buf_free(&branch_buf); + git_reference_free(our_ref); + git_reference_free(their_ref); + git_merge_head_free(their_heads[0]); + git_merge_result_free(result); + + return 0; +} + +static int merge_trivial_conflict_entrycount(void) +{ + const git_index_entry *entry; + size_t count = 0; + size_t i; + + for (i = 0; i < git_index_entrycount(repo_index); i++) { + cl_assert(entry = git_index_get_byindex(repo_index, i)); + + if (git_index_entry_stage(entry) > 0) + count++; + } + + return count; +} + +/* 2ALT: ancest:(empty)+, head:*empty*, remote:remote = result:remote */ +void test_merge_workdir_trivial__2alt(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-2alt", "trivial-2alt-branch", 0)); + + cl_assert(entry = git_index_get_bypath(repo_index, "new-in-branch.txt", 0)); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + cl_assert(merge_trivial_conflict_entrycount() == 0); +} + +/* 3ALT: ancest:(empty)+, head:head, remote:*empty* = result:head */ +void test_merge_workdir_trivial__3alt(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-3alt", "trivial-3alt-branch", 0)); + + cl_assert(entry = git_index_get_bypath(repo_index, "new-in-3alt.txt", 0)); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + cl_assert(merge_trivial_conflict_entrycount() == 0); +} + +/* 4: ancest:(empty)^, head:head, remote:remote = result:no merge */ +void test_merge_workdir_trivial__4(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-4", "trivial-4-branch", 0)); + + cl_assert((entry = git_index_get_bypath(repo_index, "new-and-different.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + cl_assert(merge_trivial_conflict_entrycount() == 2); + cl_assert(entry = git_index_get_bypath(repo_index, "new-and-different.txt", 2)); + cl_assert(entry = git_index_get_bypath(repo_index, "new-and-different.txt", 3)); +} + +/* 5ALT: ancest:*, head:head, remote:head = result:head */ +void test_merge_workdir_trivial__5alt_1(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-5alt-1", "trivial-5alt-1-branch", 0)); + + cl_assert(entry = git_index_get_bypath(repo_index, "new-and-same.txt", 0)); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + cl_assert(merge_trivial_conflict_entrycount() == 0); +} + +/* 5ALT: ancest:*, head:head, remote:head = result:head */ +void test_merge_workdir_trivial__5alt_2(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-5alt-2", "trivial-5alt-2-branch", 0)); + + cl_assert(entry = git_index_get_bypath(repo_index, "modified-to-same.txt", 0)); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + cl_assert(merge_trivial_conflict_entrycount() == 0); +} + +/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ +void test_merge_workdir_trivial__6(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-6", "trivial-6-branch", 0)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-both.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + cl_assert(merge_trivial_conflict_entrycount() == 1); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-both.txt", 1)); +} + +/* 6: ancest:ancest+, head:(empty), remote:(empty) = result:no merge */ +void test_merge_workdir_trivial__6_automerge(void) +{ + const git_index_entry *entry; + const git_index_reuc_entry *reuc; + + cl_git_pass(merge_trivial("trivial-6", "trivial-6-branch", 1)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-both.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 1); + cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "removed-in-both.txt")); + + cl_assert(merge_trivial_conflict_entrycount() == 0); +} + +/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ +void test_merge_workdir_trivial__8(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-8", "trivial-8-branch", 0)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-8.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + cl_assert(merge_trivial_conflict_entrycount() == 2); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-8.txt", 1)); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-8.txt", 3)); +} + +/* 8: ancest:ancest^, head:(empty), remote:ancest = result:no merge */ +void test_merge_workdir_trivial__8_automerge(void) +{ + const git_index_entry *entry; + const git_index_reuc_entry *reuc; + + cl_git_pass(merge_trivial("trivial-8", "trivial-8-branch", 1)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-8.txt", 0)) == NULL); + + cl_assert(git_index_reuc_entrycount(repo_index) == 1); + cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "removed-in-8.txt")); + + cl_assert(merge_trivial_conflict_entrycount() == 0); +} + +/* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */ +void test_merge_workdir_trivial__7(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-7", "trivial-7-branch", 0)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + cl_assert(merge_trivial_conflict_entrycount() == 2); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 1)); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 3)); +} + +/* 7: ancest:ancest+, head:(empty), remote:remote = result:no merge */ +void test_merge_workdir_trivial__7_automerge(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-7", "trivial-7-branch", 0)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + cl_assert(merge_trivial_conflict_entrycount() == 2); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 1)); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-7.txt", 3)); +} + +/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ +void test_merge_workdir_trivial__10(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-10", "trivial-10-branch", 0)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-10-branch.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + cl_assert(merge_trivial_conflict_entrycount() == 2); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-10-branch.txt", 1)); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-10-branch.txt", 2)); +} + +/* 10: ancest:ancest^, head:ancest, remote:(empty) = result:no merge */ +void test_merge_workdir_trivial__10_automerge(void) +{ + const git_index_entry *entry; + const git_index_reuc_entry *reuc; + + cl_git_pass(merge_trivial("trivial-10", "trivial-10-branch", 1)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-10-branch.txt", 0)) == NULL); + + cl_assert(git_index_reuc_entrycount(repo_index) == 1); + cl_assert(reuc = git_index_reuc_get_bypath(repo_index, "removed-in-10-branch.txt")); + + cl_assert(merge_trivial_conflict_entrycount() == 0); +} + +/* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */ +void test_merge_workdir_trivial__9(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-9", "trivial-9-branch", 0)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + cl_assert(merge_trivial_conflict_entrycount() == 2); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 1)); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 2)); +} + +/* 9: ancest:ancest+, head:head, remote:(empty) = result:no merge */ +void test_merge_workdir_trivial__9_automerge(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-9", "trivial-9-branch", 1)); + + cl_assert((entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + cl_assert(merge_trivial_conflict_entrycount() == 2); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 1)); + cl_assert(entry = git_index_get_bypath(repo_index, "removed-in-9-branch.txt", 2)); +} + +/* 13: ancest:ancest+, head:head, remote:ancest = result:head */ +void test_merge_workdir_trivial__13(void) +{ + const git_index_entry *entry; + git_oid expected_oid; + + cl_git_pass(merge_trivial("trivial-13", "trivial-13-branch", 0)); + + cl_assert(entry = git_index_get_bypath(repo_index, "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(repo_index) == 0); + cl_assert(merge_trivial_conflict_entrycount() == 0); +} + +/* 14: ancest:ancest+, head:ancest, remote:remote = result:remote */ +void test_merge_workdir_trivial__14(void) +{ + const git_index_entry *entry; + git_oid expected_oid; + + cl_git_pass(merge_trivial("trivial-14", "trivial-14-branch", 0)); + + cl_assert(entry = git_index_get_bypath(repo_index, "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(repo_index) == 0); + cl_assert(merge_trivial_conflict_entrycount() == 0); +} + +/* 11: ancest:ancest+, head:head, remote:remote = result:no merge */ +void test_merge_workdir_trivial__11(void) +{ + const git_index_entry *entry; + + cl_git_pass(merge_trivial("trivial-11", "trivial-11-branch", 0)); + + cl_assert((entry = git_index_get_bypath(repo_index, "modified-in-both.txt", 0)) == NULL); + cl_assert(git_index_reuc_entrycount(repo_index) == 0); + + cl_assert(merge_trivial_conflict_entrycount() == 3); + cl_assert(entry = git_index_get_bypath(repo_index, "modified-in-both.txt", 1)); + cl_assert(entry = git_index_get_bypath(repo_index, "modified-in-both.txt", 2)); + cl_assert(entry = git_index_get_bypath(repo_index, "modified-in-both.txt", 3)); +} |