Git fork
at reftables-rust 722 lines 20 kB view raw
1/* 2 * Copyright (C) 2005 Junio C Hamano 3 */ 4 5#define USE_THE_REPOSITORY_VARIABLE 6#define DISABLE_SIGN_COMPARE_WARNINGS 7 8#include "git-compat-util.h" 9#include "commit.h" 10#include "diff.h" 11#include "diffcore.h" 12#include "gettext.h" 13#include "hash.h" 14#include "hex.h" 15#include "object-name.h" 16#include "read-cache.h" 17#include "revision.h" 18#include "cache-tree.h" 19#include "unpack-trees.h" 20#include "refs.h" 21#include "repository.h" 22#include "submodule.h" 23#include "symlinks.h" 24#include "trace.h" 25#include "dir.h" 26#include "fsmonitor.h" 27#include "commit-reach.h" 28 29/* 30 * diff-files 31 */ 32 33/* 34 * Has the work tree entity been removed? 35 * 36 * Return 1 if it was removed from the work tree, 0 if an entity to be 37 * compared with the cache entry ce still exists (the latter includes 38 * the case where a directory that is not a submodule repository 39 * exists for ce that is a submodule -- it is a submodule that is not 40 * checked out). Return negative for an error. 41 */ 42static int check_removed(const struct cache_entry *ce, struct stat *st) 43{ 44 int stat_err; 45 46 if (!(ce->ce_flags & CE_FSMONITOR_VALID)) 47 stat_err = lstat(ce->name, st); 48 else 49 stat_err = fake_lstat(ce, st); 50 if (stat_err < 0) { 51 if (!is_missing_file_error(errno)) 52 return -1; 53 return 1; 54 } 55 56 if (has_symlink_leading_path(ce->name, ce_namelen(ce))) 57 return 1; 58 if (S_ISDIR(st->st_mode)) { 59 struct object_id sub; 60 61 /* 62 * If ce is already a gitlink, we can have a plain 63 * directory (i.e. the submodule is not checked out), 64 * or a checked out submodule. Either case this is not 65 * a case where something was removed from the work tree, 66 * so we will return 0. 67 * 68 * Otherwise, if the directory is not a submodule 69 * repository, that means ce which was a blob turned into 70 * a directory --- the blob was removed! 71 */ 72 if (!S_ISGITLINK(ce->ce_mode) && 73 repo_resolve_gitlink_ref(the_repository, ce->name, 74 "HEAD", &sub)) 75 return 1; 76 } 77 return 0; 78} 79 80/* 81 * Has a file changed or has a submodule new commits or a dirty work tree? 82 * 83 * Return 1 when changes are detected, 0 otherwise. If the DIRTY_SUBMODULES 84 * option is set, the caller does not only want to know if a submodule is 85 * modified at all but wants to know all the conditions that are met (new 86 * commits, untracked content and/or modified content). 87 */ 88static int match_stat_with_submodule(struct diff_options *diffopt, 89 const struct cache_entry *ce, 90 struct stat *st, unsigned ce_option, 91 unsigned *dirty_submodule) 92{ 93 int changed = ie_match_stat(diffopt->repo->index, ce, st, ce_option); 94 if (S_ISGITLINK(ce->ce_mode)) { 95 struct diff_flags orig_flags = diffopt->flags; 96 if (!diffopt->flags.override_submodule_config) 97 set_diffopt_flags_from_submodule_config(diffopt, ce->name); 98 if (diffopt->flags.ignore_submodules) 99 changed = 0; 100 else if (!diffopt->flags.ignore_dirty_submodules && 101 (!changed || diffopt->flags.dirty_submodules)) 102 *dirty_submodule = is_submodule_modified(ce->name, 103 diffopt->flags.ignore_untracked_in_submodules); 104 diffopt->flags = orig_flags; 105 } 106 return changed; 107} 108 109void run_diff_files(struct rev_info *revs, unsigned int option) 110{ 111 int entries, i; 112 int diff_unmerged_stage = revs->max_count; 113 unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED) 114 ? CE_MATCH_RACY_IS_DIRTY : 0); 115 uint64_t start = getnanotime(); 116 struct index_state *istate = revs->diffopt.repo->index; 117 118 if (revs->diffopt.max_depth_valid) 119 die(_("max-depth is not supported for worktree diffs")); 120 121 diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/"); 122 123 refresh_fsmonitor(istate); 124 125 if (diff_unmerged_stage < 0) 126 diff_unmerged_stage = 2; 127 entries = istate->cache_nr; 128 for (i = 0; i < entries; i++) { 129 unsigned int oldmode, newmode; 130 struct cache_entry *ce = istate->cache[i]; 131 int changed; 132 unsigned dirty_submodule = 0; 133 const struct object_id *old_oid, *new_oid; 134 135 if (diff_can_quit_early(&revs->diffopt)) 136 break; 137 138 /* 139 * NEEDSWORK: 140 * Here we filter with pathspec but the result is further 141 * filtered out when --relative is in effect. To end-users, 142 * a pathspec element that matched only to paths outside the 143 * current directory is like not matching anything at all; 144 * the handling of ps_matched[] here may become problematic 145 * if/when we add the "--error-unmatch" option to "git diff". 146 */ 147 if (!ce_path_match(istate, ce, &revs->prune_data, revs->ps_matched)) 148 continue; 149 150 if (revs->diffopt.prefix && 151 strncmp(ce->name, revs->diffopt.prefix, revs->diffopt.prefix_length)) 152 continue; 153 154 if (ce_stage(ce)) { 155 struct combine_diff_path *dpath; 156 struct diff_filepair *pair; 157 unsigned int wt_mode = 0; 158 int num_compare_stages = 0; 159 struct stat st; 160 161 changed = check_removed(ce, &st); 162 if (!changed) 163 wt_mode = ce_mode_from_stat(ce, st.st_mode); 164 else { 165 if (changed < 0) { 166 perror(ce->name); 167 continue; 168 } 169 wt_mode = 0; 170 } 171 172 /* 173 * Allocate space for two parents, which will come from 174 * index stages #2 and #3, if present. Below we'll fill 175 * these from (stage - 2). 176 */ 177 dpath = combine_diff_path_new(ce->name, ce_namelen(ce), 178 wt_mode, null_oid(the_hash_algo), 2); 179 180 while (i < entries) { 181 struct cache_entry *nce = istate->cache[i]; 182 int stage; 183 184 if (strcmp(ce->name, nce->name)) 185 break; 186 187 /* Stage #2 (ours) is the first parent, 188 * stage #3 (theirs) is the second. 189 */ 190 stage = ce_stage(nce); 191 if (2 <= stage) { 192 int mode = nce->ce_mode; 193 num_compare_stages++; 194 oidcpy(&dpath->parent[stage - 2].oid, 195 &nce->oid); 196 dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode); 197 dpath->parent[stage-2].status = 198 DIFF_STATUS_MODIFIED; 199 } 200 201 /* diff against the proper unmerged stage */ 202 if (stage == diff_unmerged_stage) 203 ce = nce; 204 i++; 205 } 206 /* 207 * Compensate for loop update 208 */ 209 i--; 210 211 if (revs->combine_merges && num_compare_stages == 2) { 212 show_combined_diff(dpath, 2, revs); 213 free(dpath); 214 continue; 215 } 216 FREE_AND_NULL(dpath); 217 218 /* 219 * Show the diff for the 'ce' if we found the one 220 * from the desired stage. 221 */ 222 pair = diff_unmerge(&revs->diffopt, ce->name); 223 if (wt_mode) 224 pair->two->mode = wt_mode; 225 if (ce_stage(ce) != diff_unmerged_stage) 226 continue; 227 } 228 229 if (ce_uptodate(ce) || ce_skip_worktree(ce)) 230 continue; 231 232 /* 233 * When CE_VALID is set (via "update-index --assume-unchanged" 234 * or via adding paths while core.ignorestat is set to true), 235 * the user has promised that the working tree file for that 236 * path will not be modified. When CE_FSMONITOR_VALID is true, 237 * the fsmonitor knows that the path hasn't been modified since 238 * we refreshed the cached stat information. In either case, 239 * we do not have to stat to see if the path has been removed 240 * or modified. 241 */ 242 if (ce->ce_flags & (CE_VALID | CE_FSMONITOR_VALID)) { 243 changed = 0; 244 newmode = ce->ce_mode; 245 } else { 246 struct stat st; 247 248 changed = check_removed(ce, &st); 249 if (changed) { 250 if (changed < 0) { 251 perror(ce->name); 252 continue; 253 } 254 diff_addremove(&revs->diffopt, '-', ce->ce_mode, 255 &ce->oid, 256 !is_null_oid(&ce->oid), 257 ce->name, 0); 258 continue; 259 } else if (revs->diffopt.ita_invisible_in_index && 260 ce_intent_to_add(ce)) { 261 newmode = ce_mode_from_stat(ce, st.st_mode); 262 diff_addremove(&revs->diffopt, '+', newmode, 263 null_oid(the_hash_algo), 0, ce->name, 0); 264 continue; 265 } 266 267 changed = match_stat_with_submodule(&revs->diffopt, ce, &st, 268 ce_option, &dirty_submodule); 269 newmode = ce_mode_from_stat(ce, st.st_mode); 270 } 271 272 if (!changed && !dirty_submodule) { 273 ce_mark_uptodate(ce); 274 mark_fsmonitor_valid(istate, ce); 275 if (!revs->diffopt.flags.find_copies_harder) 276 continue; 277 } 278 oldmode = ce->ce_mode; 279 old_oid = &ce->oid; 280 new_oid = changed ? null_oid(the_hash_algo) : &ce->oid; 281 diff_change(&revs->diffopt, oldmode, newmode, 282 old_oid, new_oid, 283 !is_null_oid(old_oid), 284 !is_null_oid(new_oid), 285 ce->name, 0, dirty_submodule); 286 287 } 288 diffcore_std(&revs->diffopt); 289 diff_flush(&revs->diffopt); 290 trace_performance_since(start, "diff-files"); 291} 292 293/* 294 * diff-index 295 */ 296 297/* A file entry went away or appeared */ 298static void diff_index_show_file(struct rev_info *revs, 299 const char *prefix, 300 const struct cache_entry *ce, 301 const struct object_id *oid, int oid_valid, 302 unsigned int mode, 303 unsigned dirty_submodule) 304{ 305 diff_addremove(&revs->diffopt, prefix[0], mode, 306 oid, oid_valid, ce->name, dirty_submodule); 307} 308 309static int get_stat_data(const struct cache_entry *ce, 310 const struct object_id **oidp, 311 unsigned int *modep, 312 int cached, int match_missing, 313 unsigned *dirty_submodule, struct diff_options *diffopt) 314{ 315 const struct object_id *oid = &ce->oid; 316 unsigned int mode = ce->ce_mode; 317 318 if (!cached && !ce_uptodate(ce)) { 319 int changed; 320 struct stat st; 321 changed = check_removed(ce, &st); 322 if (changed < 0) 323 return -1; 324 else if (changed) { 325 if (match_missing) { 326 *oidp = oid; 327 *modep = mode; 328 return 0; 329 } 330 return -1; 331 } 332 changed = match_stat_with_submodule(diffopt, ce, &st, 333 0, dirty_submodule); 334 if (changed) { 335 mode = ce_mode_from_stat(ce, st.st_mode); 336 oid = null_oid(the_hash_algo); 337 } 338 } 339 340 *oidp = oid; 341 *modep = mode; 342 return 0; 343} 344 345static void show_new_file(struct rev_info *revs, 346 const struct cache_entry *new_file, 347 int cached, int match_missing) 348{ 349 const struct object_id *oid; 350 unsigned int mode; 351 unsigned dirty_submodule = 0; 352 353 if (new_file && S_ISSPARSEDIR(new_file->ce_mode)) { 354 diff_tree_oid(NULL, &new_file->oid, new_file->name, &revs->diffopt); 355 return; 356 } 357 358 /* 359 * New file in the index: it might actually be different in 360 * the working tree. 361 */ 362 if (get_stat_data(new_file, &oid, &mode, cached, match_missing, 363 &dirty_submodule, &revs->diffopt) < 0) 364 return; 365 366 diff_index_show_file(revs, "+", new_file, oid, !is_null_oid(oid), mode, dirty_submodule); 367} 368 369static int show_modified(struct rev_info *revs, 370 const struct cache_entry *old_entry, 371 const struct cache_entry *new_entry, 372 int report_missing, 373 int cached, int match_missing) 374{ 375 unsigned int mode, oldmode; 376 const struct object_id *oid; 377 unsigned dirty_submodule = 0; 378 379 assert(S_ISSPARSEDIR(old_entry->ce_mode) == 380 S_ISSPARSEDIR(new_entry->ce_mode)); 381 382 /* 383 * If both are sparse directory entries, then expand the 384 * modifications to the file level. If only one was a sparse 385 * directory, then they appear as an add and delete instead of 386 * a modification. 387 */ 388 if (S_ISSPARSEDIR(new_entry->ce_mode)) { 389 diff_tree_oid(&old_entry->oid, &new_entry->oid, new_entry->name, &revs->diffopt); 390 return 0; 391 } 392 393 if (get_stat_data(new_entry, &oid, &mode, cached, match_missing, 394 &dirty_submodule, &revs->diffopt) < 0) { 395 if (report_missing) 396 diff_index_show_file(revs, "-", old_entry, 397 &old_entry->oid, 1, old_entry->ce_mode, 398 0); 399 return -1; 400 } 401 402 if (revs->combine_merges && !cached && 403 (!oideq(oid, &old_entry->oid) || !oideq(&old_entry->oid, &new_entry->oid))) { 404 struct combine_diff_path *p; 405 406 p = combine_diff_path_new(new_entry->name, 407 ce_namelen(new_entry), 408 mode, null_oid(the_hash_algo), 2); 409 p->parent[0].status = DIFF_STATUS_MODIFIED; 410 p->parent[0].mode = new_entry->ce_mode; 411 oidcpy(&p->parent[0].oid, &new_entry->oid); 412 p->parent[1].status = DIFF_STATUS_MODIFIED; 413 p->parent[1].mode = old_entry->ce_mode; 414 oidcpy(&p->parent[1].oid, &old_entry->oid); 415 show_combined_diff(p, 2, revs); 416 free(p); 417 return 0; 418 } 419 420 oldmode = old_entry->ce_mode; 421 if (mode == oldmode && oideq(oid, &old_entry->oid) && !dirty_submodule && 422 !revs->diffopt.flags.find_copies_harder) 423 return 0; 424 425 diff_change(&revs->diffopt, oldmode, mode, 426 &old_entry->oid, oid, 1, !is_null_oid(oid), 427 old_entry->name, 0, dirty_submodule); 428 return 0; 429} 430 431/* 432 * This gets a mix of an existing index and a tree, one pathname entry 433 * at a time. The index entry may be a single stage-0 one, but it could 434 * also be multiple unmerged entries (in which case idx_pos/idx_nr will 435 * give you the position and number of entries in the index). 436 */ 437static void do_oneway_diff(struct unpack_trees_options *o, 438 const struct cache_entry *idx, 439 const struct cache_entry *tree) 440{ 441 struct rev_info *revs = o->unpack_data; 442 int match_missing, cached; 443 444 /* 445 * i-t-a entries do not actually exist in the index (if we're 446 * looking at its content) 447 */ 448 if (o->index_only && 449 revs->diffopt.ita_invisible_in_index && 450 idx && ce_intent_to_add(idx)) { 451 idx = NULL; 452 if (!tree) 453 return; /* nothing to diff.. */ 454 } 455 456 /* if the entry is not checked out, don't examine work tree */ 457 cached = o->index_only || 458 (idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx))); 459 460 match_missing = revs->match_missing; 461 462 if (cached && idx && ce_stage(idx)) { 463 struct diff_filepair *pair; 464 pair = diff_unmerge(&revs->diffopt, idx->name); 465 if (tree) 466 fill_filespec(pair->one, &tree->oid, 1, 467 tree->ce_mode); 468 return; 469 } 470 471 /* 472 * Something added to the tree? 473 */ 474 if (!tree) { 475 show_new_file(revs, idx, cached, match_missing); 476 return; 477 } 478 479 /* 480 * Something removed from the tree? 481 */ 482 if (!idx) { 483 if (S_ISSPARSEDIR(tree->ce_mode)) { 484 diff_tree_oid(&tree->oid, NULL, tree->name, &revs->diffopt); 485 return; 486 } 487 488 diff_index_show_file(revs, "-", tree, &tree->oid, 1, 489 tree->ce_mode, 0); 490 return; 491 } 492 493 /* Show difference between old and new */ 494 show_modified(revs, tree, idx, 1, cached, match_missing); 495} 496 497/* 498 * The unpack_trees() interface is designed for merging, so 499 * the different source entries are designed primarily for 500 * the source trees, with the old index being really mainly 501 * used for being replaced by the result. 502 * 503 * For diffing, the index is more important, and we only have a 504 * single tree. 505 * 506 * We're supposed to advance o->pos to skip what we have already processed. 507 * 508 * This wrapper makes it all more readable, and takes care of all 509 * the fairly complex unpack_trees() semantic requirements, including 510 * the skipping, the path matching, the type conflict cases etc. 511 */ 512static int oneway_diff(const struct cache_entry * const *src, 513 struct unpack_trees_options *o) 514{ 515 const struct cache_entry *idx = src[0]; 516 const struct cache_entry *tree = src[1]; 517 struct rev_info *revs = o->unpack_data; 518 519 /* 520 * Unpack-trees generates a DF/conflict entry if 521 * there was a directory in the index and a tree 522 * in the tree. From a diff standpoint, that's a 523 * delete of the tree and a create of the file. 524 */ 525 if (tree == o->df_conflict_entry) 526 tree = NULL; 527 528 if (ce_path_match(revs->diffopt.repo->index, 529 idx ? idx : tree, 530 &revs->prune_data, NULL)) { 531 do_oneway_diff(o, idx, tree); 532 if (diff_can_quit_early(&revs->diffopt)) { 533 o->exiting_early = 1; 534 return -1; 535 } 536 } 537 538 return 0; 539} 540 541static int diff_cache(struct rev_info *revs, 542 const struct object_id *tree_oid, 543 const char *tree_name, 544 int cached) 545{ 546 struct tree *tree; 547 struct tree_desc t; 548 struct unpack_trees_options opts; 549 550 tree = parse_tree_indirect(tree_oid); 551 if (!tree) 552 return error("bad tree object %s", 553 tree_name ? tree_name : oid_to_hex(tree_oid)); 554 memset(&opts, 0, sizeof(opts)); 555 opts.head_idx = 1; 556 opts.index_only = cached; 557 opts.diff_index_cached = (cached && 558 !revs->diffopt.flags.find_copies_harder); 559 opts.merge = 1; 560 opts.fn = oneway_diff; 561 opts.unpack_data = revs; 562 opts.src_index = revs->diffopt.repo->index; 563 opts.dst_index = NULL; 564 opts.pathspec = &revs->diffopt.pathspec; 565 opts.pathspec->recursive = 1; 566 if (revs->diffopt.max_depth_valid) 567 die(_("max-depth is not supported for index diffs")); 568 569 init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size); 570 return unpack_trees(1, &t, &opts); 571} 572 573void diff_get_merge_base(const struct rev_info *revs, struct object_id *mb) 574{ 575 int i; 576 struct commit *mb_child[2] = {0}; 577 struct commit_list *merge_bases = NULL; 578 579 for (i = 0; i < revs->pending.nr; i++) { 580 struct object *obj = revs->pending.objects[i].item; 581 if (obj->flags) 582 die(_("--merge-base does not work with ranges")); 583 } 584 585 /* 586 * This check must go after the for loop above because A...B 587 * ranges produce three pending commits, resulting in a 588 * misleading error message. 589 */ 590 if (revs->pending.nr < 1 || revs->pending.nr > 2) 591 BUG("unexpected revs->pending.nr: %d", revs->pending.nr); 592 593 for (i = 0; i < revs->pending.nr; i++) 594 mb_child[i] = lookup_commit_reference(the_repository, &revs->pending.objects[i].item->oid); 595 if (revs->pending.nr == 1) { 596 struct object_id oid; 597 598 if (repo_get_oid(the_repository, "HEAD", &oid)) 599 die(_("unable to get HEAD")); 600 601 mb_child[1] = lookup_commit_reference(the_repository, &oid); 602 } 603 604 if (repo_get_merge_bases(the_repository, mb_child[0], mb_child[1], &merge_bases) < 0) 605 exit(128); 606 if (!merge_bases) 607 die(_("no merge base found")); 608 if (merge_bases->next) 609 die(_("multiple merge bases found")); 610 611 oidcpy(mb, &merge_bases->item->object.oid); 612 613 free_commit_list(merge_bases); 614} 615 616void run_diff_index(struct rev_info *revs, unsigned int option) 617{ 618 struct object_array_entry *ent; 619 int cached = !!(option & DIFF_INDEX_CACHED); 620 int merge_base = !!(option & DIFF_INDEX_MERGE_BASE); 621 struct object_id oid; 622 const char *name; 623 char merge_base_hex[GIT_MAX_HEXSZ + 1]; 624 struct index_state *istate = revs->diffopt.repo->index; 625 626 if (revs->pending.nr != 1) 627 BUG("run_diff_index must be passed exactly one tree"); 628 629 trace_performance_enter(); 630 ent = revs->pending.objects; 631 632 refresh_fsmonitor(istate); 633 634 if (merge_base) { 635 diff_get_merge_base(revs, &oid); 636 name = oid_to_hex_r(merge_base_hex, &oid); 637 } else { 638 oidcpy(&oid, &ent->item->oid); 639 name = ent->name; 640 } 641 642 if (diff_cache(revs, &oid, name, cached)) 643 exit(128); 644 645 diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/"); 646 diffcore_fix_diff_index(); 647 diffcore_std(&revs->diffopt); 648 diff_flush(&revs->diffopt); 649 trace_performance_leave("diff-index"); 650} 651 652int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt) 653{ 654 struct rev_info revs; 655 656 repo_init_revisions(opt->repo, &revs, NULL); 657 copy_pathspec(&revs.prune_data, &opt->pathspec); 658 diff_free(&revs.diffopt); 659 revs.diffopt = *opt; 660 revs.diffopt.no_free = 1; 661 662 if (diff_cache(&revs, tree_oid, NULL, 1)) 663 exit(128); 664 665 release_revisions(&revs); 666 return 0; 667} 668 669int index_differs_from(struct repository *r, 670 const char *def, const struct diff_flags *flags, 671 int ita_invisible_in_index) 672{ 673 struct rev_info rev; 674 struct setup_revision_opt opt; 675 unsigned has_changes; 676 677 repo_init_revisions(r, &rev, NULL); 678 memset(&opt, 0, sizeof(opt)); 679 opt.def = def; 680 setup_revisions(0, NULL, &rev, &opt); 681 rev.diffopt.flags.quick = 1; 682 rev.diffopt.flags.exit_with_status = 1; 683 if (flags) { 684 diff_flags_or(&rev.diffopt.flags, flags); 685 /* 686 * Now that flags are merged, honor override_submodule_config 687 * and ignore_submodules from passed flags. 688 */ 689 if (flags->override_submodule_config) 690 rev.diffopt.flags.ignore_submodules = flags->ignore_submodules; 691 } 692 rev.diffopt.ita_invisible_in_index = ita_invisible_in_index; 693 run_diff_index(&rev, DIFF_INDEX_CACHED); 694 has_changes = rev.diffopt.flags.has_changes; 695 release_revisions(&rev); 696 return (has_changes != 0); 697} 698 699static const char *idiff_prefix_cb(struct diff_options *opt UNUSED, void *data) 700{ 701 return data; 702} 703 704void show_interdiff(const struct object_id *oid1, const struct object_id *oid2, 705 int indent, struct diff_options *diffopt) 706{ 707 struct diff_options opts; 708 struct strbuf prefix = STRBUF_INIT; 709 710 memcpy(&opts, diffopt, sizeof(opts)); 711 opts.output_format = DIFF_FORMAT_PATCH; 712 opts.output_prefix = idiff_prefix_cb; 713 strbuf_addchars(&prefix, ' ', indent); 714 opts.output_prefix_data = prefix.buf; 715 diff_setup_done(&opts); 716 717 diff_tree_oid(oid1, oid2, "", &opts); 718 diffcore_std(&opts); 719 diff_flush(&opts); 720 721 strbuf_release(&prefix); 722}