1919#include "dir.h"
2020#include "pathspec.h"
2121#include "submodule.h"
22+ #include "submodule-config.h"
2223
2324static char const * const grep_usage [] = {
2425 N_ ("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]" ),
@@ -28,6 +29,7 @@ static char const * const grep_usage[] = {
2829static const char * super_prefix ;
2930static int recurse_submodules ;
3031static struct argv_array submodule_options = ARGV_ARRAY_INIT ;
32+ static const char * parent_basename ;
3133
3234static int grep_submodule_launch (struct grep_opt * opt ,
3335 const struct grep_source * gs );
@@ -534,19 +536,53 @@ static int grep_submodule_launch(struct grep_opt *opt,
534536{
535537 struct child_process cp = CHILD_PROCESS_INIT ;
536538 int status , i ;
539+ const char * end_of_base ;
540+ const char * name ;
537541 struct work_item * w = opt -> output_priv ;
538542
543+ end_of_base = strchr (gs -> name , ':' );
544+ if (gs -> identifier && end_of_base )
545+ name = end_of_base + 1 ;
546+ else
547+ name = gs -> name ;
548+
539549 prepare_submodule_repo_env (& cp .env_array );
540550
541551 /* Add super prefix */
542552 argv_array_pushf (& cp .args , "--super-prefix=%s%s/" ,
543553 super_prefix ? super_prefix : "" ,
544- gs -> name );
554+ name );
545555 argv_array_push (& cp .args , "grep" );
546556
557+ /*
558+ * Add basename of parent project
559+ * When performing grep on a tree object the filename is prefixed
560+ * with the object's name: 'tree-name:filename'. In order to
561+ * provide uniformity of output we want to pass the name of the
562+ * parent project's object name to the submodule so the submodule can
563+ * prefix its output with the parent's name and not its own SHA1.
564+ */
565+ if (gs -> identifier && end_of_base )
566+ argv_array_pushf (& cp .args , "--parent-basename=%.*s" ,
567+ (int ) (end_of_base - gs -> name ),
568+ gs -> name );
569+
547570 /* Add options */
548- for (i = 0 ; i < submodule_options .argc ; i ++ )
571+ for (i = 0 ; i < submodule_options .argc ; i ++ ) {
572+ /*
573+ * If there is a tree identifier for the submodule, add the
574+ * rev after adding the submodule options but before the
575+ * pathspecs. To do this we listen for the '--' and insert the
576+ * sha1 before pushing the '--' onto the child process argv
577+ * array.
578+ */
579+ if (gs -> identifier &&
580+ !strcmp ("--" , submodule_options .argv [i ])) {
581+ argv_array_push (& cp .args , sha1_to_hex (gs -> identifier ));
582+ }
583+
549584 argv_array_push (& cp .args , submodule_options .argv [i ]);
585+ }
550586
551587 cp .git_cmd = 1 ;
552588 cp .dir = gs -> path ;
@@ -673,12 +709,22 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
673709 enum interesting match = entry_not_interesting ;
674710 struct name_entry entry ;
675711 int old_baselen = base -> len ;
712+ struct strbuf name = STRBUF_INIT ;
713+ int name_base_len = 0 ;
714+ if (super_prefix ) {
715+ strbuf_addstr (& name , super_prefix );
716+ name_base_len = name .len ;
717+ }
676718
677719 while (tree_entry (tree , & entry )) {
678720 int te_len = tree_entry_len (& entry );
679721
680722 if (match != all_entries_interesting ) {
681- match = tree_entry_interesting (& entry , base , tn_len , pathspec );
723+ strbuf_addstr (& name , base -> buf + tn_len );
724+ match = tree_entry_interesting (& entry , & name ,
725+ 0 , pathspec );
726+ strbuf_setlen (& name , name_base_len );
727+
682728 if (match == all_entries_not_interesting )
683729 break ;
684730 if (match == entry_not_interesting )
@@ -690,8 +736,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
690736 if (S_ISREG (entry .mode )) {
691737 hit |= grep_sha1 (opt , entry .oid -> hash , base -> buf , tn_len ,
692738 check_attr ? base -> buf + tn_len : NULL );
693- }
694- else if (S_ISDIR (entry .mode )) {
739+ } else if (S_ISDIR (entry .mode )) {
695740 enum object_type type ;
696741 struct tree_desc sub ;
697742 void * data ;
@@ -707,12 +752,18 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
707752 hit |= grep_tree (opt , pathspec , & sub , base , tn_len ,
708753 check_attr );
709754 free (data );
755+ } else if (recurse_submodules && S_ISGITLINK (entry .mode )) {
756+ hit |= grep_submodule (opt , entry .oid -> hash , base -> buf ,
757+ base -> buf + tn_len );
710758 }
759+
711760 strbuf_setlen (base , old_baselen );
712761
713762 if (hit && opt -> status_only )
714763 break ;
715764 }
765+
766+ strbuf_release (& name );
716767 return hit ;
717768}
718769
@@ -736,6 +787,10 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
736787 if (!data )
737788 die (_ ("unable to read tree (%s)" ), oid_to_hex (& obj -> oid ));
738789
790+ /* Use parent's name as base when recursing submodules */
791+ if (recurse_submodules && parent_basename )
792+ name = parent_basename ;
793+
739794 len = name ? strlen (name ) : 0 ;
740795 strbuf_init (& base , PATH_MAX + len + 1 );
741796 if (len ) {
@@ -762,6 +817,12 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
762817 for (i = 0 ; i < nr ; i ++ ) {
763818 struct object * real_obj ;
764819 real_obj = deref_tag (list -> objects [i ].item , NULL , 0 );
820+
821+ /* load the gitmodules file for this rev */
822+ if (recurse_submodules ) {
823+ submodule_free ();
824+ gitmodules_config_sha1 (real_obj -> oid .hash );
825+ }
765826 if (grep_object (opt , pathspec , real_obj , list -> objects [i ].name , list -> objects [i ].path )) {
766827 hit = 1 ;
767828 if (opt -> status_only )
@@ -902,6 +963,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
902963 N_ ("ignore files specified via '.gitignore'" ), 1 ),
903964 OPT_BOOL (0 , "recurse-submodules" , & recurse_submodules ,
904965 N_ ("recursivley search in each submodule" )),
966+ OPT_STRING (0 , "parent-basename" , & parent_basename ,
967+ N_ ("basename" ),
968+ N_ ("prepend parent project's basename to output" )),
905969 OPT_GROUP ("" ),
906970 OPT_BOOL ('v' , "invert-match" , & opt .invert ,
907971 N_ ("show non-matching lines" )),
@@ -1154,7 +1218,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
11541218 }
11551219 }
11561220
1157- if (recurse_submodules && (!use_index || untracked || list . nr ))
1221+ if (recurse_submodules && (!use_index || untracked ))
11581222 die (_ ("option not supported with --recurse-submodules." ));
11591223
11601224 if (!show_in_pager && !opt .status_only )
0 commit comments