@@ -743,6 +743,103 @@ char *compute_alternate_path(const char *path, struct strbuf *err)
743743 return ref_git ;
744744}
745745
746+ static void fill_alternate_refs_command (struct child_process * cmd ,
747+ const char * repo_path )
748+ {
749+ const char * value ;
750+
751+ if (!git_config_get_value ("core.alternateRefsCommand" , & value )) {
752+ cmd -> use_shell = 1 ;
753+
754+ argv_array_push (& cmd -> args , value );
755+ argv_array_push (& cmd -> args , repo_path );
756+ } else {
757+ cmd -> git_cmd = 1 ;
758+
759+ argv_array_pushf (& cmd -> args , "--git-dir=%s" , repo_path );
760+ argv_array_push (& cmd -> args , "for-each-ref" );
761+ argv_array_push (& cmd -> args , "--format=%(objectname)" );
762+
763+ if (!git_config_get_value ("core.alternateRefsPrefixes" , & value )) {
764+ argv_array_push (& cmd -> args , "--" );
765+ argv_array_split (& cmd -> args , value );
766+ }
767+ }
768+
769+ cmd -> env = local_repo_env ;
770+ cmd -> out = -1 ;
771+ }
772+
773+ static void read_alternate_refs (const char * path ,
774+ alternate_ref_fn * cb ,
775+ void * data )
776+ {
777+ struct child_process cmd = CHILD_PROCESS_INIT ;
778+ struct strbuf line = STRBUF_INIT ;
779+ FILE * fh ;
780+
781+ fill_alternate_refs_command (& cmd , path );
782+
783+ if (start_command (& cmd ))
784+ return ;
785+
786+ fh = xfdopen (cmd .out , "r" );
787+ while (strbuf_getline_lf (& line , fh ) != EOF ) {
788+ struct object_id oid ;
789+ const char * p ;
790+
791+ if (parse_oid_hex (line .buf , & oid , & p ) || * p ) {
792+ warning (_ ("invalid line while parsing alternate refs: %s" ),
793+ line .buf );
794+ break ;
795+ }
796+
797+ cb (& oid , data );
798+ }
799+
800+ fclose (fh );
801+ finish_command (& cmd );
802+ }
803+
804+ struct alternate_refs_data {
805+ alternate_ref_fn * fn ;
806+ void * data ;
807+ };
808+
809+ static int refs_from_alternate_cb (struct object_directory * e ,
810+ void * data )
811+ {
812+ struct strbuf path = STRBUF_INIT ;
813+ size_t base_len ;
814+ struct alternate_refs_data * cb = data ;
815+
816+ if (!strbuf_realpath (& path , e -> path , 0 ))
817+ goto out ;
818+ if (!strbuf_strip_suffix (& path , "/objects" ))
819+ goto out ;
820+ base_len = path .len ;
821+
822+ /* Is this a git repository with refs? */
823+ strbuf_addstr (& path , "/refs" );
824+ if (!is_directory (path .buf ))
825+ goto out ;
826+ strbuf_setlen (& path , base_len );
827+
828+ read_alternate_refs (path .buf , cb -> fn , cb -> data );
829+
830+ out :
831+ strbuf_release (& path );
832+ return 0 ;
833+ }
834+
835+ void for_each_alternate_ref (alternate_ref_fn fn , void * data )
836+ {
837+ struct alternate_refs_data cb ;
838+ cb .fn = fn ;
839+ cb .data = data ;
840+ foreach_alt_odb (refs_from_alternate_cb , & cb );
841+ }
842+
746843int foreach_alt_odb (alt_odb_fn fn , void * cb )
747844{
748845 struct object_directory * ent ;
0 commit comments