The fourteenth batch
[git.git] / notes-merge.c
blobb4cc594a790965aca297fe87392a50b643e6fb41
1 #include "cache.h"
2 #include "commit.h"
3 #include "refs.h"
4 #include "object-store.h"
5 #include "repository.h"
6 #include "diff.h"
7 #include "diffcore.h"
8 #include "xdiff-interface.h"
9 #include "ll-merge.h"
10 #include "dir.h"
11 #include "notes.h"
12 #include "notes-merge.h"
13 #include "strbuf.h"
14 #include "notes-utils.h"
15 #include "commit-reach.h"
17 struct notes_merge_pair {
18         struct object_id obj, base, local, remote;
21 void init_notes_merge_options(struct repository *r,
22                               struct notes_merge_options *o)
24         memset(o, 0, sizeof(struct notes_merge_options));
25         strbuf_init(&(o->commit_msg), 0);
26         o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
27         o->repo = r;
30 static int path_to_oid(const char *path, struct object_id *oid)
32         char hex_oid[GIT_MAX_HEXSZ];
33         int i = 0;
34         while (*path && i < the_hash_algo->hexsz) {
35                 if (*path != '/')
36                         hex_oid[i++] = *path;
37                 path++;
38         }
39         if (*path || i != the_hash_algo->hexsz)
40                 return -1;
41         return get_oid_hex(hex_oid, oid);
44 static int verify_notes_filepair(struct diff_filepair *p, struct object_id *oid)
46         switch (p->status) {
47         case DIFF_STATUS_MODIFIED:
48                 assert(p->one->mode == p->two->mode);
49                 assert(!is_null_oid(&p->one->oid));
50                 assert(!is_null_oid(&p->two->oid));
51                 break;
52         case DIFF_STATUS_ADDED:
53                 assert(is_null_oid(&p->one->oid));
54                 break;
55         case DIFF_STATUS_DELETED:
56                 assert(is_null_oid(&p->two->oid));
57                 break;
58         default:
59                 return -1;
60         }
61         assert(!strcmp(p->one->path, p->two->path));
62         return path_to_oid(p->one->path, oid);
65 static struct notes_merge_pair *find_notes_merge_pair_pos(
66                 struct notes_merge_pair *list, int len, struct object_id *obj,
67                 int insert_new, int *occupied)
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 = oidcmp(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) */
102         if (!cmp)
103                 *occupied = 1;
104         else {
105                 *occupied = 0;
106                 if (insert_new && i < len) {
107                         MOVE_ARRAY(list + i + 1, list + i, len - i);
108                         memset(list + i, 0, sizeof(struct notes_merge_pair));
109                 }
110         }
111         last_index = i;
112         return list + i;
115 static struct object_id uninitialized = {
116         .hash =
117         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
118         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
121 static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
122                                                  const struct object_id *base,
123                                                  const struct object_id *remote,
124                                                  int *num_changes)
126         struct diff_options opt;
127         struct notes_merge_pair *changes;
128         int i, len = 0;
130         trace_printf("\tdiff_tree_remote(base = %.7s, remote = %.7s)\n",
131                oid_to_hex(base), oid_to_hex(remote));
133         repo_diff_setup(o->repo, &opt);
134         opt.flags.recursive = 1;
135         opt.output_format = DIFF_FORMAT_NO_OUTPUT;
136         diff_setup_done(&opt);
137         diff_tree_oid(base, remote, "", &opt);
138         diffcore_std(&opt);
140         CALLOC_ARRAY(changes, diff_queued_diff.nr);
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                 struct object_id obj;
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, oid_to_hex(&p->one->oid),
152                                oid_to_hex(&p->two->oid));
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(oideq(&mp->obj, &obj));
159                         if (is_null_oid(&p->one->oid)) { /* addition */
160                                 assert(is_null_oid(&mp->remote));
161                                 oidcpy(&mp->remote, &p->two->oid);
162                         } else if (is_null_oid(&p->two->oid)) { /* deletion */
163                                 assert(is_null_oid(&mp->base));
164                                 oidcpy(&mp->base, &p->one->oid);
165                         } else
166                                 assert(!"Invalid existing change recorded");
167                 } else {
168                         oidcpy(&mp->obj, &obj);
169                         oidcpy(&mp->base, &p->one->oid);
170                         oidcpy(&mp->local, &uninitialized);
171                         oidcpy(&mp->remote, &p->two->oid);
172                         len++;
173                 }
174                 trace_printf("\t\tStored remote change for %s: %.7s -> %.7s\n",
175                        oid_to_hex(&mp->obj), oid_to_hex(&mp->base),
176                        oid_to_hex(&mp->remote));
177         }
178         diff_flush(&opt);
180         *num_changes = len;
181         return changes;
184 static void diff_tree_local(struct notes_merge_options *o,
185                             struct notes_merge_pair *changes, int len,
186                             const struct object_id *base,
187                             const struct object_id *local)
189         struct diff_options opt;
190         int i;
192         trace_printf("\tdiff_tree_local(len = %i, base = %.7s, local = %.7s)\n",
193                len, oid_to_hex(base), oid_to_hex(local));
195         repo_diff_setup(o->repo, &opt);
196         opt.flags.recursive = 1;
197         opt.output_format = DIFF_FORMAT_NO_OUTPUT;
198         diff_setup_done(&opt);
199         diff_tree_oid(base, local, "", &opt);
200         diffcore_std(&opt);
202         for (i = 0; i < diff_queued_diff.nr; i++) {
203                 struct diff_filepair *p = diff_queued_diff.queue[i];
204                 struct notes_merge_pair *mp;
205                 int match;
206                 struct object_id obj;
208                 if (verify_notes_filepair(p, &obj)) {
209                         trace_printf("\t\tCannot merge entry '%s' (%c): "
210                                "%.7s -> %.7s. Skipping!\n", p->one->path,
211                                p->status, oid_to_hex(&p->one->oid),
212                                oid_to_hex(&p->two->oid));
213                         continue;
214                 }
215                 mp = find_notes_merge_pair_pos(changes, len, &obj, 0, &match);
216                 if (!match) {
217                         trace_printf("\t\tIgnoring local-only change for %s: "
218                                "%.7s -> %.7s\n", oid_to_hex(&obj),
219                                oid_to_hex(&p->one->oid),
220                                oid_to_hex(&p->two->oid));
221                         continue;
222                 }
224                 assert(oideq(&mp->obj, &obj));
225                 if (is_null_oid(&p->two->oid)) { /* deletion */
226                         /*
227                          * Either this is a true deletion (1), or it is part
228                          * of an A/D pair (2), or D/A pair (3):
229                          *
230                          * (1) mp->local is uninitialized; set it to null_sha1
231                          * (2) mp->local is not uninitialized; don't touch it
232                          * (3) mp->local is uninitialized; set it to null_sha1
233                          *     (will be overwritten by following addition)
234                          */
235                         if (oideq(&mp->local, &uninitialized))
236                                 oidclr(&mp->local);
237                 } else if (is_null_oid(&p->one->oid)) { /* addition */
238                         /*
239                          * Either this is a true addition (1), or it is part
240                          * of an A/D pair (2), or D/A pair (3):
241                          *
242                          * (1) mp->local is uninitialized; set to p->two->sha1
243                          * (2) mp->local is uninitialized; set to p->two->sha1
244                          * (3) mp->local is null_sha1;     set to p->two->sha1
245                          */
246                         assert(is_null_oid(&mp->local) ||
247                                oideq(&mp->local, &uninitialized));
248                         oidcpy(&mp->local, &p->two->oid);
249                 } else { /* modification */
250                         /*
251                          * This is a true modification. p->one->sha1 shall
252                          * match mp->base, and mp->local shall be uninitialized.
253                          * Set mp->local to p->two->sha1.
254                          */
255                         assert(oideq(&p->one->oid, &mp->base));
256                         assert(oideq(&mp->local, &uninitialized));
257                         oidcpy(&mp->local, &p->two->oid);
258                 }
259                 trace_printf("\t\tStored local change for %s: %.7s -> %.7s\n",
260                        oid_to_hex(&mp->obj), oid_to_hex(&mp->base),
261                        oid_to_hex(&mp->local));
262         }
263         diff_flush(&opt);
266 static void check_notes_merge_worktree(struct notes_merge_options *o)
268         if (!o->has_worktree) {
269                 /*
270                  * Must establish NOTES_MERGE_WORKTREE.
271                  * Abort if NOTES_MERGE_WORKTREE already exists
272                  */
273                 if (file_exists(git_path(NOTES_MERGE_WORKTREE)) &&
274                     !is_empty_dir(git_path(NOTES_MERGE_WORKTREE))) {
275                         if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
276                                 die(_("You have not concluded your previous "
277                                     "notes merge (%s exists).\nPlease, use "
278                                     "'git notes merge --commit' or 'git notes "
279                                     "merge --abort' to commit/abort the "
280                                     "previous merge before you start a new "
281                                     "notes merge."), git_path("NOTES_MERGE_*"));
282                         else
283                                 die(_("You have not concluded your notes merge "
284                                     "(%s exists)."), git_path("NOTES_MERGE_*"));
285                 }
287                 if (safe_create_leading_directories_const(git_path(
288                                 NOTES_MERGE_WORKTREE "/.test")))
289                         die_errno("unable to create directory %s",
290                                   git_path(NOTES_MERGE_WORKTREE));
291                 o->has_worktree = 1;
292         } else if (!file_exists(git_path(NOTES_MERGE_WORKTREE)))
293                 /* NOTES_MERGE_WORKTREE should already be established */
294                 die("missing '%s'. This should not happen",
295                     git_path(NOTES_MERGE_WORKTREE));
298 static void write_buf_to_worktree(const struct object_id *obj,
299                                   const char *buf, unsigned long size)
301         int fd;
302         char *path = git_pathdup(NOTES_MERGE_WORKTREE "/%s", oid_to_hex(obj));
303         if (safe_create_leading_directories_const(path))
304                 die_errno("unable to create directory for '%s'", path);
306         fd = xopen(path, O_WRONLY | O_EXCL | O_CREAT, 0666);
308         while (size > 0) {
309                 ssize_t ret = write_in_full(fd, buf, size);
310                 if (ret < 0) {
311                         /* Ignore epipe */
312                         if (errno == EPIPE)
313                                 break;
314                         die_errno("notes-merge");
315                 }
316                 size -= ret;
317                 buf += ret;
318         }
320         close(fd);
321         free(path);
324 static void write_note_to_worktree(const struct object_id *obj,
325                                    const struct object_id *note)
327         enum object_type type;
328         unsigned long size;
329         void *buf = read_object_file(note, &type, &size);
331         if (!buf)
332                 die("cannot read note %s for object %s",
333                     oid_to_hex(note), oid_to_hex(obj));
334         if (type != OBJ_BLOB)
335                 die("blob expected in note %s for object %s",
336                     oid_to_hex(note), oid_to_hex(obj));
337         write_buf_to_worktree(obj, buf, size);
338         free(buf);
341 static int ll_merge_in_worktree(struct notes_merge_options *o,
342                                 struct notes_merge_pair *p)
344         mmbuffer_t result_buf;
345         mmfile_t base, local, remote;
346         enum ll_merge_result status;
348         read_mmblob(&base, &p->base);
349         read_mmblob(&local, &p->local);
350         read_mmblob(&remote, &p->remote);
352         status = ll_merge(&result_buf, oid_to_hex(&p->obj), &base, NULL,
353                           &local, o->local_ref, &remote, o->remote_ref,
354                           o->repo->index, NULL);
356         free(base.ptr);
357         free(local.ptr);
358         free(remote.ptr);
360         if (status == LL_MERGE_BINARY_CONFLICT)
361                 warning("Cannot merge binary files: %s (%s vs. %s)",
362                         oid_to_hex(&p->obj), o->local_ref, o->remote_ref);
363         if ((status < 0) || !result_buf.ptr)
364                 die("Failed to execute internal merge");
366         write_buf_to_worktree(&p->obj, result_buf.ptr, result_buf.size);
367         free(result_buf.ptr);
369         return status;
372 static int merge_one_change_manual(struct notes_merge_options *o,
373                                    struct notes_merge_pair *p,
374                                    struct notes_tree *t)
376         const char *lref = o->local_ref ? o->local_ref : "local version";
377         const char *rref = o->remote_ref ? o->remote_ref : "remote version";
379         trace_printf("\t\t\tmerge_one_change_manual(obj = %.7s, base = %.7s, "
380                "local = %.7s, remote = %.7s)\n",
381                oid_to_hex(&p->obj), oid_to_hex(&p->base),
382                oid_to_hex(&p->local), oid_to_hex(&p->remote));
384         /* add "Conflicts:" section to commit message first time through */
385         if (!o->has_worktree)
386                 strbuf_addstr(&(o->commit_msg), "\n\nConflicts:\n");
388         strbuf_addf(&(o->commit_msg), "\t%s\n", oid_to_hex(&p->obj));
390         if (o->verbosity >= 2)
391                 printf("Auto-merging notes for %s\n", oid_to_hex(&p->obj));
392         check_notes_merge_worktree(o);
393         if (is_null_oid(&p->local)) {
394                 /* D/F conflict, checkout p->remote */
395                 assert(!is_null_oid(&p->remote));
396                 if (o->verbosity >= 1)
397                         printf("CONFLICT (delete/modify): Notes for object %s "
398                                 "deleted in %s and modified in %s. Version from %s "
399                                 "left in tree.\n",
400                                 oid_to_hex(&p->obj), lref, rref, rref);
401                 write_note_to_worktree(&p->obj, &p->remote);
402         } else if (is_null_oid(&p->remote)) {
403                 /* D/F conflict, checkout p->local */
404                 assert(!is_null_oid(&p->local));
405                 if (o->verbosity >= 1)
406                         printf("CONFLICT (delete/modify): Notes for object %s "
407                                 "deleted in %s and modified in %s. Version from %s "
408                                 "left in tree.\n",
409                                 oid_to_hex(&p->obj), rref, lref, lref);
410                 write_note_to_worktree(&p->obj, &p->local);
411         } else {
412                 /* "regular" conflict, checkout result of ll_merge() */
413                 const char *reason = "content";
414                 if (is_null_oid(&p->base))
415                         reason = "add/add";
416                 assert(!is_null_oid(&p->local));
417                 assert(!is_null_oid(&p->remote));
418                 if (o->verbosity >= 1)
419                         printf("CONFLICT (%s): Merge conflict in notes for "
420                                 "object %s\n", reason,
421                                 oid_to_hex(&p->obj));
422                 ll_merge_in_worktree(o, p);
423         }
425         trace_printf("\t\t\tremoving from partial merge result\n");
426         remove_note(t, p->obj.hash);
428         return 1;
431 static int merge_one_change(struct notes_merge_options *o,
432                             struct notes_merge_pair *p, struct notes_tree *t)
434         /*
435          * Return 0 if change is successfully resolved (stored in notes_tree).
436          * Return 1 is change results in a conflict (NOT stored in notes_tree,
437          * but instead written to NOTES_MERGE_WORKTREE with conflict markers).
438          */
439         switch (o->strategy) {
440         case NOTES_MERGE_RESOLVE_MANUAL:
441                 return merge_one_change_manual(o, p, t);
442         case NOTES_MERGE_RESOLVE_OURS:
443                 if (o->verbosity >= 2)
444                         printf("Using local notes for %s\n",
445                                                 oid_to_hex(&p->obj));
446                 /* nothing to do */
447                 return 0;
448         case NOTES_MERGE_RESOLVE_THEIRS:
449                 if (o->verbosity >= 2)
450                         printf("Using remote notes for %s\n",
451                                                 oid_to_hex(&p->obj));
452                 if (add_note(t, &p->obj, &p->remote, combine_notes_overwrite))
453                         BUG("combine_notes_overwrite failed");
454                 return 0;
455         case NOTES_MERGE_RESOLVE_UNION:
456                 if (o->verbosity >= 2)
457                         printf("Concatenating local and remote notes for %s\n",
458                                                         oid_to_hex(&p->obj));
459                 if (add_note(t, &p->obj, &p->remote, combine_notes_concatenate))
460                         die("failed to concatenate notes "
461                             "(combine_notes_concatenate)");
462                 return 0;
463         case NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ:
464                 if (o->verbosity >= 2)
465                         printf("Concatenating unique lines in local and remote "
466                                 "notes for %s\n", oid_to_hex(&p->obj));
467                 if (add_note(t, &p->obj, &p->remote, combine_notes_cat_sort_uniq))
468                         die("failed to concatenate notes "
469                             "(combine_notes_cat_sort_uniq)");
470                 return 0;
471         }
472         die("Unknown strategy (%i).", o->strategy);
475 static int merge_changes(struct notes_merge_options *o,
476                          struct notes_merge_pair *changes, int *num_changes,
477                          struct notes_tree *t)
479         int i, conflicts = 0;
481         trace_printf("\tmerge_changes(num_changes = %i)\n", *num_changes);
482         for (i = 0; i < *num_changes; i++) {
483                 struct notes_merge_pair *p = changes + i;
484                 trace_printf("\t\t%.7s: %.7s -> %.7s/%.7s\n",
485                        oid_to_hex(&p->obj), oid_to_hex(&p->base),
486                        oid_to_hex(&p->local),
487                        oid_to_hex(&p->remote));
489                 if (oideq(&p->base, &p->remote)) {
490                         /* no remote change; nothing to do */
491                         trace_printf("\t\t\tskipping (no remote change)\n");
492                 } else if (oideq(&p->local, &p->remote)) {
493                         /* same change in local and remote; nothing to do */
494                         trace_printf("\t\t\tskipping (local == remote)\n");
495                 } else if (oideq(&p->local, &uninitialized) ||
496                            oideq(&p->local, &p->base)) {
497                         /* no local change; adopt remote change */
498                         trace_printf("\t\t\tno local change, adopted remote\n");
499                         if (add_note(t, &p->obj, &p->remote,
500                                      combine_notes_overwrite))
501                                 BUG("combine_notes_overwrite failed");
502                 } else {
503                         /* need file-level merge between local and remote */
504                         trace_printf("\t\t\tneed content-level merge\n");
505                         conflicts += merge_one_change(o, p, t);
506                 }
507         }
509         return conflicts;
512 static int merge_from_diffs(struct notes_merge_options *o,
513                             const struct object_id *base,
514                             const struct object_id *local,
515                             const struct object_id *remote,
516                             struct notes_tree *t)
518         struct notes_merge_pair *changes;
519         int num_changes, conflicts;
521         trace_printf("\tmerge_from_diffs(base = %.7s, local = %.7s, "
522                "remote = %.7s)\n", oid_to_hex(base), oid_to_hex(local),
523                oid_to_hex(remote));
525         changes = diff_tree_remote(o, base, remote, &num_changes);
526         diff_tree_local(o, changes, num_changes, base, local);
528         conflicts = merge_changes(o, changes, &num_changes, t);
529         free(changes);
531         if (o->verbosity >= 4)
532                 printf(t->dirty ?
533                        "Merge result: %i unmerged notes and a dirty notes tree\n" :
534                        "Merge result: %i unmerged notes and a clean notes tree\n",
535                        conflicts);
537         return conflicts ? -1 : 1;
540 int notes_merge(struct notes_merge_options *o,
541                 struct notes_tree *local_tree,
542                 struct object_id *result_oid)
544         struct object_id local_oid, remote_oid;
545         struct commit *local, *remote;
546         struct commit_list *bases = NULL;
547         const struct object_id *base_oid, *base_tree_oid;
548         int result = 0;
550         assert(o->local_ref && o->remote_ref);
551         assert(!strcmp(o->local_ref, local_tree->ref));
552         oidclr(result_oid);
554         trace_printf("notes_merge(o->local_ref = %s, o->remote_ref = %s)\n",
555                o->local_ref, o->remote_ref);
557         /* Dereference o->local_ref into local_sha1 */
558         if (read_ref_full(o->local_ref, 0, &local_oid, NULL))
559                 die("Failed to resolve local notes ref '%s'", o->local_ref);
560         else if (!check_refname_format(o->local_ref, 0) &&
561                 is_null_oid(&local_oid))
562                 local = NULL; /* local_oid == null_oid indicates unborn ref */
563         else if (!(local = lookup_commit_reference(o->repo, &local_oid)))
564                 die("Could not parse local commit %s (%s)",
565                     oid_to_hex(&local_oid), o->local_ref);
566         trace_printf("\tlocal commit: %.7s\n", oid_to_hex(&local_oid));
568         /* Dereference o->remote_ref into remote_oid */
569         if (get_oid(o->remote_ref, &remote_oid)) {
570                 /*
571                  * Failed to get remote_oid. If o->remote_ref looks like an
572                  * unborn ref, perform the merge using an empty notes tree.
573                  */
574                 if (!check_refname_format(o->remote_ref, 0)) {
575                         oidclr(&remote_oid);
576                         remote = NULL;
577                 } else {
578                         die("Failed to resolve remote notes ref '%s'",
579                             o->remote_ref);
580                 }
581         } else if (!(remote = lookup_commit_reference(o->repo, &remote_oid))) {
582                 die("Could not parse remote commit %s (%s)",
583                     oid_to_hex(&remote_oid), o->remote_ref);
584         }
585         trace_printf("\tremote commit: %.7s\n", oid_to_hex(&remote_oid));
587         if (!local && !remote)
588                 die("Cannot merge empty notes ref (%s) into empty notes ref "
589                     "(%s)", o->remote_ref, o->local_ref);
590         if (!local) {
591                 /* result == remote commit */
592                 oidcpy(result_oid, &remote_oid);
593                 goto found_result;
594         }
595         if (!remote) {
596                 /* result == local commit */
597                 oidcpy(result_oid, &local_oid);
598                 goto found_result;
599         }
600         assert(local && remote);
602         /* Find merge bases */
603         bases = get_merge_bases(local, remote);
604         if (!bases) {
605                 base_oid = null_oid();
606                 base_tree_oid = the_hash_algo->empty_tree;
607                 if (o->verbosity >= 4)
608                         printf("No merge base found; doing history-less merge\n");
609         } else if (!bases->next) {
610                 base_oid = &bases->item->object.oid;
611                 base_tree_oid = get_commit_tree_oid(bases->item);
612                 if (o->verbosity >= 4)
613                         printf("One merge base found (%.7s)\n",
614                                oid_to_hex(base_oid));
615         } else {
616                 /* TODO: How to handle multiple merge-bases? */
617                 base_oid = &bases->item->object.oid;
618                 base_tree_oid = get_commit_tree_oid(bases->item);
619                 if (o->verbosity >= 3)
620                         printf("Multiple merge bases found. Using the first "
621                                 "(%.7s)\n", oid_to_hex(base_oid));
622         }
624         if (o->verbosity >= 4)
625                 printf("Merging remote commit %.7s into local commit %.7s with "
626                         "merge-base %.7s\n", oid_to_hex(&remote->object.oid),
627                         oid_to_hex(&local->object.oid),
628                         oid_to_hex(base_oid));
630         if (oideq(&remote->object.oid, base_oid)) {
631                 /* Already merged; result == local commit */
632                 if (o->verbosity >= 2)
633                         printf_ln("Already up to date.");
634                 oidcpy(result_oid, &local->object.oid);
635                 goto found_result;
636         }
637         if (oideq(&local->object.oid, base_oid)) {
638                 /* Fast-forward; result == remote commit */
639                 if (o->verbosity >= 2)
640                         printf("Fast-forward\n");
641                 oidcpy(result_oid, &remote->object.oid);
642                 goto found_result;
643         }
645         result = merge_from_diffs(o, base_tree_oid,
646                                   get_commit_tree_oid(local),
647                                   get_commit_tree_oid(remote), local_tree);
649         if (result != 0) { /* non-trivial merge (with or without conflicts) */
650                 /* Commit (partial) result */
651                 struct commit_list *parents = NULL;
652                 commit_list_insert(remote, &parents); /* LIFO order */
653                 commit_list_insert(local, &parents);
654                 create_notes_commit(o->repo, local_tree, parents, o->commit_msg.buf,
655                                     o->commit_msg.len, result_oid);
656         }
658 found_result:
659         free_commit_list(bases);
660         strbuf_release(&(o->commit_msg));
661         trace_printf("notes_merge(): result = %i, result_oid = %.7s\n",
662                result, oid_to_hex(result_oid));
663         return result;
666 int notes_merge_commit(struct notes_merge_options *o,
667                        struct notes_tree *partial_tree,
668                        struct commit *partial_commit,
669                        struct object_id *result_oid)
671         /*
672          * Iterate through files in .git/NOTES_MERGE_WORKTREE and add all
673          * found notes to 'partial_tree'. Write the updated notes tree to
674          * the DB, and commit the resulting tree object while reusing the
675          * commit message and parents from 'partial_commit'.
676          * Finally store the new commit object OID into 'result_oid'.
677          */
678         DIR *dir;
679         struct dirent *e;
680         struct strbuf path = STRBUF_INIT;
681         const char *buffer = get_commit_buffer(partial_commit, NULL);
682         const char *msg = strstr(buffer, "\n\n");
683         int baselen;
685         git_path_buf(&path, NOTES_MERGE_WORKTREE);
686         if (o->verbosity >= 3)
687                 printf("Committing notes in notes merge worktree at %s\n",
688                         path.buf);
690         if (!msg || msg[2] == '\0')
691                 die("partial notes commit has empty message");
692         msg += 2;
694         dir = opendir(path.buf);
695         if (!dir)
696                 die_errno("could not open %s", path.buf);
698         strbuf_addch(&path, '/');
699         baselen = path.len;
700         while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL) {
701                 struct stat st;
702                 struct object_id obj_oid, blob_oid;
704                 if (get_oid_hex(e->d_name, &obj_oid)) {
705                         if (o->verbosity >= 3)
706                                 printf("Skipping non-SHA1 entry '%s%s'\n",
707                                         path.buf, e->d_name);
708                         continue;
709                 }
711                 strbuf_addstr(&path, e->d_name);
712                 /* write file as blob, and add to partial_tree */
713                 if (stat(path.buf, &st))
714                         die_errno("Failed to stat '%s'", path.buf);
715                 if (index_path(o->repo->index, &blob_oid, path.buf, &st, HASH_WRITE_OBJECT))
716                         die("Failed to write blob object from '%s'", path.buf);
717                 if (add_note(partial_tree, &obj_oid, &blob_oid, NULL))
718                         die("Failed to add resolved note '%s' to notes tree",
719                             path.buf);
720                 if (o->verbosity >= 4)
721                         printf("Added resolved note for object %s: %s\n",
722                                 oid_to_hex(&obj_oid), oid_to_hex(&blob_oid));
723                 strbuf_setlen(&path, baselen);
724         }
726         create_notes_commit(o->repo, partial_tree, partial_commit->parents, msg,
727                             strlen(msg), result_oid);
728         unuse_commit_buffer(partial_commit, buffer);
729         if (o->verbosity >= 4)
730                 printf("Finalized notes merge commit: %s\n",
731                         oid_to_hex(result_oid));
732         strbuf_release(&path);
733         closedir(dir);
734         return 0;
737 int notes_merge_abort(struct notes_merge_options *o)
739         /*
740          * Remove all files within .git/NOTES_MERGE_WORKTREE. We do not remove
741          * the .git/NOTES_MERGE_WORKTREE directory itself, since it might be
742          * the current working directory of the user.
743          */
744         struct strbuf buf = STRBUF_INIT;
745         int ret;
747         git_path_buf(&buf, NOTES_MERGE_WORKTREE);
748         if (o->verbosity >= 3)
749                 printf("Removing notes merge worktree at %s/*\n", buf.buf);
750         ret = remove_dir_recursively(&buf, REMOVE_DIR_KEEP_TOPLEVEL);
751         strbuf_release(&buf);
752         return ret;