25
25
#include "submodule-config.h"
26
26
#include "object-store.h"
27
27
#include "packfile.h"
28
+ #include "sparse-checkout.h"
28
29
29
30
static char const * const grep_usage [] = {
30
31
N_ ("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]" ),
@@ -410,7 +411,7 @@ static int grep_cache(struct grep_opt *opt,
410
411
const struct pathspec * pathspec , int cached );
411
412
static int grep_tree (struct grep_opt * opt , const struct pathspec * pathspec ,
412
413
struct tree_desc * tree , struct strbuf * base , int tn_len ,
413
- int check_attr );
414
+ int is_root_tree );
414
415
415
416
static int grep_submodule (struct grep_opt * opt ,
416
417
const struct pathspec * pathspec ,
@@ -498,6 +499,7 @@ static int grep_cache(struct grep_opt *opt,
498
499
int nr ;
499
500
struct strbuf name = STRBUF_INIT ;
500
501
int name_base_len = 0 ;
502
+ int sparse_paths_only = restrict_to_sparse_paths (repo );
501
503
if (repo -> submodule_prefix ) {
502
504
name_base_len = strlen (repo -> submodule_prefix );
503
505
strbuf_addstr (& name , repo -> submodule_prefix );
@@ -508,6 +510,10 @@ static int grep_cache(struct grep_opt *opt,
508
510
509
511
for (nr = 0 ; nr < repo -> index -> cache_nr ; nr ++ ) {
510
512
const struct cache_entry * ce = repo -> index -> cache [nr ];
513
+
514
+ if (sparse_paths_only && ce_skip_worktree (ce ))
515
+ continue ;
516
+
511
517
strbuf_setlen (& name , name_base_len );
512
518
strbuf_addstr (& name , ce -> name );
513
519
@@ -520,8 +526,7 @@ static int grep_cache(struct grep_opt *opt,
520
526
* cache entry are identical, even if worktree file has
521
527
* been modified, so use cache version instead
522
528
*/
523
- if (cached || (ce -> ce_flags & CE_VALID ) ||
524
- ce_skip_worktree (ce )) {
529
+ if (cached || (ce -> ce_flags & CE_VALID )) {
525
530
if (ce_stage (ce ) || ce_intent_to_add (ce ))
526
531
continue ;
527
532
hit |= grep_oid (opt , & ce -> oid , name .buf ,
@@ -552,9 +557,76 @@ static int grep_cache(struct grep_opt *opt,
552
557
return hit ;
553
558
}
554
559
555
- static int grep_tree (struct grep_opt * opt , const struct pathspec * pathspec ,
556
- struct tree_desc * tree , struct strbuf * base , int tn_len ,
557
- int check_attr )
560
+ static struct pattern_list * get_sparsity_patterns (struct repository * repo )
561
+ {
562
+ struct pattern_list * patterns ;
563
+ char * sparse_file ;
564
+ int sparse_config , cone_config ;
565
+
566
+ if (repo_config_get_bool (repo , "core.sparsecheckout" , & sparse_config ) ||
567
+ !sparse_config ) {
568
+ return NULL ;
569
+ }
570
+
571
+ sparse_file = repo_git_path (repo , "info/sparse-checkout" );
572
+ patterns = xcalloc (1 , sizeof (* patterns ));
573
+
574
+ if (repo_config_get_bool (repo , "core.sparsecheckoutcone" , & cone_config ))
575
+ cone_config = 0 ;
576
+ patterns -> use_cone_patterns = cone_config ;
577
+
578
+ if (add_patterns_from_file_to_list (sparse_file , "" , 0 , patterns , NULL )) {
579
+ if (file_exists (sparse_file )) {
580
+ warning (_ ("failed to load sparse-checkout file: '%s'" ),
581
+ sparse_file );
582
+ }
583
+ free (sparse_file );
584
+ free (patterns );
585
+ return NULL ;
586
+ }
587
+
588
+ free (sparse_file );
589
+ return patterns ;
590
+ }
591
+
592
+ static int path_in_sparse_checkout (struct strbuf * path , int prefix_len ,
593
+ unsigned int entry_mode ,
594
+ struct index_state * istate ,
595
+ struct pattern_list * sparsity ,
596
+ enum pattern_match_result parent_match ,
597
+ enum pattern_match_result * match )
598
+ {
599
+ int dtype = DT_UNKNOWN ;
600
+ int is_dir = S_ISDIR (entry_mode );
601
+
602
+ if (parent_match == MATCHED_RECURSIVE ) {
603
+ * match = parent_match ;
604
+ return 1 ;
605
+ }
606
+
607
+ if (is_dir && !is_dir_sep (path -> buf [path -> len - 1 ]))
608
+ strbuf_addch (path , '/' );
609
+
610
+ * match = path_matches_pattern_list (path -> buf , path -> len ,
611
+ path -> buf + prefix_len , & dtype ,
612
+ sparsity , istate );
613
+ if (* match == UNDECIDED )
614
+ * match = parent_match ;
615
+
616
+ if (is_dir )
617
+ strbuf_trim_trailing_dir_sep (path );
618
+
619
+ if (* match == NOT_MATCHED &&
620
+ (!is_dir || (is_dir && sparsity -> use_cone_patterns )))
621
+ return 0 ;
622
+
623
+ return 1 ;
624
+ }
625
+
626
+ static int do_grep_tree (struct grep_opt * opt , const struct pathspec * pathspec ,
627
+ struct tree_desc * tree , struct strbuf * base , int tn_len ,
628
+ int check_attr , struct pattern_list * sparsity ,
629
+ enum pattern_match_result default_sparsity_match )
558
630
{
559
631
struct repository * repo = opt -> repo ;
560
632
int hit = 0 ;
@@ -570,6 +642,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
570
642
571
643
while (tree_entry (tree , & entry )) {
572
644
int te_len = tree_entry_len (& entry );
645
+ enum pattern_match_result sparsity_match = 0 ;
573
646
574
647
if (match != all_entries_interesting ) {
575
648
strbuf_addstr (& name , base -> buf + tn_len );
@@ -586,6 +659,19 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
586
659
587
660
strbuf_add (base , entry .path , te_len );
588
661
662
+ if (sparsity ) {
663
+ struct strbuf path = STRBUF_INIT ;
664
+ strbuf_addstr (& path , base -> buf + tn_len );
665
+
666
+ if (!path_in_sparse_checkout (& path , old_baselen - tn_len ,
667
+ entry .mode , repo -> index ,
668
+ sparsity , default_sparsity_match ,
669
+ & sparsity_match )) {
670
+ strbuf_setlen (base , old_baselen );
671
+ continue ;
672
+ }
673
+ }
674
+
589
675
if (S_ISREG (entry .mode )) {
590
676
hit |= grep_oid (opt , & entry .oid , base -> buf , tn_len ,
591
677
check_attr ? base -> buf + tn_len : NULL );
@@ -602,8 +688,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
602
688
603
689
strbuf_addch (base , '/' );
604
690
init_tree_desc (& sub , data , size );
605
- hit |= grep_tree (opt , pathspec , & sub , base , tn_len ,
606
- check_attr );
691
+ hit |= do_grep_tree (opt , pathspec , & sub , base , tn_len ,
692
+ check_attr , sparsity , sparsity_match );
607
693
free (data );
608
694
} else if (recurse_submodules && S_ISGITLINK (entry .mode )) {
609
695
hit |= grep_submodule (opt , pathspec , & entry .oid ,
@@ -621,6 +707,32 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
621
707
return hit ;
622
708
}
623
709
710
+ /*
711
+ * Note: sparsity patterns and paths' attributes will only be considered if
712
+ * is_root_tree has true value. (Otherwise, we cannot properly perform pattern
713
+ * matching on paths.)
714
+ */
715
+ static int grep_tree (struct grep_opt * opt , const struct pathspec * pathspec ,
716
+ struct tree_desc * tree , struct strbuf * base , int tn_len ,
717
+ int is_root_tree )
718
+ {
719
+ struct pattern_list * patterns = NULL ;
720
+ int sparse_paths_only = restrict_to_sparse_paths (opt -> repo );
721
+ int ret ;
722
+
723
+ if (is_root_tree && sparse_paths_only )
724
+ patterns = get_sparsity_patterns (opt -> repo );
725
+
726
+ ret = do_grep_tree (opt , pathspec , tree , base , tn_len , is_root_tree ,
727
+ patterns , 0 );
728
+
729
+ if (patterns ) {
730
+ clear_pattern_list (patterns );
731
+ free (patterns );
732
+ }
733
+ return ret ;
734
+ }
735
+
624
736
static int grep_object (struct grep_opt * opt , const struct pathspec * pathspec ,
625
737
struct object * obj , const char * name , const char * path )
626
738
{
@@ -1148,6 +1260,12 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
1148
1260
1149
1261
if (!use_index || untracked ) {
1150
1262
int use_exclude = (opt_exclude < 0 ) ? use_index : !!opt_exclude ;
1263
+
1264
+ if (opt_restrict_to_sparse_paths >= 0 ) {
1265
+ die (_ ("--[no-]restrict-to-sparse-paths is incompatible"
1266
+ " with --no-index and --untracked" ));
1267
+ }
1268
+
1151
1269
hit = grep_directory (& opt , & pathspec , use_exclude , use_index );
1152
1270
} else if (0 <= opt_exclude ) {
1153
1271
die (_ ("--[no-]exclude-standard cannot be used for tracked contents" ));
0 commit comments