Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@microsoft.com>2013-07-03 09:00:45 +0400
committerEdward Thomson <ethomson@microsoft.com>2013-11-05 19:00:39 +0400
commit039db728f3a0477129e664f0fd8c08316a9e8b62 (patch)
treeef86e21bc11aec3fe2a8c860a169c84ab7ccc875 /tests-clar
parentae26c4b80f6d144df0e7915f72c64c5daf73ca50 (diff)
merge branch into current, updating workdir
Diffstat (limited to 'tests-clar')
-rw-r--r--tests-clar/merge/merge_helpers.c23
-rw-r--r--tests-clar/merge/merge_helpers.h3
-rw-r--r--tests-clar/merge/workdir/fastforward.c148
-rw-r--r--tests-clar/merge/workdir/renames.c156
-rw-r--r--tests-clar/merge/workdir/setup.c92
-rw-r--r--tests-clar/merge/workdir/simple.c491
-rw-r--r--tests-clar/merge/workdir/trivial.c341
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));
+}