PageRenderTime 27ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/git-source/diff-lib.c

https://bitbucket.org/b0dz1o/git-kata-registration
C | 527 lines | 373 code | 58 blank | 96 comment | 77 complexity | bba62608ee2508702331563c06f6defb MD5 | raw file
  1. /*
  2. * Copyright (C) 2005 Junio C Hamano
  3. */
  4. #include "cache.h"
  5. #include "quote.h"
  6. #include "commit.h"
  7. #include "diff.h"
  8. #include "diffcore.h"
  9. #include "revision.h"
  10. #include "cache-tree.h"
  11. #include "unpack-trees.h"
  12. #include "refs.h"
  13. #include "submodule.h"
  14. /*
  15. * diff-files
  16. */
  17. /*
  18. * Has the work tree entity been removed?
  19. *
  20. * Return 1 if it was removed from the work tree, 0 if an entity to be
  21. * compared with the cache entry ce still exists (the latter includes
  22. * the case where a directory that is not a submodule repository
  23. * exists for ce that is a submodule -- it is a submodule that is not
  24. * checked out). Return negative for an error.
  25. */
  26. static int check_removed(const struct cache_entry *ce, struct stat *st)
  27. {
  28. if (lstat(ce->name, st) < 0) {
  29. if (errno != ENOENT && errno != ENOTDIR)
  30. return -1;
  31. return 1;
  32. }
  33. if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
  34. return 1;
  35. if (S_ISDIR(st->st_mode)) {
  36. unsigned char sub[20];
  37. /*
  38. * If ce is already a gitlink, we can have a plain
  39. * directory (i.e. the submodule is not checked out),
  40. * or a checked out submodule. Either case this is not
  41. * a case where something was removed from the work tree,
  42. * so we will return 0.
  43. *
  44. * Otherwise, if the directory is not a submodule
  45. * repository, that means ce which was a blob turned into
  46. * a directory --- the blob was removed!
  47. */
  48. if (!S_ISGITLINK(ce->ce_mode) &&
  49. resolve_gitlink_ref(ce->name, "HEAD", sub))
  50. return 1;
  51. }
  52. return 0;
  53. }
  54. /*
  55. * Has a file changed or has a submodule new commits or a dirty work tree?
  56. *
  57. * Return 1 when changes are detected, 0 otherwise. If the DIRTY_SUBMODULES
  58. * option is set, the caller does not only want to know if a submodule is
  59. * modified at all but wants to know all the conditions that are met (new
  60. * commits, untracked content and/or modified content).
  61. */
  62. static int match_stat_with_submodule(struct diff_options *diffopt,
  63. struct cache_entry *ce, struct stat *st,
  64. unsigned ce_option, unsigned *dirty_submodule)
  65. {
  66. int changed = ce_match_stat(ce, st, ce_option);
  67. if (S_ISGITLINK(ce->ce_mode)) {
  68. unsigned orig_flags = diffopt->flags;
  69. if (!DIFF_OPT_TST(diffopt, OVERRIDE_SUBMODULE_CONFIG))
  70. set_diffopt_flags_from_submodule_config(diffopt, ce->name);
  71. if (DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES))
  72. changed = 0;
  73. else if (!DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)
  74. && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES)))
  75. *dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));
  76. diffopt->flags = orig_flags;
  77. }
  78. return changed;
  79. }
  80. int run_diff_files(struct rev_info *revs, unsigned int option)
  81. {
  82. int entries, i;
  83. int diff_unmerged_stage = revs->max_count;
  84. int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
  85. unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
  86. ? CE_MATCH_RACY_IS_DIRTY : 0);
  87. diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
  88. if (diff_unmerged_stage < 0)
  89. diff_unmerged_stage = 2;
  90. entries = active_nr;
  91. for (i = 0; i < entries; i++) {
  92. struct stat st;
  93. unsigned int oldmode, newmode;
  94. struct cache_entry *ce = active_cache[i];
  95. int changed;
  96. unsigned dirty_submodule = 0;
  97. if (diff_can_quit_early(&revs->diffopt))
  98. break;
  99. if (!ce_path_match(ce, &revs->prune_data))
  100. continue;
  101. if (ce_stage(ce)) {
  102. struct combine_diff_path *dpath;
  103. struct diff_filepair *pair;
  104. unsigned int wt_mode = 0;
  105. int num_compare_stages = 0;
  106. size_t path_len;
  107. path_len = ce_namelen(ce);
  108. dpath = xmalloc(combine_diff_path_size(5, path_len));
  109. dpath->path = (char *) &(dpath->parent[5]);
  110. dpath->next = NULL;
  111. dpath->len = path_len;
  112. memcpy(dpath->path, ce->name, path_len);
  113. dpath->path[path_len] = '\0';
  114. hashclr(dpath->sha1);
  115. memset(&(dpath->parent[0]), 0,
  116. sizeof(struct combine_diff_parent)*5);
  117. changed = check_removed(ce, &st);
  118. if (!changed)
  119. wt_mode = ce_mode_from_stat(ce, st.st_mode);
  120. else {
  121. if (changed < 0) {
  122. perror(ce->name);
  123. continue;
  124. }
  125. if (silent_on_removed)
  126. continue;
  127. wt_mode = 0;
  128. }
  129. dpath->mode = wt_mode;
  130. while (i < entries) {
  131. struct cache_entry *nce = active_cache[i];
  132. int stage;
  133. if (strcmp(ce->name, nce->name))
  134. break;
  135. /* Stage #2 (ours) is the first parent,
  136. * stage #3 (theirs) is the second.
  137. */
  138. stage = ce_stage(nce);
  139. if (2 <= stage) {
  140. int mode = nce->ce_mode;
  141. num_compare_stages++;
  142. hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
  143. dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);
  144. dpath->parent[stage-2].status =
  145. DIFF_STATUS_MODIFIED;
  146. }
  147. /* diff against the proper unmerged stage */
  148. if (stage == diff_unmerged_stage)
  149. ce = nce;
  150. i++;
  151. }
  152. /*
  153. * Compensate for loop update
  154. */
  155. i--;
  156. if (revs->combine_merges && num_compare_stages == 2) {
  157. show_combined_diff(dpath, 2,
  158. revs->dense_combined_merges,
  159. revs);
  160. free(dpath);
  161. continue;
  162. }
  163. free(dpath);
  164. dpath = NULL;
  165. /*
  166. * Show the diff for the 'ce' if we found the one
  167. * from the desired stage.
  168. */
  169. pair = diff_unmerge(&revs->diffopt, ce->name);
  170. if (wt_mode)
  171. pair->two->mode = wt_mode;
  172. if (ce_stage(ce) != diff_unmerged_stage)
  173. continue;
  174. }
  175. if (ce_uptodate(ce) || ce_skip_worktree(ce))
  176. continue;
  177. /* If CE_VALID is set, don't look at workdir for file removal */
  178. changed = (ce->ce_flags & CE_VALID) ? 0 : check_removed(ce, &st);
  179. if (changed) {
  180. if (changed < 0) {
  181. perror(ce->name);
  182. continue;
  183. }
  184. if (silent_on_removed)
  185. continue;
  186. diff_addremove(&revs->diffopt, '-', ce->ce_mode,
  187. ce->sha1, !is_null_sha1(ce->sha1),
  188. ce->name, 0);
  189. continue;
  190. }
  191. changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
  192. ce_option, &dirty_submodule);
  193. if (!changed && !dirty_submodule) {
  194. ce_mark_uptodate(ce);
  195. if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
  196. continue;
  197. }
  198. oldmode = ce->ce_mode;
  199. newmode = ce_mode_from_stat(ce, st.st_mode);
  200. diff_change(&revs->diffopt, oldmode, newmode,
  201. ce->sha1, (changed ? null_sha1 : ce->sha1),
  202. !is_null_sha1(ce->sha1), (changed ? 0 : !is_null_sha1(ce->sha1)),
  203. ce->name, 0, dirty_submodule);
  204. }
  205. diffcore_std(&revs->diffopt);
  206. diff_flush(&revs->diffopt);
  207. return 0;
  208. }
  209. /*
  210. * diff-index
  211. */
  212. /* A file entry went away or appeared */
  213. static void diff_index_show_file(struct rev_info *revs,
  214. const char *prefix,
  215. struct cache_entry *ce,
  216. const unsigned char *sha1, int sha1_valid,
  217. unsigned int mode,
  218. unsigned dirty_submodule)
  219. {
  220. diff_addremove(&revs->diffopt, prefix[0], mode,
  221. sha1, sha1_valid, ce->name, dirty_submodule);
  222. }
  223. static int get_stat_data(struct cache_entry *ce,
  224. const unsigned char **sha1p,
  225. unsigned int *modep,
  226. int cached, int match_missing,
  227. unsigned *dirty_submodule, struct diff_options *diffopt)
  228. {
  229. const unsigned char *sha1 = ce->sha1;
  230. unsigned int mode = ce->ce_mode;
  231. if (!cached && !ce_uptodate(ce)) {
  232. int changed;
  233. struct stat st;
  234. changed = check_removed(ce, &st);
  235. if (changed < 0)
  236. return -1;
  237. else if (changed) {
  238. if (match_missing) {
  239. *sha1p = sha1;
  240. *modep = mode;
  241. return 0;
  242. }
  243. return -1;
  244. }
  245. changed = match_stat_with_submodule(diffopt, ce, &st,
  246. 0, dirty_submodule);
  247. if (changed) {
  248. mode = ce_mode_from_stat(ce, st.st_mode);
  249. sha1 = null_sha1;
  250. }
  251. }
  252. *sha1p = sha1;
  253. *modep = mode;
  254. return 0;
  255. }
  256. static void show_new_file(struct rev_info *revs,
  257. struct cache_entry *new,
  258. int cached, int match_missing)
  259. {
  260. const unsigned char *sha1;
  261. unsigned int mode;
  262. unsigned dirty_submodule = 0;
  263. /*
  264. * New file in the index: it might actually be different in
  265. * the working tree.
  266. */
  267. if (get_stat_data(new, &sha1, &mode, cached, match_missing,
  268. &dirty_submodule, &revs->diffopt) < 0)
  269. return;
  270. diff_index_show_file(revs, "+", new, sha1, !is_null_sha1(sha1), mode, dirty_submodule);
  271. }
  272. static int show_modified(struct rev_info *revs,
  273. struct cache_entry *old,
  274. struct cache_entry *new,
  275. int report_missing,
  276. int cached, int match_missing)
  277. {
  278. unsigned int mode, oldmode;
  279. const unsigned char *sha1;
  280. unsigned dirty_submodule = 0;
  281. if (get_stat_data(new, &sha1, &mode, cached, match_missing,
  282. &dirty_submodule, &revs->diffopt) < 0) {
  283. if (report_missing)
  284. diff_index_show_file(revs, "-", old,
  285. old->sha1, 1, old->ce_mode, 0);
  286. return -1;
  287. }
  288. if (revs->combine_merges && !cached &&
  289. (hashcmp(sha1, old->sha1) || hashcmp(old->sha1, new->sha1))) {
  290. struct combine_diff_path *p;
  291. int pathlen = ce_namelen(new);
  292. p = xmalloc(combine_diff_path_size(2, pathlen));
  293. p->path = (char *) &p->parent[2];
  294. p->next = NULL;
  295. p->len = pathlen;
  296. memcpy(p->path, new->name, pathlen);
  297. p->path[pathlen] = 0;
  298. p->mode = mode;
  299. hashclr(p->sha1);
  300. memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent));
  301. p->parent[0].status = DIFF_STATUS_MODIFIED;
  302. p->parent[0].mode = new->ce_mode;
  303. hashcpy(p->parent[0].sha1, new->sha1);
  304. p->parent[1].status = DIFF_STATUS_MODIFIED;
  305. p->parent[1].mode = old->ce_mode;
  306. hashcpy(p->parent[1].sha1, old->sha1);
  307. show_combined_diff(p, 2, revs->dense_combined_merges, revs);
  308. free(p);
  309. return 0;
  310. }
  311. oldmode = old->ce_mode;
  312. if (mode == oldmode && !hashcmp(sha1, old->sha1) && !dirty_submodule &&
  313. !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
  314. return 0;
  315. diff_change(&revs->diffopt, oldmode, mode,
  316. old->sha1, sha1, 1, !is_null_sha1(sha1),
  317. old->name, 0, dirty_submodule);
  318. return 0;
  319. }
  320. /*
  321. * This gets a mix of an existing index and a tree, one pathname entry
  322. * at a time. The index entry may be a single stage-0 one, but it could
  323. * also be multiple unmerged entries (in which case idx_pos/idx_nr will
  324. * give you the position and number of entries in the index).
  325. */
  326. static void do_oneway_diff(struct unpack_trees_options *o,
  327. struct cache_entry *idx,
  328. struct cache_entry *tree)
  329. {
  330. struct rev_info *revs = o->unpack_data;
  331. int match_missing, cached;
  332. /* if the entry is not checked out, don't examine work tree */
  333. cached = o->index_only ||
  334. (idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx)));
  335. /*
  336. * Backward compatibility wart - "diff-index -m" does
  337. * not mean "do not ignore merges", but "match_missing".
  338. *
  339. * But with the revision flag parsing, that's found in
  340. * "!revs->ignore_merges".
  341. */
  342. match_missing = !revs->ignore_merges;
  343. if (cached && idx && ce_stage(idx)) {
  344. struct diff_filepair *pair;
  345. pair = diff_unmerge(&revs->diffopt, idx->name);
  346. if (tree)
  347. fill_filespec(pair->one, tree->sha1, 1, tree->ce_mode);
  348. return;
  349. }
  350. /*
  351. * Something added to the tree?
  352. */
  353. if (!tree) {
  354. show_new_file(revs, idx, cached, match_missing);
  355. return;
  356. }
  357. /*
  358. * Something removed from the tree?
  359. */
  360. if (!idx) {
  361. diff_index_show_file(revs, "-", tree, tree->sha1, 1, tree->ce_mode, 0);
  362. return;
  363. }
  364. /* Show difference between old and new */
  365. show_modified(revs, tree, idx, 1, cached, match_missing);
  366. }
  367. /*
  368. * The unpack_trees() interface is designed for merging, so
  369. * the different source entries are designed primarily for
  370. * the source trees, with the old index being really mainly
  371. * used for being replaced by the result.
  372. *
  373. * For diffing, the index is more important, and we only have a
  374. * single tree.
  375. *
  376. * We're supposed to advance o->pos to skip what we have already processed.
  377. *
  378. * This wrapper makes it all more readable, and takes care of all
  379. * the fairly complex unpack_trees() semantic requirements, including
  380. * the skipping, the path matching, the type conflict cases etc.
  381. */
  382. static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
  383. {
  384. struct cache_entry *idx = src[0];
  385. struct cache_entry *tree = src[1];
  386. struct rev_info *revs = o->unpack_data;
  387. /*
  388. * Unpack-trees generates a DF/conflict entry if
  389. * there was a directory in the index and a tree
  390. * in the tree. From a diff standpoint, that's a
  391. * delete of the tree and a create of the file.
  392. */
  393. if (tree == o->df_conflict_entry)
  394. tree = NULL;
  395. if (ce_path_match(idx ? idx : tree, &revs->prune_data)) {
  396. do_oneway_diff(o, idx, tree);
  397. if (diff_can_quit_early(&revs->diffopt)) {
  398. o->exiting_early = 1;
  399. return -1;
  400. }
  401. }
  402. return 0;
  403. }
  404. static int diff_cache(struct rev_info *revs,
  405. const unsigned char *tree_sha1,
  406. const char *tree_name,
  407. int cached)
  408. {
  409. struct tree *tree;
  410. struct tree_desc t;
  411. struct unpack_trees_options opts;
  412. tree = parse_tree_indirect(tree_sha1);
  413. if (!tree)
  414. return error("bad tree object %s",
  415. tree_name ? tree_name : sha1_to_hex(tree_sha1));
  416. memset(&opts, 0, sizeof(opts));
  417. opts.head_idx = 1;
  418. opts.index_only = cached;
  419. opts.diff_index_cached = (cached &&
  420. !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER));
  421. opts.merge = 1;
  422. opts.fn = oneway_diff;
  423. opts.unpack_data = revs;
  424. opts.src_index = &the_index;
  425. opts.dst_index = NULL;
  426. opts.pathspec = &revs->diffopt.pathspec;
  427. opts.pathspec->recursive = 1;
  428. opts.pathspec->max_depth = -1;
  429. init_tree_desc(&t, tree->buffer, tree->size);
  430. return unpack_trees(1, &t, &opts);
  431. }
  432. int run_diff_index(struct rev_info *revs, int cached)
  433. {
  434. struct object_array_entry *ent;
  435. ent = revs->pending.objects;
  436. if (diff_cache(revs, ent->item->sha1, ent->name, cached))
  437. exit(128);
  438. diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/");
  439. diffcore_fix_diff_index(&revs->diffopt);
  440. diffcore_std(&revs->diffopt);
  441. diff_flush(&revs->diffopt);
  442. return 0;
  443. }
  444. int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
  445. {
  446. struct rev_info revs;
  447. init_revisions(&revs, NULL);
  448. init_pathspec(&revs.prune_data, opt->pathspec.raw);
  449. revs.diffopt = *opt;
  450. if (diff_cache(&revs, tree_sha1, NULL, 1))
  451. exit(128);
  452. return 0;
  453. }
  454. int index_differs_from(const char *def, int diff_flags)
  455. {
  456. struct rev_info rev;
  457. struct setup_revision_opt opt;
  458. init_revisions(&rev, NULL);
  459. memset(&opt, 0, sizeof(opt));
  460. opt.def = def;
  461. setup_revisions(0, NULL, &rev, &opt);
  462. DIFF_OPT_SET(&rev.diffopt, QUICK);
  463. DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
  464. rev.diffopt.flags |= diff_flags;
  465. run_diff_index(&rev, 1);
  466. if (rev.pending.alloc)
  467. free(rev.pending.objects);
  468. return (DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0);
  469. }