Code

git notes merge: Initial implementation handling trivial merges only
[git.git] / notes-merge.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "refs.h"
4 #include "notes-merge.h"
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 }
12 #define OUTPUT(o, v, ...) \
13         do { \
14                 if ((o)->verbosity >= (v)) { \
15                         printf(__VA_ARGS__); \
16                         puts(""); \
17                 } \
18         } while (0)
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;
29         assert(o->local_ref && o->remote_ref);
30         hashclr(result_sha1);
32         trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n",
33                o->local_ref, o->remote_ref);
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));
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));
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);
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         }
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));
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         }
112         /* TODO: */
113         result = error("notes_merge() cannot yet handle real merges.");
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;