@@ -12,9 +12,6 @@ static const char *diff_opts = "-pu";
1212static unsigned char null_sha1 [20 ] = { 0 , };
1313
1414static int reverse_diff ;
15- static int generate_patch ;
16- static int line_termination = '\n' ;
17- static int inter_name_termination = '\t' ;
1815
1916static const char * external_diff (void )
2017{
@@ -502,7 +499,9 @@ struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
502499 return dp ;
503500}
504501
505- static void diff_flush_raw (struct diff_filepair * p )
502+ static void diff_flush_raw (struct diff_filepair * p ,
503+ int line_termination ,
504+ int inter_name_termination )
506505{
507506 int two_paths ;
508507 char status [10 ];
@@ -566,10 +565,6 @@ static void diff_flush_patch(struct diff_filepair *p)
566565 const char * name , * other ;
567566 char msg_ [PATH_MAX * 2 + 200 ], * msg ;
568567
569- /* diffcore_prune() keeps "stay" entries for diff-raw
570- * copy/rename detection, but when we are generating
571- * patches we do not need them.
572- */
573568 if (diff_unmodified_pair (p ))
574569 return ;
575570
@@ -585,7 +580,7 @@ static void diff_flush_patch(struct diff_filepair *p)
585580 "similarity index %d%%\n"
586581 "copy from %s\n"
587582 "copy to %s\n" ,
588- (int )(0.5 + p -> score * 100 /MAX_SCORE ),
583+ (int )(0.5 + p -> score * 100.0 /MAX_SCORE ),
589584 p -> one -> path , p -> two -> path );
590585 msg = msg_ ;
591586 break ;
@@ -594,7 +589,7 @@ static void diff_flush_patch(struct diff_filepair *p)
594589 "similarity index %d%%\n"
595590 "rename old %s\n"
596591 "rename new %s\n" ,
597- (int )(0.5 + p -> score * 100 /MAX_SCORE ),
592+ (int )(0.5 + p -> score * 100.0 /MAX_SCORE ),
598593 p -> one -> path , p -> two -> path );
599594 msg = msg_ ;
600595 break ;
@@ -630,105 +625,82 @@ int diff_needs_to_stay(struct diff_queue_struct *q, int i,
630625 return 0 ;
631626}
632627
633- static int diff_used_as_source (struct diff_queue_struct * q , int lim ,
634- struct diff_filespec * it )
628+ int diff_queue_is_empty (void )
635629{
636- int i ;
637- for (i = 0 ; i < lim ; i ++ ) {
638- struct diff_filepair * p = q -> queue [i ++ ];
639- if (!strcmp (p -> one -> path , it -> path ))
640- return 1 ;
641- }
642- return 0 ;
630+ struct diff_queue_struct * q = & diff_queued_diff ;
631+ return q -> nr == 0 ;
643632}
644633
645- void diffcore_prune (void )
634+ static void diff_resolve_rename_copy (void )
646635{
647- /*
648- * Although rename/copy detection wants to have "no-change"
649- * entries fed into them, the downstream do not need to see
650- * them, unless we had rename/copy for the same path earlier.
651- * This function removes such entries.
652- *
653- * The applications that use rename/copy should:
654- *
655- * (1) feed change and "no-change" entries via diff_queue().
656- * (2) call diffcore_rename, and any other future diffcore_xxx
657- * that would benefit by still having "no-change" entries.
658- * (3) call diffcore_prune
659- * (4) call other diffcore_xxx that do not need to see
660- * "no-change" entries.
661- * (5) call diff_flush().
662- */
663- struct diff_queue_struct * q = & diff_queued_diff ;
664- struct diff_queue_struct outq ;
665636 int i ;
666-
667- outq .queue = NULL ;
668- outq .nr = outq .alloc = 0 ;
669-
637+ struct diff_queue_struct * q = & diff_queued_diff ;
670638 for (i = 0 ; i < q -> nr ; i ++ ) {
671639 struct diff_filepair * p = q -> queue [i ];
672- if (!diff_unmodified_pair (p ) ||
673- diff_used_as_source (q , i , p -> one ))
674- diff_q (& outq , p );
675- else
676- free (p );
640+ p -> status = 0 ;
641+ if (DIFF_PAIR_UNMERGED (p ))
642+ p -> status = 'U' ;
643+ else if (!DIFF_FILE_VALID ((p )-> one ))
644+ p -> status = 'N' ;
645+ else if (!DIFF_FILE_VALID ((p )-> two )) {
646+ /* maybe earlier one said 'R', meaning
647+ * it will take it, in which case we do
648+ * not need to keep 'D'.
649+ */
650+ int j ;
651+ for (j = 0 ; j < i ; j ++ ) {
652+ struct diff_filepair * pp = q -> queue [j ];
653+ if (pp -> status == 'R' &&
654+ !strcmp (pp -> one -> path , p -> one -> path ))
655+ break ;
656+ }
657+ if (j < i )
658+ continue ;
659+ p -> status = 'D' ;
660+ }
661+ else if (strcmp (p -> one -> path , p -> two -> path )) {
662+ /* This is rename or copy. Which one is it? */
663+ if (diff_needs_to_stay (q , i + 1 , p -> one ))
664+ p -> status = 'C' ;
665+ else
666+ p -> status = 'R' ;
667+ }
668+ else if (memcmp (p -> one -> sha1 , p -> two -> sha1 , 20 ))
669+ p -> status = 'M' ;
670+ else {
671+ /* we do not need this one */
672+ p -> status = 0 ;
673+ }
677674 }
678- free (q -> queue );
679- * q = outq ;
680- return ;
681- }
682-
683- int diff_queue_is_empty (void )
684- {
685- struct diff_queue_struct * q = & diff_queued_diff ;
686- return q -> nr == 0 ;
687675}
688676
689677void diff_flush (int diff_output_style , int resolve_rename_copy )
690678{
691679 struct diff_queue_struct * q = & diff_queued_diff ;
692680 int i ;
681+ int line_termination = '\n' ;
682+ int inter_name_termination = '\t' ;
693683
694- generate_patch = 0 ;
695- switch (diff_output_style ) {
696- case DIFF_FORMAT_HUMAN :
697- line_termination = '\n' ;
698- inter_name_termination = '\t' ;
699- break ;
700- case DIFF_FORMAT_MACHINE :
684+ if (diff_output_style == DIFF_FORMAT_MACHINE )
701685 line_termination = inter_name_termination = 0 ;
702- break ;
703- case DIFF_FORMAT_PATCH :
704- generate_patch = 1 ;
705- break ;
706- }
686+ if (resolve_rename_copy )
687+ diff_resolve_rename_copy ();
688+
707689 for (i = 0 ; i < q -> nr ; i ++ ) {
708690 struct diff_filepair * p = q -> queue [i ];
709- if (resolve_rename_copy ) {
710- if (DIFF_PAIR_UNMERGED (p ))
711- p -> status = 'U' ;
712- else if (!DIFF_FILE_VALID ((p )-> one ))
713- p -> status = 'N' ;
714- else if (!DIFF_FILE_VALID ((p )-> two ))
715- p -> status = 'D' ;
716- else if (strcmp (p -> one -> path , p -> two -> path )) {
717- /* This is rename or copy. Which one is it? */
718- if (diff_needs_to_stay (q , i + 1 , p -> one ))
719- p -> status = 'C' ;
720- else
721- p -> status = 'R' ;
722- }
723- else
724- p -> status = 'M' ;
725- }
726- if (generate_patch )
691+ if (p -> status == 0 )
692+ continue ;
693+ switch (diff_output_style ) {
694+ case DIFF_FORMAT_PATCH :
727695 diff_flush_patch (p );
728- else
729- diff_flush_raw (p );
696+ break ;
697+ case DIFF_FORMAT_HUMAN :
698+ case DIFF_FORMAT_MACHINE :
699+ diff_flush_raw (p , line_termination ,
700+ inter_name_termination );
701+ break ;
702+ }
730703 }
731-
732704 for (i = 0 ; i < q -> nr ; i ++ ) {
733705 struct diff_filepair * p = q -> queue [i ];
734706 diff_free_filespec_data (p -> one );
@@ -755,9 +727,9 @@ void diff_addremove(int addremove, unsigned mode,
755727 * with something like '=' or '*' (I haven't decided
756728 * which but should not make any difference).
757729 * Feeding the same new and old to diff_change()
758- * also has the same effect. diffcore_prune() should
759- * be used to filter uninteresting ones out before the
760- * final output happens .
730+ * also has the same effect.
731+ * Before the final output happens, they are pruned after
732+ * merged into rename/copy pairs as appropriate .
761733 */
762734 if (reverse_diff )
763735 addremove = (addremove == '+' ? '-' :
0 commit comments