diff-lib: accept option flags in run_diff_index()
[git] / builtin / diff.c
1 /*
2  * Builtin "git diff"
3  *
4  * Copyright (c) 2006 Junio C Hamano
5  */
6 #define USE_THE_INDEX_COMPATIBILITY_MACROS
7 #include "cache.h"
8 #include "config.h"
9 #include "ewah/ewok.h"
10 #include "lockfile.h"
11 #include "color.h"
12 #include "commit.h"
13 #include "blob.h"
14 #include "tag.h"
15 #include "diff.h"
16 #include "diffcore.h"
17 #include "revision.h"
18 #include "log-tree.h"
19 #include "builtin.h"
20 #include "submodule.h"
21 #include "oid-array.h"
22
23 #define DIFF_NO_INDEX_EXPLICIT 1
24 #define DIFF_NO_INDEX_IMPLICIT 2
25
26 static const char builtin_diff_usage[] =
27 "git diff [<options>] [<commit>] [--] [<path>...]\n"
28 "   or: git diff [<options>] --cached [<commit>] [--] [<path>...]\n"
29 "   or: git diff [<options>] <commit> [<commit>...] <commit> [--] [<path>...]\n"
30 "   or: git diff [<options>] <commit>...<commit>] [--] [<path>...]\n"
31 "   or: git diff [<options>] <blob> <blob>]\n"
32 "   or: git diff [<options>] --no-index [--] <path> <path>]\n"
33 COMMON_DIFF_OPTIONS_HELP;
34
35 static const char *blob_path(struct object_array_entry *entry)
36 {
37         return entry->path ? entry->path : entry->name;
38 }
39
40 static void stuff_change(struct diff_options *opt,
41                          unsigned old_mode, unsigned new_mode,
42                          const struct object_id *old_oid,
43                          const struct object_id *new_oid,
44                          int old_oid_valid,
45                          int new_oid_valid,
46                          const char *old_path,
47                          const char *new_path)
48 {
49         struct diff_filespec *one, *two;
50
51         if (!is_null_oid(old_oid) && !is_null_oid(new_oid) &&
52             oideq(old_oid, new_oid) && (old_mode == new_mode))
53                 return;
54
55         if (opt->flags.reverse_diff) {
56                 SWAP(old_mode, new_mode);
57                 SWAP(old_oid, new_oid);
58                 SWAP(old_path, new_path);
59         }
60
61         if (opt->prefix &&
62             (strncmp(old_path, opt->prefix, opt->prefix_length) ||
63              strncmp(new_path, opt->prefix, opt->prefix_length)))
64                 return;
65
66         one = alloc_filespec(old_path);
67         two = alloc_filespec(new_path);
68         fill_filespec(one, old_oid, old_oid_valid, old_mode);
69         fill_filespec(two, new_oid, new_oid_valid, new_mode);
70
71         diff_queue(&diff_queued_diff, one, two);
72 }
73
74 static int builtin_diff_b_f(struct rev_info *revs,
75                             int argc, const char **argv,
76                             struct object_array_entry **blob)
77 {
78         /* Blob vs file in the working tree*/
79         struct stat st;
80         const char *path;
81
82         if (argc > 1)
83                 usage(builtin_diff_usage);
84
85         GUARD_PATHSPEC(&revs->prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
86         path = revs->prune_data.items[0].match;
87
88         if (lstat(path, &st))
89                 die_errno(_("failed to stat '%s'"), path);
90         if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
91                 die(_("'%s': not a regular file or symlink"), path);
92
93         diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/");
94
95         if (blob[0]->mode == S_IFINVALID)
96                 blob[0]->mode = canon_mode(st.st_mode);
97
98         stuff_change(&revs->diffopt,
99                      blob[0]->mode, canon_mode(st.st_mode),
100                      &blob[0]->item->oid, &null_oid,
101                      1, 0,
102                      blob[0]->path ? blob[0]->path : path,
103                      path);
104         diffcore_std(&revs->diffopt);
105         diff_flush(&revs->diffopt);
106         return 0;
107 }
108
109 static int builtin_diff_blobs(struct rev_info *revs,
110                               int argc, const char **argv,
111                               struct object_array_entry **blob)
112 {
113         const unsigned mode = canon_mode(S_IFREG | 0644);
114
115         if (argc > 1)
116                 usage(builtin_diff_usage);
117
118         if (blob[0]->mode == S_IFINVALID)
119                 blob[0]->mode = mode;
120
121         if (blob[1]->mode == S_IFINVALID)
122                 blob[1]->mode = mode;
123
124         stuff_change(&revs->diffopt,
125                      blob[0]->mode, blob[1]->mode,
126                      &blob[0]->item->oid, &blob[1]->item->oid,
127                      1, 1,
128                      blob_path(blob[0]), blob_path(blob[1]));
129         diffcore_std(&revs->diffopt);
130         diff_flush(&revs->diffopt);
131         return 0;
132 }
133
134 static int builtin_diff_index(struct rev_info *revs,
135                               int argc, const char **argv)
136 {
137         unsigned int option = 0;
138         while (1 < argc) {
139                 const char *arg = argv[1];
140                 if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged"))
141                         option |= DIFF_INDEX_CACHED;
142                 else
143                         usage(builtin_diff_usage);
144                 argv++; argc--;
145         }
146         /*
147          * Make sure there is one revision (i.e. pending object),
148          * and there is no revision filtering parameters.
149          */
150         if (revs->pending.nr != 1 ||
151             revs->max_count != -1 || revs->min_age != -1 ||
152             revs->max_age != -1)
153                 usage(builtin_diff_usage);
154         if (!(option & DIFF_INDEX_CACHED)) {
155                 setup_work_tree();
156                 if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
157                         perror("read_cache_preload");
158                         return -1;
159                 }
160         } else if (read_cache() < 0) {
161                 perror("read_cache");
162                 return -1;
163         }
164         return run_diff_index(revs, option);
165 }
166
167 static int builtin_diff_tree(struct rev_info *revs,
168                              int argc, const char **argv,
169                              struct object_array_entry *ent0,
170                              struct object_array_entry *ent1)
171 {
172         const struct object_id *(oid[2]);
173         int swap = 0;
174
175         if (argc > 1)
176                 usage(builtin_diff_usage);
177
178         /*
179          * We saw two trees, ent0 and ent1.  If ent1 is uninteresting,
180          * swap them.
181          */
182         if (ent1->item->flags & UNINTERESTING)
183                 swap = 1;
184         oid[swap] = &ent0->item->oid;
185         oid[1 - swap] = &ent1->item->oid;
186         diff_tree_oid(oid[0], oid[1], "", &revs->diffopt);
187         log_tree_diff_flush(revs);
188         return 0;
189 }
190
191 static int builtin_diff_combined(struct rev_info *revs,
192                                  int argc, const char **argv,
193                                  struct object_array_entry *ent,
194                                  int ents)
195 {
196         struct oid_array parents = OID_ARRAY_INIT;
197         int i;
198
199         if (argc > 1)
200                 usage(builtin_diff_usage);
201
202         if (!revs->dense_combined_merges && !revs->combine_merges)
203                 revs->dense_combined_merges = revs->combine_merges = 1;
204         for (i = 1; i < ents; i++)
205                 oid_array_append(&parents, &ent[i].item->oid);
206         diff_tree_combined(&ent[0].item->oid, &parents,
207                            revs->dense_combined_merges, revs);
208         oid_array_clear(&parents);
209         return 0;
210 }
211
212 static void refresh_index_quietly(void)
213 {
214         struct lock_file lock_file = LOCK_INIT;
215         int fd;
216
217         fd = hold_locked_index(&lock_file, 0);
218         if (fd < 0)
219                 return;
220         discard_cache();
221         read_cache();
222         refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
223         repo_update_index_if_able(the_repository, &lock_file);
224 }
225
226 static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
227 {
228         unsigned int options = 0;
229
230         while (1 < argc && argv[1][0] == '-') {
231                 if (!strcmp(argv[1], "--base"))
232                         revs->max_count = 1;
233                 else if (!strcmp(argv[1], "--ours"))
234                         revs->max_count = 2;
235                 else if (!strcmp(argv[1], "--theirs"))
236                         revs->max_count = 3;
237                 else if (!strcmp(argv[1], "-q"))
238                         options |= DIFF_SILENT_ON_REMOVED;
239                 else if (!strcmp(argv[1], "-h"))
240                         usage(builtin_diff_usage);
241                 else
242                         return error(_("invalid option: %s"), argv[1]);
243                 argv++; argc--;
244         }
245
246         /*
247          * "diff --base" should not combine merges because it was not
248          * asked to.  "diff -c" should not densify (if the user wants
249          * dense one, --cc can be explicitly asked for, or just rely
250          * on the default).
251          */
252         if (revs->max_count == -1 && !revs->combine_merges &&
253             (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
254                 revs->combine_merges = revs->dense_combined_merges = 1;
255
256         setup_work_tree();
257         if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
258                 perror("read_cache_preload");
259                 return -1;
260         }
261         return run_diff_files(revs, options);
262 }
263
264 struct symdiff {
265         struct bitmap *skip;
266         int warn;
267         const char *base, *left, *right;
268 };
269
270 /*
271  * Check for symmetric-difference arguments, and if present, arrange
272  * everything we need to know to handle them correctly.  As a bonus,
273  * weed out all bogus range-based revision specifications, e.g.,
274  * "git diff A..B C..D" or "git diff A..B C" get rejected.
275  *
276  * For an actual symmetric diff, *symdiff is set this way:
277  *
278  *  - its skip is non-NULL and marks *all* rev->pending.objects[i]
279  *    indices that the caller should ignore (extra merge bases, of
280  *    which there might be many, and A in A...B).  Note that the
281  *    chosen merge base and right side are NOT marked.
282  *  - warn is set if there are multiple merge bases.
283  *  - base, left, and right point to the names to use in a
284  *    warning about multiple merge bases.
285  *
286  * If there is no symmetric diff argument, sym->skip is NULL and
287  * sym->warn is cleared.  The remaining fields are not set.
288  */
289 static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym)
290 {
291         int i, is_symdiff = 0, basecount = 0, othercount = 0;
292         int lpos = -1, rpos = -1, basepos = -1;
293         struct bitmap *map = NULL;
294
295         /*
296          * Use the whence fields to find merge bases and left and
297          * right parts of symmetric difference, so that we do not
298          * depend on the order that revisions are parsed.  If there
299          * are any revs that aren't from these sources, we have a
300          * "git diff C A...B" or "git diff A...B C" case.  Or we
301          * could even get "git diff A...B C...E", for instance.
302          *
303          * If we don't have just one merge base, we pick one
304          * at random.
305          *
306          * NB: REV_CMD_LEFT, REV_CMD_RIGHT are also used for A..B,
307          * so we must check for SYMMETRIC_LEFT too.  The two arrays
308          * rev->pending.objects and rev->cmdline.rev are parallel.
309          */
310         for (i = 0; i < rev->cmdline.nr; i++) {
311                 struct object *obj = rev->pending.objects[i].item;
312                 switch (rev->cmdline.rev[i].whence) {
313                 case REV_CMD_MERGE_BASE:
314                         if (basepos < 0)
315                                 basepos = i;
316                         basecount++;
317                         break;          /* do mark all bases */
318                 case REV_CMD_LEFT:
319                         if (lpos >= 0)
320                                 usage(builtin_diff_usage);
321                         lpos = i;
322                         if (obj->flags & SYMMETRIC_LEFT) {
323                                 is_symdiff = 1;
324                                 break;  /* do mark A */
325                         }
326                         continue;
327                 case REV_CMD_RIGHT:
328                         if (rpos >= 0)
329                                 usage(builtin_diff_usage);
330                         rpos = i;
331                         continue;       /* don't mark B */
332                 case REV_CMD_PARENTS_ONLY:
333                 case REV_CMD_REF:
334                 case REV_CMD_REV:
335                         othercount++;
336                         continue;
337                 }
338                 if (map == NULL)
339                         map = bitmap_new();
340                 bitmap_set(map, i);
341         }
342
343         /*
344          * Forbid any additional revs for both A...B and A..B.
345          */
346         if (lpos >= 0 && othercount > 0)
347                 usage(builtin_diff_usage);
348
349         if (!is_symdiff) {
350                 bitmap_free(map);
351                 sym->warn = 0;
352                 sym->skip = NULL;
353                 return;
354         }
355
356         sym->left = rev->pending.objects[lpos].name;
357         sym->right = rev->pending.objects[rpos].name;
358         if (basecount == 0)
359                 die(_("%s...%s: no merge base"), sym->left, sym->right);
360         sym->base = rev->pending.objects[basepos].name;
361         bitmap_unset(map, basepos);     /* unmark the base we want */
362         sym->warn = basecount > 1;
363         sym->skip = map;
364 }
365
366 int cmd_diff(int argc, const char **argv, const char *prefix)
367 {
368         int i;
369         struct rev_info rev;
370         struct object_array ent = OBJECT_ARRAY_INIT;
371         int blobs = 0, paths = 0;
372         struct object_array_entry *blob[2];
373         int nongit = 0, no_index = 0;
374         int result = 0;
375         struct symdiff sdiff;
376
377         /*
378          * We could get N tree-ish in the rev.pending_objects list.
379          * Also there could be M blobs there, and P pathspecs. --cached may
380          * also be present.
381          *
382          * N=0, M=0:
383          *      cache vs files (diff-files)
384          *
385          * N=0, M=0, --cached:
386          *      HEAD vs cache (diff-index --cached)
387          *
388          * N=0, M=2:
389          *      compare two random blobs.  P must be zero.
390          *
391          * N=0, M=1, P=1:
392          *      compare a blob with a working tree file.
393          *
394          * N=1, M=0:
395          *      tree vs files (diff-index)
396          *
397          * N=1, M=0, --cached:
398          *      tree vs cache (diff-index --cached)
399          *
400          * N=2, M=0:
401          *      tree vs tree (diff-tree)
402          *
403          * N=0, M=0, P=2:
404          *      compare two filesystem entities (aka --no-index).
405          *
406          * Other cases are errors.
407          */
408
409         /* Were we asked to do --no-index explicitly? */
410         for (i = 1; i < argc; i++) {
411                 if (!strcmp(argv[i], "--")) {
412                         i++;
413                         break;
414                 }
415                 if (!strcmp(argv[i], "--no-index"))
416                         no_index = DIFF_NO_INDEX_EXPLICIT;
417                 if (argv[i][0] != '-')
418                         break;
419         }
420
421         prefix = setup_git_directory_gently(&nongit);
422
423         if (!no_index) {
424                 /*
425                  * Treat git diff with at least one path outside of the
426                  * repo the same as if the command would have been executed
427                  * outside of a git repository.  In this case it behaves
428                  * the same way as "git diff --no-index <a> <b>", which acts
429                  * as a colourful "diff" replacement.
430                  */
431                 if (nongit || ((argc == i + 2) &&
432                                (!path_inside_repo(prefix, argv[i]) ||
433                                 !path_inside_repo(prefix, argv[i + 1]))))
434                         no_index = DIFF_NO_INDEX_IMPLICIT;
435         }
436
437         init_diff_ui_defaults();
438         git_config(git_diff_ui_config, NULL);
439         precompose_argv(argc, argv);
440
441         repo_init_revisions(the_repository, &rev, prefix);
442
443         /* Set up defaults that will apply to both no-index and regular diffs. */
444         rev.diffopt.stat_width = -1;
445         rev.diffopt.stat_graph_width = -1;
446         rev.diffopt.flags.allow_external = 1;
447         rev.diffopt.flags.allow_textconv = 1;
448
449         /* If this is a no-index diff, just run it and exit there. */
450         if (no_index)
451                 exit(diff_no_index(&rev, no_index == DIFF_NO_INDEX_IMPLICIT,
452                                    argc, argv));
453
454
455         /*
456          * Otherwise, we are doing the usual "git" diff; set up any
457          * further defaults that apply to regular diffs.
458          */
459         rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
460
461         /*
462          * Default to intent-to-add entries invisible in the
463          * index. This makes them show up as new files in diff-files
464          * and not at all in diff-cached.
465          */
466         rev.diffopt.ita_invisible_in_index = 1;
467
468         if (nongit)
469                 die(_("Not a git repository"));
470         argc = setup_revisions(argc, argv, &rev, NULL);
471         if (!rev.diffopt.output_format) {
472                 rev.diffopt.output_format = DIFF_FORMAT_PATCH;
473                 diff_setup_done(&rev.diffopt);
474         }
475
476         rev.diffopt.flags.recursive = 1;
477
478         setup_diff_pager(&rev.diffopt);
479
480         /*
481          * Do we have --cached and not have a pending object, then
482          * default to HEAD by hand.  Eek.
483          */
484         if (!rev.pending.nr) {
485                 int i;
486                 for (i = 1; i < argc; i++) {
487                         const char *arg = argv[i];
488                         if (!strcmp(arg, "--"))
489                                 break;
490                         else if (!strcmp(arg, "--cached") ||
491                                  !strcmp(arg, "--staged")) {
492                                 add_head_to_pending(&rev);
493                                 if (!rev.pending.nr) {
494                                         struct tree *tree;
495                                         tree = lookup_tree(the_repository,
496                                                            the_repository->hash_algo->empty_tree);
497                                         add_pending_object(&rev, &tree->object, "HEAD");
498                                 }
499                                 break;
500                         }
501                 }
502         }
503
504         symdiff_prepare(&rev, &sdiff);
505         for (i = 0; i < rev.pending.nr; i++) {
506                 struct object_array_entry *entry = &rev.pending.objects[i];
507                 struct object *obj = entry->item;
508                 const char *name = entry->name;
509                 int flags = (obj->flags & UNINTERESTING);
510                 if (!obj->parsed)
511                         obj = parse_object(the_repository, &obj->oid);
512                 obj = deref_tag(the_repository, obj, NULL, 0);
513                 if (!obj)
514                         die(_("invalid object '%s' given."), name);
515                 if (obj->type == OBJ_COMMIT)
516                         obj = &get_commit_tree(((struct commit *)obj))->object;
517
518                 if (obj->type == OBJ_TREE) {
519                         if (sdiff.skip && bitmap_get(sdiff.skip, i))
520                                 continue;
521                         obj->flags |= flags;
522                         add_object_array(obj, name, &ent);
523                 } else if (obj->type == OBJ_BLOB) {
524                         if (2 <= blobs)
525                                 die(_("more than two blobs given: '%s'"), name);
526                         blob[blobs] = entry;
527                         blobs++;
528
529                 } else {
530                         die(_("unhandled object '%s' given."), name);
531                 }
532         }
533         if (rev.prune_data.nr)
534                 paths += rev.prune_data.nr;
535
536         /*
537          * Now, do the arguments look reasonable?
538          */
539         if (!ent.nr) {
540                 switch (blobs) {
541                 case 0:
542                         result = builtin_diff_files(&rev, argc, argv);
543                         break;
544                 case 1:
545                         if (paths != 1)
546                                 usage(builtin_diff_usage);
547                         result = builtin_diff_b_f(&rev, argc, argv, blob);
548                         break;
549                 case 2:
550                         if (paths)
551                                 usage(builtin_diff_usage);
552                         result = builtin_diff_blobs(&rev, argc, argv, blob);
553                         break;
554                 default:
555                         usage(builtin_diff_usage);
556                 }
557         }
558         else if (blobs)
559                 usage(builtin_diff_usage);
560         else if (ent.nr == 1)
561                 result = builtin_diff_index(&rev, argc, argv);
562         else if (ent.nr == 2) {
563                 if (sdiff.warn)
564                         warning(_("%s...%s: multiple merge bases, using %s"),
565                                 sdiff.left, sdiff.right, sdiff.base);
566                 result = builtin_diff_tree(&rev, argc, argv,
567                                            &ent.objects[0], &ent.objects[1]);
568         } else
569                 result = builtin_diff_combined(&rev, argc, argv,
570                                                ent.objects, ent.nr);
571         result = diff_result_code(&rev.diffopt, result);
572         if (1 < rev.diffopt.skip_stat_unmatch)
573                 refresh_index_quietly();
574         UNLEAK(rev);
575         UNLEAK(ent);
576         UNLEAK(blob);
577         return result;
578 }