1
+#include "cache.h"
2
+#include "commit.h"
3
+#include "refs.h"
4
+#include "notes-merge.h"
5
+
6
+void init_notes_merge_options(struct notes_merge_options *o)
7
+{
8
+ memset(o, 0, sizeof(struct notes_merge_options));
9
+ o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
10
+}
11
+
12
+#define OUTPUT(o, v, ...) \
13
+ do { \
14
+ if ((o)->verbosity >= (v)) { \
15
+ printf(__VA_ARGS__); \
16
+ puts(""); \
17
+ } \
18
+ } while (0)
19
+
20
+int notes_merge(struct notes_merge_options *o,
21
+ unsigned char *result_sha1)
22
+{
23
+ unsigned char local_sha1[20], remote_sha1[20];
24
+ struct commit *local, *remote;
25
+ struct commit_list *bases = NULL;
26
+ const unsigned char *base_sha1;
27
+ int result = 0;
28
+
29
+ assert(o->local_ref && o->remote_ref);
30
+ hashclr(result_sha1);
31
+
32
+ trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n",
33
+ o->local_ref, o->remote_ref);
34
+
35
+ /* Dereference o->local_ref into local_sha1 */
36
+ if (!resolve_ref(o->local_ref, local_sha1, 0, NULL))
37
+ die("Failed to resolve local notes ref '%s'", o->local_ref);
38
+ else if (!check_ref_format(o->local_ref) && is_null_sha1(local_sha1))
39
+ local = NULL; /* local_sha1 == null_sha1 indicates unborn ref */
40
+ else if (!(local = lookup_commit_reference(local_sha1)))
41
+ die("Could not parse local commit %s (%s)",
42
+ sha1_to_hex(local_sha1), o->local_ref);
43
+ trace_printf("\tlocal commit: %.7s\n", sha1_to_hex(local_sha1));
44
+
45
+ /* Dereference o->remote_ref into remote_sha1 */
46
+ if (get_sha1(o->remote_ref, remote_sha1)) {
47
+ /*
48
+ * Failed to get remote_sha1. If o->remote_ref looks like an
49
+ * unborn ref, perform the merge using an empty notes tree.
50
+ */
51
+ if (!check_ref_format(o->remote_ref)) {
52
+ hashclr(remote_sha1);
53
+ remote = NULL;
54
+ } else {
55
+ die("Failed to resolve remote notes ref '%s'",
56
+ o->remote_ref);
57
+ }
58
+ } else if (!(remote = lookup_commit_reference(remote_sha1))) {
59
+ die("Could not parse remote commit %s (%s)",
60
+ sha1_to_hex(remote_sha1), o->remote_ref);
61
+ }
62
+ trace_printf("\tremote commit: %.7s\n", sha1_to_hex(remote_sha1));
63
+
64
+ if (!local && !remote)
65
+ die("Cannot merge empty notes ref (%s) into empty notes ref "
66
+ "(%s)", o->remote_ref, o->local_ref);
67
+ if (!local) {
68
+ /* result == remote commit */
69
+ hashcpy(result_sha1, remote_sha1);
70
+ goto found_result;
71
+ }
72
+ if (!remote) {
73
+ /* result == local commit */
74
+ hashcpy(result_sha1, local_sha1);
75
+ goto found_result;
76
+ }
77
+ assert(local && remote);
78
+
79
+ /* Find merge bases */
80
+ bases = get_merge_bases(local, remote, 1);
81
+ if (!bases) {
82
+ base_sha1 = null_sha1;
83
+ OUTPUT(o, 4, "No merge base found; doing history-less merge");
84
+ } else if (!bases->next) {
85
+ base_sha1 = bases->item->object.sha1;
86
+ OUTPUT(o, 4, "One merge base found (%.7s)",
87
+ sha1_to_hex(base_sha1));
88
+ } else {
89
+ /* TODO: How to handle multiple merge-bases? */
90
+ base_sha1 = bases->item->object.sha1;
91
+ OUTPUT(o, 3, "Multiple merge bases found. Using the first "
92
+ "(%.7s)", sha1_to_hex(base_sha1));
93
+ }
94
+
95
+ OUTPUT(o, 4, "Merging remote commit %.7s into local commit %.7s with "
96
+ "merge-base %.7s", sha1_to_hex(remote->object.sha1),
97
+ sha1_to_hex(local->object.sha1), sha1_to_hex(base_sha1));
98
+
99
+ if (!hashcmp(remote->object.sha1, base_sha1)) {
100
+ /* Already merged; result == local commit */
101
+ OUTPUT(o, 2, "Already up-to-date!");
102
+ hashcpy(result_sha1, local->object.sha1);
103
+ goto found_result;
104
+ }
105
+ if (!hashcmp(local->object.sha1, base_sha1)) {
106
+ /* Fast-forward; result == remote commit */
107
+ OUTPUT(o, 2, "Fast-forward");
108
+ hashcpy(result_sha1, remote->object.sha1);
109
+ goto found_result;
110
+ }
111
+
112
+ /* TODO: */
113
+ result = error("notes_merge() cannot yet handle real merges.");
114
+
115
+found_result:
116
+ free_commit_list(bases);
117
+ trace_printf("notes_merge(): result = %i, result_sha1 = %.7s\n",
118
+ result, sha1_to_hex(result_sha1));
119
+ return result;
120
+}