1010#include "cache-tree.h"
1111#include "path-list.h"
1212#include "unpack-trees.h"
13+ #include "refs.h"
1314
1415/*
1516 * diff-files
@@ -333,6 +334,26 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
333334 }
334335 return run_diff_files (revs , options );
335336}
337+ /*
338+ * See if work tree has an entity that can be staged. Return 0 if so,
339+ * return 1 if not and return -1 if error.
340+ */
341+ static int check_work_tree_entity (const struct cache_entry * ce , struct stat * st , char * symcache )
342+ {
343+ if (lstat (ce -> name , st ) < 0 ) {
344+ if (errno != ENOENT && errno != ENOTDIR )
345+ return -1 ;
346+ return 1 ;
347+ }
348+ if (has_symlink_leading_path (ce -> name , symcache ))
349+ return 1 ;
350+ if (S_ISDIR (st -> st_mode )) {
351+ unsigned char sub [20 ];
352+ if (resolve_gitlink_ref (ce -> name , "HEAD" , sub ))
353+ return 1 ;
354+ }
355+ return 0 ;
356+ }
336357
337358int run_diff_files (struct rev_info * revs , unsigned int option )
338359{
@@ -468,6 +489,11 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
468489 * diff-index
469490 */
470491
492+ struct oneway_unpack_data {
493+ struct rev_info * revs ;
494+ char symcache [PATH_MAX ];
495+ };
496+
471497/* A file entry went away or appeared */
472498static void diff_index_show_file (struct rev_info * revs ,
473499 const char * prefix ,
@@ -481,16 +507,20 @@ static void diff_index_show_file(struct rev_info *revs,
481507static int get_stat_data (struct cache_entry * ce ,
482508 const unsigned char * * sha1p ,
483509 unsigned int * modep ,
484- int cached , int match_missing )
510+ int cached , int match_missing ,
511+ struct oneway_unpack_data * cbdata )
485512{
486513 const unsigned char * sha1 = ce -> sha1 ;
487514 unsigned int mode = ce -> ce_mode ;
488515
489516 if (!cached ) {
490517 int changed ;
491518 struct stat st ;
492- if (lstat (ce -> name , & st ) < 0 ) {
493- if (errno == ENOENT && match_missing ) {
519+ changed = check_work_tree_entity (ce , & st , cbdata -> symcache );
520+ if (changed < 0 )
521+ return -1 ;
522+ else if (changed ) {
523+ if (match_missing ) {
494524 * sha1p = sha1 ;
495525 * modep = mode ;
496526 return 0 ;
@@ -509,32 +539,35 @@ static int get_stat_data(struct cache_entry *ce,
509539 return 0 ;
510540}
511541
512- static void show_new_file (struct rev_info * revs ,
542+ static void show_new_file (struct oneway_unpack_data * cbdata ,
513543 struct cache_entry * new ,
514544 int cached , int match_missing )
515545{
516546 const unsigned char * sha1 ;
517547 unsigned int mode ;
548+ struct rev_info * revs = cbdata -> revs ;
518549
519- /* New file in the index: it might actually be different in
550+ /*
551+ * New file in the index: it might actually be different in
520552 * the working copy.
521553 */
522- if (get_stat_data (new , & sha1 , & mode , cached , match_missing ) < 0 )
554+ if (get_stat_data (new , & sha1 , & mode , cached , match_missing , cbdata ) < 0 )
523555 return ;
524556
525557 diff_index_show_file (revs , "+" , new , sha1 , mode );
526558}
527559
528- static int show_modified (struct rev_info * revs ,
560+ static int show_modified (struct oneway_unpack_data * cbdata ,
529561 struct cache_entry * old ,
530562 struct cache_entry * new ,
531563 int report_missing ,
532564 int cached , int match_missing )
533565{
534566 unsigned int mode , oldmode ;
535567 const unsigned char * sha1 ;
568+ struct rev_info * revs = cbdata -> revs ;
536569
537- if (get_stat_data (new , & sha1 , & mode , cached , match_missing ) < 0 ) {
570+ if (get_stat_data (new , & sha1 , & mode , cached , match_missing , cbdata ) < 0 ) {
538571 if (report_missing )
539572 diff_index_show_file (revs , "-" , old ,
540573 old -> sha1 , old -> ce_mode );
@@ -602,7 +635,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,
602635 struct cache_entry * idx ,
603636 struct cache_entry * tree )
604637{
605- struct rev_info * revs = o -> unpack_data ;
638+ struct oneway_unpack_data * cbdata = o -> unpack_data ;
639+ struct rev_info * revs = cbdata -> revs ;
606640 int match_missing , cached ;
607641
608642 /*
@@ -625,7 +659,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,
625659 * Something added to the tree?
626660 */
627661 if (!tree ) {
628- show_new_file (revs , idx , cached , match_missing );
662+ show_new_file (cbdata , idx , cached , match_missing );
629663 return ;
630664 }
631665
@@ -638,7 +672,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,
638672 }
639673
640674 /* Show difference between old and new */
641- show_modified (revs , tree , idx , 1 , cached , match_missing );
675+ show_modified (cbdata , tree , idx , 1 , cached , match_missing );
642676}
643677
644678static inline void skip_same_name (struct cache_entry * ce , struct unpack_trees_options * o )
@@ -675,7 +709,8 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
675709{
676710 struct cache_entry * idx = src [0 ];
677711 struct cache_entry * tree = src [1 ];
678- struct rev_info * revs = o -> unpack_data ;
712+ struct oneway_unpack_data * cbdata = o -> unpack_data ;
713+ struct rev_info * revs = cbdata -> revs ;
679714
680715 if (idx && ce_stage (idx ))
681716 skip_same_name (idx , o );
@@ -702,6 +737,7 @@ int run_diff_index(struct rev_info *revs, int cached)
702737 const char * tree_name ;
703738 struct unpack_trees_options opts ;
704739 struct tree_desc t ;
740+ struct oneway_unpack_data unpack_cb ;
705741
706742 mark_merge_entries ();
707743
@@ -711,12 +747,14 @@ int run_diff_index(struct rev_info *revs, int cached)
711747 if (!tree )
712748 return error ("bad tree object %s" , tree_name );
713749
750+ unpack_cb .revs = revs ;
751+ unpack_cb .symcache [0 ] = '\0' ;
714752 memset (& opts , 0 , sizeof (opts ));
715753 opts .head_idx = 1 ;
716754 opts .index_only = cached ;
717755 opts .merge = 1 ;
718756 opts .fn = oneway_diff ;
719- opts .unpack_data = revs ;
757+ opts .unpack_data = & unpack_cb ;
720758 opts .src_index = & the_index ;
721759 opts .dst_index = NULL ;
722760
@@ -738,6 +776,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
738776 struct cache_entry * last = NULL ;
739777 struct unpack_trees_options opts ;
740778 struct tree_desc t ;
779+ struct oneway_unpack_data unpack_cb ;
741780
742781 /*
743782 * This is used by git-blame to run diff-cache internally;
@@ -766,12 +805,14 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
766805 if (!tree )
767806 die ("bad tree object %s" , sha1_to_hex (tree_sha1 ));
768807
808+ unpack_cb .revs = & revs ;
809+ unpack_cb .symcache [0 ] = '\0' ;
769810 memset (& opts , 0 , sizeof (opts ));
770811 opts .head_idx = 1 ;
771812 opts .index_only = 1 ;
772813 opts .merge = 1 ;
773814 opts .fn = oneway_diff ;
774- opts .unpack_data = & revs ;
815+ opts .unpack_data = & unpack_cb ;
775816 opts .src_index = & the_index ;
776817 opts .dst_index = & the_index ;
777818
0 commit comments