]> git.ipfire.org Git - thirdparty/git.git/blame - notes-merge.c
git notes merge: Manual conflict resolution, part 2/2
[thirdparty/git.git] / notes-merge.c
CommitLineData
75ef3f4a
JH
1#include "cache.h"
2#include "commit.h"
3#include "refs.h"
2085b16a
JH
4#include "diff.h"
5#include "diffcore.h"
809f38c8
JH
6#include "xdiff-interface.h"
7#include "ll-merge.h"
8#include "dir.h"
56881843 9#include "notes.h"
75ef3f4a
JH
10#include "notes-merge.h"
11
2085b16a
JH
12struct notes_merge_pair {
13 unsigned char obj[20], base[20], local[20], remote[20];
14};
15
75ef3f4a
JH
16void init_notes_merge_options(struct notes_merge_options *o)
17{
18 memset(o, 0, sizeof(struct notes_merge_options));
19 o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
20}
21
22#define OUTPUT(o, v, ...) \
23 do { \
24 if ((o)->verbosity >= (v)) { \
25 printf(__VA_ARGS__); \
26 puts(""); \
27 } \
28 } while (0)
29
2085b16a
JH
30static int path_to_sha1(const char *path, unsigned char *sha1)
31{
32 char hex_sha1[40];
33 int i = 0;
34 while (*path && i < 40) {
35 if (*path != '/')
36 hex_sha1[i++] = *path;
37 path++;
38 }
39 if (*path || i != 40)
40 return -1;
41 return get_sha1_hex(hex_sha1, sha1);
42}
43
44static int verify_notes_filepair(struct diff_filepair *p, unsigned char *sha1)
45{
46 switch (p->status) {
47 case DIFF_STATUS_MODIFIED:
48 assert(p->one->mode == p->two->mode);
49 assert(!is_null_sha1(p->one->sha1));
50 assert(!is_null_sha1(p->two->sha1));
51 break;
52 case DIFF_STATUS_ADDED:
53 assert(is_null_sha1(p->one->sha1));
54 break;
55 case DIFF_STATUS_DELETED:
56 assert(is_null_sha1(p->two->sha1));
57 break;
58 default:
59 return -1;
60 }
61 assert(!strcmp(p->one->path, p->two->path));
62 return path_to_sha1(p->one->path, sha1);
63}
64
65static struct notes_merge_pair *find_notes_merge_pair_pos(
66 struct notes_merge_pair *list, int len, unsigned char *obj,
67 int insert_new, int *occupied)
68{
69 /*
70 * Both diff_tree_remote() and diff_tree_local() tend to process
71 * merge_pairs in ascending order. Therefore, cache last returned
72 * index, and search sequentially from there until the appropriate
73 * position is found.
74 *
75 * Since inserts only happen from diff_tree_remote() (which mainly
76 * _appends_), we don't care that inserting into the middle of the
77 * list is expensive (using memmove()).
78 */
79 static int last_index;
80 int i = last_index < len ? last_index : len - 1;
81 int prev_cmp = 0, cmp = -1;
82 while (i >= 0 && i < len) {
83 cmp = hashcmp(obj, list[i].obj);
84 if (!cmp) /* obj belongs @ i */
85 break;
86 else if (cmp < 0 && prev_cmp <= 0) /* obj belongs < i */
87 i--;
88 else if (cmp < 0) /* obj belongs between i-1 and i */
89 break;
90 else if (cmp > 0 && prev_cmp >= 0) /* obj belongs > i */
91 i++;
92 else /* if (cmp > 0) */ { /* obj belongs between i and i+1 */
93 i++;
94 break;
95 }
96 prev_cmp = cmp;
97 }
98 if (i < 0)
99 i = 0;
100 /* obj belongs at, or immediately preceding, index i (0 <= i <= len) */
101
102 if (!cmp)
103 *occupied = 1;
104 else {
105 *occupied = 0;
106 if (insert_new && i < len) {
107 memmove(list + i + 1, list + i,
108 (len - i) * sizeof(struct notes_merge_pair));
109 memset(list + i, 0, sizeof(struct notes_merge_pair));
110 }
111 }
112 last_index = i;
113 return list + i;
114}
115
116static unsigned char uninitialized[20] =
117 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
118 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
119
120static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
121 const unsigned char *base,
122 const unsigned char *remote,
123 int *num_changes)
124{
125 struct diff_options opt;
126 struct notes_merge_pair *changes;
127 int i, len = 0;
128
129 trace_printf("\tdiff_tree_remote(base = %.7s, remote = %.7s)\n",
130 sha1_to_hex(base), sha1_to_hex(remote));
131
132 diff_setup(&opt);
133 DIFF_OPT_SET(&opt, RECURSIVE);
134 opt.output_format = DIFF_FORMAT_NO_OUTPUT;
135 if (diff_setup_done(&opt) < 0)
136 die("diff_setup_done failed");
137 diff_tree_sha1(base, remote, "", &opt);
138 diffcore_std(&opt);
139
140 changes = xcalloc(diff_queued_diff.nr, sizeof(struct notes_merge_pair));
141
142 for (i = 0; i < diff_queued_diff.nr; i++) {
143 struct diff_filepair *p = diff_queued_diff.queue[i];
144 struct notes_merge_pair *mp;
145 int occupied;
146 unsigned char obj[20];
147
148 if (verify_notes_filepair(p, obj)) {
149 trace_printf("\t\tCannot merge entry '%s' (%c): "
150 "%.7s -> %.7s. Skipping!\n", p->one->path,
151 p->status, sha1_to_hex(p->one->sha1),
152 sha1_to_hex(p->two->sha1));
153 continue;
154 }
155 mp = find_notes_merge_pair_pos(changes, len, obj, 1, &occupied);
156 if (occupied) {
157 /* We've found an addition/deletion pair */
158 assert(!hashcmp(mp->obj, obj));
159 if (is_null_sha1(p->one->sha1)) { /* addition */
160 assert(is_null_sha1(mp->remote));
161 hashcpy(mp->remote, p->two->sha1);
162 } else if (is_null_sha1(p->two->sha1)) { /* deletion */
163 assert(is_null_sha1(mp->base));
164 hashcpy(mp->base, p->one->sha1);
165 } else
166 assert(!"Invalid existing change recorded");
167 } else {
168 hashcpy(mp->obj, obj);
169 hashcpy(mp->base, p->one->sha1);
170 hashcpy(mp->local, uninitialized);
171 hashcpy(mp->remote, p->two->sha1);
172 len++;
173 }
174 trace_printf("\t\tStored remote change for %s: %.7s -> %.7s\n",
175 sha1_to_hex(mp->obj), sha1_to_hex(mp->base),
176 sha1_to_hex(mp->remote));
177 }
178 diff_flush(&opt);
179 diff_tree_release_paths(&opt);
180
181 *num_changes = len;
182 return changes;
183}
184
185static void diff_tree_local(struct notes_merge_options *o,
186 struct notes_merge_pair *changes, int len,
187 const unsigned char *base,
188 const unsigned char *local)
189{
190 struct diff_options opt;
191 int i;
192
193 trace_printf("\tdiff_tree_local(len = %i, base = %.7s, local = %.7s)\n",
194 len, sha1_to_hex(base), sha1_to_hex(local));
195
196 diff_setup(&opt);
197 DIFF_OPT_SET(&opt, RECURSIVE);
198 opt.output_format = DIFF_FORMAT_NO_OUTPUT;
199 if (diff_setup_done(&opt) < 0)
200 die("diff_setup_done failed");
201 diff_tree_sha1(base, local, "", &opt);
202 diffcore_std(&opt);
203
204 for (i = 0; i < diff_queued_diff.nr; i++) {
205 struct diff_filepair *p = diff_queued_diff.queue[i];
206 struct notes_merge_pair *mp;
207 int match;
208 unsigned char obj[20];
209
210 if (verify_notes_filepair(p, obj)) {
211 trace_printf("\t\tCannot merge entry '%s' (%c): "
212 "%.7s -> %.7s. Skipping!\n", p->one->path,
213 p->status, sha1_to_hex(p->one->sha1),
214 sha1_to_hex(p->two->sha1));
215 continue;
216 }
217 mp = find_notes_merge_pair_pos(changes, len, obj, 0, &match);
218 if (!match) {
219 trace_printf("\t\tIgnoring local-only change for %s: "
220 "%.7s -> %.7s\n", sha1_to_hex(obj),
221 sha1_to_hex(p->one->sha1),
222 sha1_to_hex(p->two->sha1));
223 continue;
224 }
225
226 assert(!hashcmp(mp->obj, obj));
227 if (is_null_sha1(p->two->sha1)) { /* deletion */
228 /*
229 * Either this is a true deletion (1), or it is part
230 * of an A/D pair (2), or D/A pair (3):
231 *
232 * (1) mp->local is uninitialized; set it to null_sha1
233 * (2) mp->local is not uninitialized; don't touch it
234 * (3) mp->local is uninitialized; set it to null_sha1
235 * (will be overwritten by following addition)
236 */
237 if (!hashcmp(mp->local, uninitialized))
238 hashclr(mp->local);
239 } else if (is_null_sha1(p->one->sha1)) { /* addition */
240 /*
241 * Either this is a true addition (1), or it is part
242 * of an A/D pair (2), or D/A pair (3):
243 *
244 * (1) mp->local is uninitialized; set to p->two->sha1
245 * (2) mp->local is uninitialized; set to p->two->sha1
246 * (3) mp->local is null_sha1; set to p->two->sha1
247 */
248 assert(is_null_sha1(mp->local) ||
249 !hashcmp(mp->local, uninitialized));
250 hashcpy(mp->local, p->two->sha1);
251 } else { /* modification */
252 /*
253 * This is a true modification. p->one->sha1 shall
254 * match mp->base, and mp->local shall be uninitialized.
255 * Set mp->local to p->two->sha1.
256 */
257 assert(!hashcmp(p->one->sha1, mp->base));
258 assert(!hashcmp(mp->local, uninitialized));
259 hashcpy(mp->local, p->two->sha1);
260 }
261 trace_printf("\t\tStored local change for %s: %.7s -> %.7s\n",
262 sha1_to_hex(mp->obj), sha1_to_hex(mp->base),
263 sha1_to_hex(mp->local));
264 }
265 diff_flush(&opt);
266 diff_tree_release_paths(&opt);
267}
268
809f38c8
JH
269static void check_notes_merge_worktree(struct notes_merge_options *o)
270{
271 if (!o->has_worktree) {
272 /*
273 * Must establish NOTES_MERGE_WORKTREE.
274 * Abort if NOTES_MERGE_WORKTREE already exists
275 */
276 if (file_exists(git_path(NOTES_MERGE_WORKTREE))) {
277 if (advice_resolve_conflict)
278 die("You have not concluded your previous "
279 "notes merge (%s exists).\nPlease, use "
280 "'git notes merge --commit' or 'git notes "
6abb3655 281 "merge --abort' to commit/abort the "
809f38c8
JH
282 "previous merge before you start a new "
283 "notes merge.", git_path("NOTES_MERGE_*"));
284 else
285 die("You have not concluded your notes merge "
286 "(%s exists).", git_path("NOTES_MERGE_*"));
287 }
288
289 if (safe_create_leading_directories(git_path(
290 NOTES_MERGE_WORKTREE "/.test")))
291 die_errno("unable to create directory %s",
292 git_path(NOTES_MERGE_WORKTREE));
293 o->has_worktree = 1;
294 } else if (!file_exists(git_path(NOTES_MERGE_WORKTREE)))
295 /* NOTES_MERGE_WORKTREE should already be established */
296 die("missing '%s'. This should not happen",
297 git_path(NOTES_MERGE_WORKTREE));
298}
299
300static void write_buf_to_worktree(const unsigned char *obj,
301 const char *buf, unsigned long size)
302{
303 int fd;
304 char *path = git_path(NOTES_MERGE_WORKTREE "/%s", sha1_to_hex(obj));
305 if (safe_create_leading_directories(path))
306 die_errno("unable to create directory for '%s'", path);
307 if (file_exists(path))
308 die("found existing file at '%s'", path);
309
310 fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0666);
311 if (fd < 0)
312 die_errno("failed to open '%s'", path);
313
314 while (size > 0) {
315 long ret = write_in_full(fd, buf, size);
316 if (ret < 0) {
317 /* Ignore epipe */
318 if (errno == EPIPE)
319 break;
320 die_errno("notes-merge");
321 } else if (!ret) {
322 die("notes-merge: disk full?");
323 }
324 size -= ret;
325 buf += ret;
326 }
327
328 close(fd);
329}
330
331static void write_note_to_worktree(const unsigned char *obj,
332 const unsigned char *note)
333{
334 enum object_type type;
335 unsigned long size;
336 void *buf = read_sha1_file(note, &type, &size);
337
338 if (!buf)
339 die("cannot read note %s for object %s",
340 sha1_to_hex(note), sha1_to_hex(obj));
341 if (type != OBJ_BLOB)
342 die("blob expected in note %s for object %s",
343 sha1_to_hex(note), sha1_to_hex(obj));
344 write_buf_to_worktree(obj, buf, size);
345 free(buf);
346}
347
348static int ll_merge_in_worktree(struct notes_merge_options *o,
349 struct notes_merge_pair *p)
350{
351 mmbuffer_t result_buf;
352 mmfile_t base, local, remote;
353 int status;
354
355 read_mmblob(&base, p->base);
356 read_mmblob(&local, p->local);
357 read_mmblob(&remote, p->remote);
358
359 status = ll_merge(&result_buf, sha1_to_hex(p->obj), &base, NULL,
360 &local, o->local_ref, &remote, o->remote_ref, 0);
361
362 free(base.ptr);
363 free(local.ptr);
364 free(remote.ptr);
365
366 if ((status < 0) || !result_buf.ptr)
367 die("Failed to execute internal merge");
368
369 write_buf_to_worktree(p->obj, result_buf.ptr, result_buf.size);
370 free(result_buf.ptr);
371
372 return status;
373}
374
375static int merge_one_change_manual(struct notes_merge_options *o,
376 struct notes_merge_pair *p,
377 struct notes_tree *t)
378{
379 const char *lref = o->local_ref ? o->local_ref : "local version";
380 const char *rref = o->remote_ref ? o->remote_ref : "remote version";
381
382 trace_printf("\t\t\tmerge_one_change_manual(obj = %.7s, base = %.7s, "
383 "local = %.7s, remote = %.7s)\n",
384 sha1_to_hex(p->obj), sha1_to_hex(p->base),
385 sha1_to_hex(p->local), sha1_to_hex(p->remote));
386
387 OUTPUT(o, 2, "Auto-merging notes for %s", sha1_to_hex(p->obj));
388 check_notes_merge_worktree(o);
389 if (is_null_sha1(p->local)) {
390 /* D/F conflict, checkout p->remote */
391 assert(!is_null_sha1(p->remote));
392 OUTPUT(o, 1, "CONFLICT (delete/modify): Notes for object %s "
393 "deleted in %s and modified in %s. Version from %s "
394 "left in tree.", sha1_to_hex(p->obj), lref, rref, rref);
395 write_note_to_worktree(p->obj, p->remote);
396 } else if (is_null_sha1(p->remote)) {
397 /* D/F conflict, checkout p->local */
398 assert(!is_null_sha1(p->local));
399 OUTPUT(o, 1, "CONFLICT (delete/modify): Notes for object %s "
400 "deleted in %s and modified in %s. Version from %s "
401 "left in tree.", sha1_to_hex(p->obj), rref, lref, lref);
402 write_note_to_worktree(p->obj, p->local);
403 } else {
404 /* "regular" conflict, checkout result of ll_merge() */
405 const char *reason = "content";
406 if (is_null_sha1(p->base))
407 reason = "add/add";
408 assert(!is_null_sha1(p->local));
409 assert(!is_null_sha1(p->remote));
410 OUTPUT(o, 1, "CONFLICT (%s): Merge conflict in notes for "
411 "object %s", reason, sha1_to_hex(p->obj));
412 ll_merge_in_worktree(o, p);
413 }
414
415 trace_printf("\t\t\tremoving from partial merge result\n");
416 remove_note(t, p->obj);
417
418 return 1;
419}
420
3228e671
JH
421static int merge_one_change(struct notes_merge_options *o,
422 struct notes_merge_pair *p, struct notes_tree *t)
423{
424 /*
809f38c8
JH
425 * Return 0 if change is successfully resolved (stored in notes_tree).
426 * Return 1 is change results in a conflict (NOT stored in notes_tree,
427 * but instead written to NOTES_MERGE_WORKTREE with conflict markers).
3228e671
JH
428 */
429 switch (o->strategy) {
430 case NOTES_MERGE_RESOLVE_MANUAL:
809f38c8 431 return merge_one_change_manual(o, p, t);
3228e671
JH
432 case NOTES_MERGE_RESOLVE_OURS:
433 OUTPUT(o, 2, "Using local notes for %s", sha1_to_hex(p->obj));
434 /* nothing to do */
435 return 0;
436 case NOTES_MERGE_RESOLVE_THEIRS:
437 OUTPUT(o, 2, "Using remote notes for %s", sha1_to_hex(p->obj));
438 if (add_note(t, p->obj, p->remote, combine_notes_overwrite))
439 die("BUG: combine_notes_overwrite failed");
440 return 0;
441 case NOTES_MERGE_RESOLVE_UNION:
442 OUTPUT(o, 2, "Concatenating local and remote notes for %s",
443 sha1_to_hex(p->obj));
444 if (add_note(t, p->obj, p->remote, combine_notes_concatenate))
445 die("failed to concatenate notes "
446 "(combine_notes_concatenate)");
447 return 0;
448 }
449 die("Unknown strategy (%i).", o->strategy);
450}
451
2085b16a
JH
452static int merge_changes(struct notes_merge_options *o,
453 struct notes_merge_pair *changes, int *num_changes,
454 struct notes_tree *t)
455{
456 int i, conflicts = 0;
457
458 trace_printf("\tmerge_changes(num_changes = %i)\n", *num_changes);
459 for (i = 0; i < *num_changes; i++) {
460 struct notes_merge_pair *p = changes + i;
461 trace_printf("\t\t%.7s: %.7s -> %.7s/%.7s\n",
462 sha1_to_hex(p->obj), sha1_to_hex(p->base),
463 sha1_to_hex(p->local), sha1_to_hex(p->remote));
464
465 if (!hashcmp(p->base, p->remote)) {
466 /* no remote change; nothing to do */
467 trace_printf("\t\t\tskipping (no remote change)\n");
468 } else if (!hashcmp(p->local, p->remote)) {
469 /* same change in local and remote; nothing to do */
470 trace_printf("\t\t\tskipping (local == remote)\n");
471 } else if (!hashcmp(p->local, uninitialized) ||
472 !hashcmp(p->local, p->base)) {
473 /* no local change; adopt remote change */
474 trace_printf("\t\t\tno local change, adopted remote\n");
475 if (add_note(t, p->obj, p->remote,
476 combine_notes_overwrite))
477 die("BUG: combine_notes_overwrite failed");
478 } else {
479 /* need file-level merge between local and remote */
480 trace_printf("\t\t\tneed content-level merge\n");
3228e671 481 conflicts += merge_one_change(o, p, t);
2085b16a
JH
482 }
483 }
484
485 return conflicts;
486}
487
488static int merge_from_diffs(struct notes_merge_options *o,
489 const unsigned char *base,
490 const unsigned char *local,
491 const unsigned char *remote, struct notes_tree *t)
492{
493 struct notes_merge_pair *changes;
494 int num_changes, conflicts;
495
496 trace_printf("\tmerge_from_diffs(base = %.7s, local = %.7s, "
497 "remote = %.7s)\n", sha1_to_hex(base), sha1_to_hex(local),
498 sha1_to_hex(remote));
499
500 changes = diff_tree_remote(o, base, remote, &num_changes);
501 diff_tree_local(o, changes, num_changes, base, local);
502
503 conflicts = merge_changes(o, changes, &num_changes, t);
504 free(changes);
505
506 OUTPUT(o, 4, "Merge result: %i unmerged notes and a %s notes tree",
507 conflicts, t->dirty ? "dirty" : "clean");
508
509 return conflicts ? -1 : 1;
510}
511
56881843
JH
512void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
513 const char *msg, unsigned char *result_sha1)
514{
515 unsigned char tree_sha1[20];
516
517 assert(t->initialized);
518
519 if (write_notes_tree(t, tree_sha1))
520 die("Failed to write notes tree to database");
521
522 if (!parents) {
523 /* Deduce parent commit from t->ref */
524 unsigned char parent_sha1[20];
525 if (!read_ref(t->ref, parent_sha1)) {
526 struct commit *parent = lookup_commit(parent_sha1);
527 if (!parent || parse_commit(parent))
528 die("Failed to find/parse commit %s", t->ref);
529 commit_list_insert(parent, &parents);
530 }
531 /* else: t->ref points to nothing, assume root/orphan commit */
532 }
533
534 if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL))
535 die("Failed to commit notes tree to database");
536}
537
75ef3f4a 538int notes_merge(struct notes_merge_options *o,
2085b16a 539 struct notes_tree *local_tree,
75ef3f4a
JH
540 unsigned char *result_sha1)
541{
542 unsigned char local_sha1[20], remote_sha1[20];
543 struct commit *local, *remote;
544 struct commit_list *bases = NULL;
2085b16a 545 const unsigned char *base_sha1, *base_tree_sha1;
75ef3f4a
JH
546 int result = 0;
547
548 assert(o->local_ref && o->remote_ref);
2085b16a 549 assert(!strcmp(o->local_ref, local_tree->ref));
75ef3f4a
JH
550 hashclr(result_sha1);
551
552 trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n",
553 o->local_ref, o->remote_ref);
554
555 /* Dereference o->local_ref into local_sha1 */
556 if (!resolve_ref(o->local_ref, local_sha1, 0, NULL))
557 die("Failed to resolve local notes ref '%s'", o->local_ref);
558 else if (!check_ref_format(o->local_ref) && is_null_sha1(local_sha1))
559 local = NULL; /* local_sha1 == null_sha1 indicates unborn ref */
560 else if (!(local = lookup_commit_reference(local_sha1)))
561 die("Could not parse local commit %s (%s)",
562 sha1_to_hex(local_sha1), o->local_ref);
563 trace_printf("\tlocal commit: %.7s\n", sha1_to_hex(local_sha1));
564
565 /* Dereference o->remote_ref into remote_sha1 */
566 if (get_sha1(o->remote_ref, remote_sha1)) {
567 /*
568 * Failed to get remote_sha1. If o->remote_ref looks like an
569 * unborn ref, perform the merge using an empty notes tree.
570 */
571 if (!check_ref_format(o->remote_ref)) {
572 hashclr(remote_sha1);
573 remote = NULL;
574 } else {
575 die("Failed to resolve remote notes ref '%s'",
576 o->remote_ref);
577 }
578 } else if (!(remote = lookup_commit_reference(remote_sha1))) {
579 die("Could not parse remote commit %s (%s)",
580 sha1_to_hex(remote_sha1), o->remote_ref);
581 }
582 trace_printf("\tremote commit: %.7s\n", sha1_to_hex(remote_sha1));
583
584 if (!local && !remote)
585 die("Cannot merge empty notes ref (%s) into empty notes ref "
586 "(%s)", o->remote_ref, o->local_ref);
587 if (!local) {
588 /* result == remote commit */
589 hashcpy(result_sha1, remote_sha1);
590 goto found_result;
591 }
592 if (!remote) {
593 /* result == local commit */
594 hashcpy(result_sha1, local_sha1);
595 goto found_result;
596 }
597 assert(local && remote);
598
599 /* Find merge bases */
600 bases = get_merge_bases(local, remote, 1);
601 if (!bases) {
602 base_sha1 = null_sha1;
2085b16a 603 base_tree_sha1 = (unsigned char *)EMPTY_TREE_SHA1_BIN;
75ef3f4a
JH
604 OUTPUT(o, 4, "No merge base found; doing history-less merge");
605 } else if (!bases->next) {
606 base_sha1 = bases->item->object.sha1;
2085b16a 607 base_tree_sha1 = bases->item->tree->object.sha1;
75ef3f4a
JH
608 OUTPUT(o, 4, "One merge base found (%.7s)",
609 sha1_to_hex(base_sha1));
610 } else {
611 /* TODO: How to handle multiple merge-bases? */
612 base_sha1 = bases->item->object.sha1;
2085b16a 613 base_tree_sha1 = bases->item->tree->object.sha1;
75ef3f4a
JH
614 OUTPUT(o, 3, "Multiple merge bases found. Using the first "
615 "(%.7s)", sha1_to_hex(base_sha1));
616 }
617
618 OUTPUT(o, 4, "Merging remote commit %.7s into local commit %.7s with "
619 "merge-base %.7s", sha1_to_hex(remote->object.sha1),
620 sha1_to_hex(local->object.sha1), sha1_to_hex(base_sha1));
621
622 if (!hashcmp(remote->object.sha1, base_sha1)) {
623 /* Already merged; result == local commit */
624 OUTPUT(o, 2, "Already up-to-date!");
625 hashcpy(result_sha1, local->object.sha1);
626 goto found_result;
627 }
628 if (!hashcmp(local->object.sha1, base_sha1)) {
629 /* Fast-forward; result == remote commit */
630 OUTPUT(o, 2, "Fast-forward");
631 hashcpy(result_sha1, remote->object.sha1);
632 goto found_result;
633 }
634
2085b16a
JH
635 result = merge_from_diffs(o, base_tree_sha1, local->tree->object.sha1,
636 remote->tree->object.sha1, local_tree);
637
809f38c8
JH
638 if (result != 0) { /* non-trivial merge (with or without conflicts) */
639 /* Commit (partial) result */
2085b16a
JH
640 struct commit_list *parents = NULL;
641 commit_list_insert(remote, &parents); /* LIFO order */
642 commit_list_insert(local, &parents);
643 create_notes_commit(local_tree, parents, o->commit_msg,
644 result_sha1);
645 }
75ef3f4a
JH
646
647found_result:
648 free_commit_list(bases);
649 trace_printf("notes_merge(): result = %i, result_sha1 = %.7s\n",
650 result, sha1_to_hex(result_sha1));
651 return result;
652}
6abb3655
JH
653
654int notes_merge_commit(struct notes_merge_options *o,
655 struct notes_tree *partial_tree,
656 struct commit *partial_commit,
657 unsigned char *result_sha1)
658{
659 /*
660 * Iterate through files in .git/NOTES_MERGE_WORKTREE and add all
661 * found notes to 'partial_tree'. Write the updates notes tree to
662 * the DB, and commit the resulting tree object while reusing the
663 * commit message and parents from 'partial_commit'.
664 * Finally store the new commit object SHA1 into 'result_sha1'.
665 */
666 struct dir_struct dir;
667 const char *path = git_path(NOTES_MERGE_WORKTREE "/");
668 int path_len = strlen(path), i;
669 const char *msg = strstr(partial_commit->buffer, "\n\n");
670
671 OUTPUT(o, 3, "Committing notes in notes merge worktree at %.*s",
672 path_len - 1, path);
673
674 if (!msg || msg[2] == '\0')
675 die("partial notes commit has empty message");
676 msg += 2;
677
678 memset(&dir, 0, sizeof(dir));
679 read_directory(&dir, path, path_len, NULL);
680 for (i = 0; i < dir.nr; i++) {
681 struct dir_entry *ent = dir.entries[i];
682 struct stat st;
683 const char *relpath = ent->name + path_len;
684 unsigned char obj_sha1[20], blob_sha1[20];
685
686 if (ent->len - path_len != 40 || get_sha1_hex(relpath, obj_sha1)) {
687 OUTPUT(o, 3, "Skipping non-SHA1 entry '%s'", ent->name);
688 continue;
689 }
690
691 /* write file as blob, and add to partial_tree */
692 if (stat(ent->name, &st))
693 die_errno("Failed to stat '%s'", ent->name);
694 if (index_path(blob_sha1, ent->name, &st, 1))
695 die("Failed to write blob object from '%s'", ent->name);
696 if (add_note(partial_tree, obj_sha1, blob_sha1, NULL))
697 die("Failed to add resolved note '%s' to notes tree",
698 ent->name);
699 OUTPUT(o, 4, "Added resolved note for object %s: %s",
700 sha1_to_hex(obj_sha1), sha1_to_hex(blob_sha1));
701 }
702
703 create_notes_commit(partial_tree, partial_commit->parents, msg,
704 result_sha1);
705 OUTPUT(o, 4, "Finalized notes merge commit: %s",
706 sha1_to_hex(result_sha1));
707 return 0;
708}
709
710int notes_merge_abort(struct notes_merge_options *o)
711{
712 /* Remove .git/NOTES_MERGE_WORKTREE directory and all files within */
713 struct strbuf buf = STRBUF_INIT;
714 int ret;
715
716 strbuf_addstr(&buf, git_path(NOTES_MERGE_WORKTREE));
717 OUTPUT(o, 3, "Removing notes merge worktree at %s", buf.buf);
718 ret = remove_dir_recursively(&buf, 0);
719 strbuf_release(&buf);
720 return ret;
721}