3
#include "refs.h"
4
#include "diff.h"
5
#include "diffcore.h"
6
+#include "xdiff-interface.h"
7
+#include "ll-merge.h"
8
+#include "dir.h"
9
#include "notes.h"
10
#include "notes-merge.h"
11
266
diff_tree_release_paths(&opt);
267
}
268
269
+static 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 "
281
+ "merge --reset' to commit/abort the "
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
+
300
+static 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
+
331
+static 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
+
348
+static 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
+
375
+static 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
+
421
static int merge_one_change(struct notes_merge_options *o,
422
struct notes_merge_pair *p, struct notes_tree *t)
423
{
424
/*
270
- * Return 0 if change was resolved (and added to notes_tree),
271
- * 1 if conflict
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).
428
*/
429
switch (o->strategy) {
430
case NOTES_MERGE_RESOLVE_MANUAL:
275
- return 1;
431
+ return merge_one_change_manual(o, p, t);
432
case NOTES_MERGE_RESOLVE_OURS:
433
OUTPUT(o, 2, "Using local notes for %s", sha1_to_hex(p->obj));
434
/* nothing to do */
635
result = merge_from_diffs(o, base_tree_sha1, local->tree->object.sha1,
636
remote->tree->object.sha1, local_tree);
637
482
- if (result > 0) { /* successful non-trivial merge */
483
- /* Commit result */
638
+ if (result != 0) { /* non-trivial merge (with or without conflicts) */
639
+ /* Commit (partial) result */
640
struct commit_list *parents = NULL;
641
commit_list_insert(remote, &parents); /* LIFO order */
642
commit_list_insert(local, &parents);