summaryrefslogtreecommitdiff
path: root/src/merge.c
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@microsoft.com>2014-03-11 17:19:35 -0700
committerEdward Thomson <ethomson@microsoft.com>2014-03-20 09:25:06 -0700
commitccb308273a8662a9692849115a929bd1a74a15f7 (patch)
tree3bf744f845d84b99c75aaad84a94009127d75581 /src/merge.c
parent05d47768caf6fec51fa85cb6275c9ba8324aead6 (diff)
downloadlibgit2-ccb308273a8662a9692849115a929bd1a74a15f7.tar.gz
Add `git_merge_status` to provide info about an upcoming merge
Diffstat (limited to 'src/merge.c')
-rw-r--r--src/merge.c83
1 files changed, 74 insertions, 9 deletions
diff --git a/src/merge.c b/src/merge.c
index 8a33edb13..cdc1921ce 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -2497,6 +2497,79 @@ static int merge_state_cleanup(git_repository *repo)
return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
}
+static int merge_heads(
+ git_merge_head **ancestor_head_out,
+ git_merge_head **our_head_out,
+ git_repository *repo,
+ const git_merge_head **their_heads,
+ size_t their_heads_len)
+{
+ git_merge_head *ancestor_head = NULL, *our_head = NULL;
+ git_reference *our_ref = NULL;
+ int error = 0;
+
+ *ancestor_head_out = NULL;
+ *our_head_out = NULL;
+
+ if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0)
+ goto done;
+
+ if ((error = git_reference_lookup(&our_ref, repo, GIT_HEAD_FILE)) < 0 ||
+ (error = git_merge_head_from_ref(&our_head, repo, our_ref)) < 0)
+ goto done;
+
+ if ((error = merge_ancestor_head(&ancestor_head, repo, our_head, their_heads, their_heads_len)) < 0) {
+ if (error != GIT_ENOTFOUND)
+ goto done;
+
+ giterr_clear();
+ error = 0;
+ }
+
+ *ancestor_head_out = ancestor_head;
+ *our_head_out = our_head;
+
+done:
+ if (error < 0) {
+ git_merge_head_free(ancestor_head);
+ git_merge_head_free(our_head);
+ }
+
+ git_reference_free(our_ref);
+
+ return error;
+}
+
+int git_merge_status(
+ git_merge_status_t *out,
+ git_repository *repo,
+ const git_merge_head **their_heads,
+ size_t their_heads_len)
+{
+ git_merge_head *ancestor_head = NULL, *our_head = NULL;
+ int error;
+
+ assert(out && repo && their_heads);
+
+ *out = GIT_MERGE_STATUS_NORMAL;
+
+ if ((error = merge_heads(&ancestor_head, &our_head, repo, their_heads, their_heads_len)) < 0)
+ goto done;
+
+ if (their_heads_len == 1 && ancestor_head != NULL) {
+ /* We're up-to-date if we're trying to merge our own common ancestor. */
+ if (git_oid_equal(&ancestor_head->oid, &their_heads[0]->oid))
+ *out = GIT_MERGE_STATUS_UP_TO_DATE;
+
+ /* We're fastforwardable if we're our own common ancestor. */
+ else if (git_oid_equal(&ancestor_head->oid, &our_head->oid))
+ *out = GIT_MERGE_STATUS_FASTFORWARD;
+ }
+
+done:
+ return error;
+}
+
int git_merge(
git_merge_result **out,
git_repository *repo,
@@ -2530,15 +2603,7 @@ int git_merge(
their_trees = git__calloc(their_heads_len, sizeof(git_tree *));
GITERR_CHECK_ALLOC(their_trees);
- if ((error = git_repository__ensure_not_bare(repo, "merge")) < 0)
- goto on_error;
-
- if ((error = git_reference_lookup(&our_ref, repo, GIT_HEAD_FILE)) < 0 ||
- (error = git_merge_head_from_ref(&our_head, repo, our_ref)) < 0)
- goto on_error;
-
- if ((error = merge_ancestor_head(&ancestor_head, repo, our_head, their_heads, their_heads_len)) < 0 &&
- error != GIT_ENOTFOUND)
+ if ((error = merge_heads(&ancestor_head, &our_head, repo, their_heads, their_heads_len)) < 0)
goto on_error;
if ((error = merge_normalize_opts(repo, &opts, given_opts, ancestor_head, our_head, their_heads_len, their_heads)) < 0)