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