Commit 453e6b3e by Vicent Martí

Merge pull request #1007 from ethomson/merge

merge!
parents ae26c4b8 039db728
...@@ -66,6 +66,29 @@ typedef struct { ...@@ -66,6 +66,29 @@ typedef struct {
/** /**
* Option flags for `git_merge`.
*
* GIT_MERGE_NO_FASTFORWARD - Do not fast-forward.
*/
typedef enum {
GIT_MERGE_NO_FASTFORWARD = 1,
GIT_MERGE_FASTFORWARD_ONLY = 2,
} git_merge_flags_t;
typedef struct {
unsigned int version;
git_merge_flags_t merge_flags;
git_merge_tree_opts merge_tree_opts;
git_checkout_opts checkout_opts;
} git_merge_opts;
#define GIT_MERGE_OPTS_VERSION 1
#define GIT_MERGE_OPTS_INIT {GIT_MERGE_OPTS_VERSION, 0, GIT_MERGE_TREE_OPTS_INIT, GIT_CHECKOUT_OPTS_INIT}
/**
* Find a merge base between two commits * Find a merge base between two commits
* *
* @param out the OID of a merge base between 'one' and 'two' * @param out the OID of a merge base between 'one' and 'two'
...@@ -168,6 +191,43 @@ GIT_EXTERN(int) git_merge_trees( ...@@ -168,6 +191,43 @@ GIT_EXTERN(int) git_merge_trees(
const git_tree *their_tree, const git_tree *their_tree,
const git_merge_tree_opts *opts); const git_merge_tree_opts *opts);
/**
* Merges the given commits into HEAD, producing a new commit.
*
* @param out the results of the merge
* @param repo the repository to merge
* @param merge_heads the heads to merge into
* @param merge_heads_len the number of heads to merge
* @param flags merge flags
*/
GIT_EXTERN(int) git_merge(
git_merge_result **out,
git_repository *repo,
const git_merge_head **their_heads,
size_t their_heads_len,
const git_merge_opts *opts);
/**
* Returns true if a merge is up-to-date (we were asked to merge the target
* into itself.)
*/
GIT_EXTERN(int) git_merge_result_is_uptodate(git_merge_result *merge_result);
/**
* Returns true if a merge is eligible for fastforward
*/
GIT_EXTERN(int) git_merge_result_is_fastforward(git_merge_result *merge_result);
/**
* Gets the fast-forward OID if the merge was a fastforward.
*
* @param out the OID of the fast-forward
* @param merge_result the results of the merge
*/
GIT_EXTERN(int) git_merge_result_fastforward_oid(git_oid *out, git_merge_result *merge_result);
GIT_EXTERN(void) git_merge_result_free(git_merge_result *merge_result);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -174,6 +174,9 @@ typedef struct git_reference_iterator git_reference_iterator; ...@@ -174,6 +174,9 @@ typedef struct git_reference_iterator git_reference_iterator;
/** Merge heads, the input to merge */ /** Merge heads, the input to merge */
typedef struct git_merge_head git_merge_head; typedef struct git_merge_head git_merge_head;
/** Merge result */
typedef struct git_merge_result git_merge_result;
/** Representation of a status collection */ /** Representation of a status collection */
typedef struct git_status_list git_status_list; typedef struct git_status_list git_status_list;
......
...@@ -114,9 +114,20 @@ struct git_merge_head { ...@@ -114,9 +114,20 @@ struct git_merge_head {
char *remote_url; char *remote_url;
git_oid oid; git_oid oid;
char oid_str[GIT_OID_HEXSZ+1];
git_commit *commit; git_commit *commit;
}; };
/** Internal structure for merge results */
struct git_merge_result {
bool is_uptodate;
bool is_fastforward;
git_oid fastforward_oid;
git_index *index;
};
int git_merge__bases_many( int git_merge__bases_many(
git_commit_list **out, git_commit_list **out,
git_revwalk *walk, git_revwalk *walk,
......
...@@ -52,6 +52,29 @@ int merge_trees_from_branches( ...@@ -52,6 +52,29 @@ int merge_trees_from_branches(
return 0; 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) void merge__dump_index_entries(git_vector *index_entries)
{ {
size_t i; size_t i;
......
...@@ -44,6 +44,9 @@ int merge_trees_from_branches( ...@@ -44,6 +44,9 @@ int merge_trees_from_branches(
const char *ours_name, const char *theirs_name, const char *ours_name, const char *theirs_name,
git_merge_tree_opts *opts); 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_diff_list(git_merge_diff_list *diff_list, const struct merge_index_entry expected[], size_t expected_len);
int merge_test_merge_conflicts(git_vector *conflicts, const struct merge_index_conflict_data expected[], size_t expected_len); int merge_test_merge_conflicts(git_vector *conflicts, const struct merge_index_conflict_data expected[], size_t expected_len);
......
#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);
}
#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);
}
...@@ -71,7 +71,7 @@ static void write_file_contents(const char *filename, const char *output) ...@@ -71,7 +71,7 @@ static void write_file_contents(const char *filename, const char *output)
git_buf_free(&file_path_buf); git_buf_free(&file_path_buf);
} }
/* git merge --no-ff octo1 */ /* git merge octo1 */
void test_merge_workdir_setup__one_branch(void) void test_merge_workdir_setup__one_branch(void)
{ {
git_oid our_oid; git_oid our_oid;
...@@ -97,7 +97,33 @@ void test_merge_workdir_setup__one_branch(void) ...@@ -97,7 +97,33 @@ void test_merge_workdir_setup__one_branch(void)
git_merge_head_free(their_heads[0]); 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) void test_merge_workdir_setup__one_oid(void)
{ {
git_oid our_oid; git_oid our_oid;
...@@ -964,3 +990,65 @@ void test_merge_workdir_setup__head_foreach_octopus(void) ...@@ -964,3 +990,65 @@ void test_merge_workdir_setup__head_foreach_octopus(void)
cl_assert(cb_data.i == cb_data.len); 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]);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment