Commit 0ef19fe1 by Edward Thomson

Merge submodules

parent db3462ce
...@@ -71,7 +71,8 @@ typedef struct { ...@@ -71,7 +71,8 @@ typedef struct {
int name_collision:1, int name_collision:1,
directoryfile:1, directoryfile:1,
one_to_two:1, one_to_two:1,
binary:1; binary:1,
submodule:1;
} checkout_conflictdata; } checkout_conflictdata;
static int checkout_notify( static int checkout_notify(
...@@ -682,11 +683,22 @@ GIT_INLINE(bool) conflict_pathspec_match( ...@@ -682,11 +683,22 @@ GIT_INLINE(bool) conflict_pathspec_match(
return false; return false;
} }
GIT_INLINE(int) checkout_conflict_detect_submodule(checkout_conflictdata *conflict)
{
conflict->submodule = ((conflict->ancestor && S_ISGITLINK(conflict->ancestor->mode)) ||
(conflict->ours && S_ISGITLINK(conflict->ours->mode)) ||
(conflict->theirs && S_ISGITLINK(conflict->theirs->mode)));
return 0;
}
GIT_INLINE(int) checkout_conflict_detect_binary(git_repository *repo, checkout_conflictdata *conflict) GIT_INLINE(int) checkout_conflict_detect_binary(git_repository *repo, checkout_conflictdata *conflict)
{ {
git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL; git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
int error = 0; int error = 0;
if (conflict->submodule)
return 0;
if (conflict->ancestor) { if (conflict->ancestor) {
if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor->oid)) < 0) if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor->oid)) < 0)
goto done; goto done;
...@@ -740,7 +752,8 @@ static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, g ...@@ -740,7 +752,8 @@ static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, g
conflict->ours = ours; conflict->ours = ours;
conflict->theirs = theirs; conflict->theirs = theirs;
if ((error = checkout_conflict_detect_binary(data->repo, conflict)) < 0) if ((error = checkout_conflict_detect_submodule(conflict)) < 0 ||
(error = checkout_conflict_detect_binary(data->repo, conflict)) < 0)
goto done; goto done;
git_vector_insert(&data->conflicts, conflict); git_vector_insert(&data->conflicts, conflict);
...@@ -1791,6 +1804,10 @@ static int checkout_create_conflicts(checkout_data *data) ...@@ -1791,6 +1804,10 @@ static int checkout_create_conflicts(checkout_data *data)
else if (S_ISLNK(conflict->theirs->mode)) else if (S_ISLNK(conflict->theirs->mode))
error = checkout_write_entry(data, conflict, conflict->ours); error = checkout_write_entry(data, conflict, conflict->ours);
/* If any side is a gitlink, do nothing. */
else if (conflict->submodule)
error = 0;
/* If any side is binary, write the ours side */ /* If any side is binary, write the ours side */
else if (conflict->binary) else if (conflict->binary)
error = checkout_write_entry(data, conflict, conflict->ours); error = checkout_write_entry(data, conflict, conflict->ours);
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "git2/sys/index.h" #include "git2/sys/index.h"
#define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0) #define GIT_MERGE_INDEX_ENTRY_EXISTS(X) ((X).mode != 0)
#define GIT_MERGE_INDEX_ENTRY_ISFILE(X) S_ISREG((X).mode)
typedef enum { typedef enum {
TREE_IDX_ANCESTOR = 0, TREE_IDX_ANCESTOR = 0,
...@@ -447,7 +448,6 @@ static int merge_conflict_resolve_one_removed( ...@@ -447,7 +448,6 @@ static int merge_conflict_resolve_one_removed(
return error; return error;
} }
static int merge_conflict_resolve_one_renamed( static int merge_conflict_resolve_one_renamed(
int *resolved, int *resolved,
git_merge_diff_list *diff_list, git_merge_diff_list *diff_list,
...@@ -533,6 +533,12 @@ static int merge_conflict_resolve_automerge( ...@@ -533,6 +533,12 @@ static int merge_conflict_resolve_automerge(
if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE) if (conflict->type == GIT_MERGE_DIFF_DIRECTORY_FILE)
return 0; return 0;
/* Reject submodules. */
if (S_ISGITLINK(conflict->ancestor_entry.mode) ||
S_ISGITLINK(conflict->our_entry.mode) ||
S_ISGITLINK(conflict->their_entry.mode))
return 0;
/* Reject link/file conflicts. */ /* Reject link/file conflicts. */
if ((S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->our_entry.mode)) || if ((S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->our_entry.mode)) ||
(S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->their_entry.mode))) (S_ISLNK(conflict->ancestor_entry.mode) ^ S_ISLNK(conflict->their_entry.mode)))
...@@ -1156,7 +1162,7 @@ GIT_INLINE(int) merge_diff_detect_binary( ...@@ -1156,7 +1162,7 @@ GIT_INLINE(int) merge_diff_detect_binary(
git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL; git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
int error = 0; int error = 0;
if (GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->ancestor_entry)) { if (GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->ancestor_entry)) {
if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor_entry.oid)) < 0) if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor_entry.oid)) < 0)
goto done; goto done;
...@@ -1164,7 +1170,7 @@ GIT_INLINE(int) merge_diff_detect_binary( ...@@ -1164,7 +1170,7 @@ GIT_INLINE(int) merge_diff_detect_binary(
} }
if (!conflict->binary && if (!conflict->binary &&
GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->our_entry)) { GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->our_entry)) {
if ((error = git_blob_lookup(&our_blob, repo, &conflict->our_entry.oid)) < 0) if ((error = git_blob_lookup(&our_blob, repo, &conflict->our_entry.oid)) < 0)
goto done; goto done;
...@@ -1172,7 +1178,7 @@ GIT_INLINE(int) merge_diff_detect_binary( ...@@ -1172,7 +1178,7 @@ GIT_INLINE(int) merge_diff_detect_binary(
} }
if (!conflict->binary && if (!conflict->binary &&
GIT_MERGE_INDEX_ENTRY_EXISTS(conflict->their_entry)) { GIT_MERGE_INDEX_ENTRY_ISFILE(conflict->their_entry)) {
if ((error = git_blob_lookup(&their_blob, repo, &conflict->their_entry.oid)) < 0) if ((error = git_blob_lookup(&their_blob, repo, &conflict->their_entry.oid)) < 0)
goto done; goto done;
......
#include "clar_libgit2.h"
#include "git2/repository.h"
#include "git2/merge.h"
#include "buffer.h"
#include "merge.h"
#include "../merge_helpers.h"
static git_repository *repo;
#define TEST_REPO_PATH "merge-resolve"
#define SUBMODULE_MAIN_BRANCH "submodules"
#define SUBMODULE_OTHER_BRANCH "submodules-branch"
#define SUBMODULE_OTHER2_BRANCH "submodules-branch2"
#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
// Fixture setup and teardown
void test_merge_workdir_submodules__initialize(void)
{
repo = cl_git_sandbox_init(TEST_REPO_PATH);
}
void test_merge_workdir_submodules__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_merge_workdir_submodules__automerge(void)
{
git_reference *our_ref, *their_ref;
git_commit *our_commit;
git_merge_head *their_head;
git_merge_result *result;
git_merge_opts opts = GIT_MERGE_OPTS_INIT;
git_index *index;
struct merge_index_entry merge_index_entries[] = {
{ 0100644, "caff6b7d44973f53e3e0cf31d0d695188b19aec6", 0, ".gitmodules" },
{ 0100644, "950a663a6a7b2609eed1ed1ba9f41eb1a3192a9f", 0, "file1.txt" },
{ 0100644, "343e660b9cb4bee5f407c2e33fcb9df24d9407a4", 0, "file2.txt" },
{ 0160000, "d3d806a4bef96889117fd7ebac0e3cb5ec152932", 1, "submodule" },
{ 0160000, "297aa6cd028b3336c7802c7a6f49143da4e1602d", 2, "submodule" },
{ 0160000, "ae39c77c70cb6bad18bb471912460c4e1ba0f586", 3, "submodule" },
};
cl_git_pass(git_reference_lookup(&our_ref, repo, "refs/heads/" SUBMODULE_MAIN_BRANCH));
cl_git_pass(git_commit_lookup(&our_commit, repo, git_reference_target(our_ref)));
cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD));
cl_git_pass(git_reference_lookup(&their_ref, repo, "refs/heads/" SUBMODULE_OTHER_BRANCH));
cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref));
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)&their_head, 1, &opts));
cl_git_pass(git_repository_index(&index, repo));
cl_assert(merge_test_index(index, merge_index_entries, 6));
git_index_free(index);
git_merge_result_free(result);
git_merge_head_free(their_head);
git_commit_free(our_commit);
git_reference_free(their_ref);
git_reference_free(our_ref);
}
void test_merge_workdir_submodules__take_changed(void)
{
git_reference *our_ref, *their_ref;
git_commit *our_commit;
git_merge_head *their_head;
git_merge_result *result;
git_merge_opts opts = GIT_MERGE_OPTS_INIT;
git_index *index;
struct merge_index_entry merge_index_entries[] = {
{ 0100644, "caff6b7d44973f53e3e0cf31d0d695188b19aec6", 0, ".gitmodules" },
{ 0100644, "b438ff23300b2e0f80b84a6f30140dfa91e71423", 0, "file1.txt" },
{ 0100644, "f27fbafdfa6693f8f7a5128506fe3e338dbfcad2", 0, "file2.txt" },
{ 0160000, "297aa6cd028b3336c7802c7a6f49143da4e1602d", 0, "submodule" },
};
cl_git_pass(git_reference_lookup(&our_ref, repo, "refs/heads/" SUBMODULE_MAIN_BRANCH));
cl_git_pass(git_commit_lookup(&our_commit, repo, git_reference_target(our_ref)));
cl_git_pass(git_reset(repo, (git_object *)our_commit, GIT_RESET_HARD));
cl_git_pass(git_reference_lookup(&their_ref, repo, "refs/heads/" SUBMODULE_OTHER2_BRANCH));
cl_git_pass(git_merge_head_from_ref(&their_head, repo, their_ref));
cl_git_pass(git_merge(&result, repo, (const git_merge_head **)&their_head, 1, &opts));
cl_git_pass(git_repository_index(&index, repo));
cl_assert(merge_test_index(index, merge_index_entries, 4));
git_index_free(index);
git_merge_result_free(result);
git_merge_head_free(their_head);
git_commit_free(our_commit);
git_reference_free(their_ref);
git_reference_free(our_ref);
}
...@@ -4,3 +4,5 @@ ...@@ -4,3 +4,5 @@
bare = false bare = false
logallrefupdates = true logallrefupdates = true
ignorecase = true ignorecase = true
[submodule "submodule"]
url = ../submodule
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
worktree = ../../../submodule
symlinks = false
ignorecase = true
hideDotFiles = dotGitOnly
[remote "origin"]
url = c:/Temp/TestRepos/submodule
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
# pack-refs with: peeled
297aa6cd028b3336c7802c7a6f49143da4e1602d refs/remotes/origin/master
ae39c77c70cb6bad18bb471912460c4e1ba0f586 refs/remotes/origin/submodule-branch
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