6
6
#define USE_THE_INDEX_COMPATIBILITY_MACROS
7
7
#include "cache.h"
8
8
#include "config.h"
9
+ #include "ewah/ewok.h"
9
10
#include "lockfile.h"
10
11
#include "color.h"
11
12
#include "commit.h"
23
24
#define DIFF_NO_INDEX_IMPLICIT 2
24
25
25
26
static 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 ;
27
34
28
35
static const char * blob_path (struct object_array_entry * entry )
29
36
{
@@ -254,6 +261,108 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
254
261
return run_diff_files (revs , options );
255
262
}
256
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
+ 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
+
257
366
int cmd_diff (int argc , const char * * argv , const char * prefix )
258
367
{
259
368
int i ;
@@ -263,6 +372,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
263
372
struct object_array_entry * blob [2 ];
264
373
int nongit = 0 , no_index = 0 ;
265
374
int result = 0 ;
375
+ struct symdiff sdiff ;
266
376
267
377
/*
268
378
* 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)
382
492
}
383
493
}
384
494
495
+ symdiff_prepare (& rev , & sdiff );
385
496
for (i = 0 ; i < rev .pending .nr ; i ++ ) {
386
497
struct object_array_entry * entry = & rev .pending .objects [i ];
387
498
struct object * obj = entry -> item ;
@@ -396,6 +507,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
396
507
obj = & get_commit_tree (((struct commit * )obj ))-> object ;
397
508
398
509
if (obj -> type == OBJ_TREE ) {
510
+ if (sdiff .skip && bitmap_get (sdiff .skip , i ))
511
+ continue ;
399
512
obj -> flags |= flags ;
400
513
add_object_array (obj , name , & ent );
401
514
} else if (obj -> type == OBJ_BLOB ) {
@@ -437,21 +550,12 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
437
550
usage (builtin_diff_usage );
438
551
else if (ent .nr == 1 )
439
552
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 );
441
557
result = builtin_diff_tree (& rev , argc , argv ,
442
558
& 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 ]);
455
559
} else
456
560
result = builtin_diff_combined (& rev , argc , argv ,
457
561
ent .objects , ent .nr );
0 commit comments