66#define USE_THE_INDEX_COMPATIBILITY_MACROS
77#include "cache.h"
88#include "config.h"
9+ #include "ewah/ewok.h"
910#include "lockfile.h"
1011#include "color.h"
1112#include "commit.h"
2324#define DIFF_NO_INDEX_IMPLICIT 2
2425
2526static const char builtin_diff_usage [] =
26- "git diff [<options>] [<commit> [<commit>]] [--] [<path>...]" ;
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 ;
2734
2835static const char * blob_path (struct object_array_entry * entry )
2936{
@@ -254,6 +261,108 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
254261 return run_diff_files (revs , options );
255262}
256263
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+ sym -> base = rev -> pending .objects [basepos ].name ;
359+ if (basecount == 0 )
360+ die (_ ("%s...%s: no merge base" ), sym -> left , sym -> right );
361+ bitmap_unset (map , basepos ); /* unmark the base we want */
362+ sym -> warn = basecount > 1 ;
363+ sym -> skip = map ;
364+ }
365+
257366int cmd_diff (int argc , const char * * argv , const char * prefix )
258367{
259368 int i ;
@@ -263,6 +372,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
263372 struct object_array_entry * blob [2 ];
264373 int nongit = 0 , no_index = 0 ;
265374 int result = 0 ;
375+ struct symdiff sdiff ;
266376
267377 /*
268378 * We could get N tree-ish in the rev.pending_objects list.
@@ -382,6 +492,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
382492 }
383493 }
384494
495+ symdiff_prepare (& rev , & sdiff );
385496 for (i = 0 ; i < rev .pending .nr ; i ++ ) {
386497 struct object_array_entry * entry = & rev .pending .objects [i ];
387498 struct object * obj = entry -> item ;
@@ -396,6 +507,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
396507 obj = & get_commit_tree (((struct commit * )obj ))-> object ;
397508
398509 if (obj -> type == OBJ_TREE ) {
510+ if (sdiff .skip && bitmap_get (sdiff .skip , i ))
511+ continue ;
399512 obj -> flags |= flags ;
400513 add_object_array (obj , name , & ent );
401514 } else if (obj -> type == OBJ_BLOB ) {
@@ -437,21 +550,12 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
437550 usage (builtin_diff_usage );
438551 else if (ent .nr == 1 )
439552 result = builtin_diff_index (& rev , argc , argv );
440- else if (ent .nr == 2 )
553+ else if (ent .nr == 2 ) {
554+ if (sdiff .warn )
555+ warning (_ ("%s...%s: multiple merge bases, using %s" ),
556+ sdiff .left , sdiff .right , sdiff .base );
441557 result = builtin_diff_tree (& rev , argc , argv ,
442558 & ent .objects [0 ], & ent .objects [1 ]);
443- else if (ent .objects [0 ].item -> flags & UNINTERESTING ) {
444- /*
445- * diff A...B where there is at least one merge base
446- * between A and B. We have ent.objects[0] ==
447- * merge-base, ent.objects[ents-2] == A, and
448- * ent.objects[ents-1] == B. Show diff between the
449- * base and B. Note that we pick one merge base at
450- * random if there are more than one.
451- */
452- result = builtin_diff_tree (& rev , argc , argv ,
453- & ent .objects [0 ],
454- & ent .objects [ent .nr - 1 ]);
455559 } else
456560 result = builtin_diff_combined (& rev , argc , argv ,
457561 ent .objects , ent .nr );
0 commit comments