Raw
1 #include "git-compat-util.h"
2 #include "gettext.h"
3 #include "hash.h"
4 #include "hex.h"
5 #include "lockfile.h"
6 #include "merge-ort.h"
7 #include "merge-ort-wrappers.h"
8 #include "read-cache-ll.h"
9 #include "repository.h"
10 #include "tag.h"
11 #include "tree.h"
12
13 #include "commit.h"
14
15 static int unclean(struct merge_options *opt, struct tree *head)
16 {
17 /* Sanity check on repo state; index must match head */
18 struct strbuf sb = STRBUF_INIT;
19
20 if (head && repo_index_has_changes(opt->repo, head, &sb)) {
21 error(_("Your local changes to the following files would be overwritten by merge:\n %s"),
22 sb.buf);
23 strbuf_release(&sb);
24 return -1;
25 }
26
27 return 0;
28 }
29
30 int merge_ort_nonrecursive(struct merge_options *opt,
31 struct tree *head,
32 struct tree *merge,
33 struct tree *merge_base)
34 {
35 struct merge_result result;
36 int show_msgs;
37
38 if (unclean(opt, head))
39 return -1;
40
41 if (oideq(&merge_base->object.oid, &merge->object.oid)) {
42 printf_ln(_("Already up to date."));
43 return 1;
44 }
45
46 show_msgs = !!opt->verbosity;
47 memset(&result, 0, sizeof(result));
48 merge_incore_nonrecursive(opt, merge_base, head, merge, &result);
49 merge_switch_to_result(opt, head, &result, 1, show_msgs);
50
51 return result.clean;
52 }
53
54 int merge_ort_recursive(struct merge_options *opt,
55 struct commit *side1,
56 struct commit *side2,
57 const struct commit_list *merge_bases,
58 struct commit **result)
59 {
60 struct tree *head = repo_get_commit_tree(opt->repo, side1);
61 struct merge_result tmp;
62 int show_msgs;
63
64 if (unclean(opt, head))
65 return -1;
66
67 show_msgs = !!opt->verbosity;
68 memset(&tmp, 0, sizeof(tmp));
69 merge_incore_recursive(opt, merge_bases, side1, side2, &tmp);
70 merge_switch_to_result(opt, head, &tmp, 1, show_msgs);
71 *result = NULL;
72
73 return tmp.clean;
74 }
75
76 static struct commit *get_ref(struct repository *repo,
77 const struct object_id *oid,
78 const char *name)
79 {
80 struct object *object;
81
82 object = deref_tag(repo, parse_object(repo, oid),
83 name, strlen(name));
84 if (!object)
85 return NULL;
86 if (object->type == OBJ_TREE)
87 return make_virtual_commit(repo, (struct tree*)object, name);
88 if (object->type != OBJ_COMMIT)
89 return NULL;
90 if (repo_parse_commit(repo, (struct commit *)object))
91 return NULL;
92 return (struct commit *)object;
93 }
94
95 int merge_ort_generic(struct merge_options *opt,
96 const struct object_id *head,
97 const struct object_id *merge,
98 int num_merge_bases,
99 const struct object_id *merge_bases,
100 struct commit **result)
101 {
102 int clean;
103 struct lock_file lock = LOCK_INIT;
104 struct commit *head_commit = get_ref(opt->repo, head, opt->branch1);
105 struct commit *next_commit = get_ref(opt->repo, merge, opt->branch2);
106 struct commit_list *ca = NULL;
107
108 if (merge_bases) {
109 int i;
110 for (i = 0; i < num_merge_bases; ++i) {
111 struct commit *base;
112 if (!(base = get_ref(opt->repo, &merge_bases[i],
113 oid_to_hex(&merge_bases[i]))))
114 return error(_("Could not parse object '%s'"),
115 oid_to_hex(&merge_bases[i]));
116 commit_list_insert(base, &ca);
117 }
118 }
119
120 repo_hold_locked_index(opt->repo, &lock, LOCK_DIE_ON_ERROR);
121 clean = merge_ort_recursive(opt, head_commit, next_commit, ca,
122 result);
123 commit_list_free(ca);
124 if (clean < 0) {
125 rollback_lock_file(&lock);
126 return clean;
127 }
128
129 if (write_locked_index(opt->repo->index, &lock,
130 COMMIT_LOCK | SKIP_IF_UNCHANGED))
131 return error(_("Unable to write index."));
132
133 return clean ? 0 : 1;
134 }