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