77#include "refs.h"
88#include "remote.h"
99
10+ static int get_sha1_oneline (const char * , unsigned char * , struct commit_list * );
11+
1012static int find_short_object_filename (int len , const char * name , unsigned char * sha1 )
1113{
1214 struct alternate_object_database * alt ;
@@ -562,6 +564,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
562564 expected_type = OBJ_BLOB ;
563565 else if (sp [0 ] == '}' )
564566 expected_type = OBJ_NONE ;
567+ else if (sp [0 ] == '/' )
568+ expected_type = OBJ_COMMIT ;
565569 else
566570 return -1 ;
567571
@@ -576,19 +580,37 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
576580 if (!o || (!o -> parsed && !parse_object (o -> sha1 )))
577581 return -1 ;
578582 hashcpy (sha1 , o -> sha1 );
583+ return 0 ;
579584 }
580- else {
585+
586+ /*
587+ * At this point, the syntax look correct, so
588+ * if we do not get the needed object, we should
589+ * barf.
590+ */
591+ o = peel_to_type (name , len , o , expected_type );
592+ if (!o )
593+ return -1 ;
594+
595+ hashcpy (sha1 , o -> sha1 );
596+ if (sp [0 ] == '/' ) {
597+ /* "$commit^{/foo}" */
598+ char * prefix ;
599+ int ret ;
600+ struct commit_list * list = NULL ;
601+
581602 /*
582- * At this point, the syntax look correct, so
583- * if we do not get the needed object, we should
584- * barf.
603+ * $commit^{/}. Some regex implementation may reject.
604+ * We don't need regex anyway. '' pattern always matches.
585605 */
586- o = peel_to_type (name , len , o , expected_type );
587- if (o ) {
588- hashcpy (sha1 , o -> sha1 );
606+ if (sp [1 ] == '}' )
589607 return 0 ;
590- }
591- return -1 ;
608+
609+ prefix = xstrndup (sp + 1 , name + len - 1 - (sp + 1 ));
610+ commit_list_insert ((struct commit * )o , & list );
611+ ret = get_sha1_oneline (prefix , sha1 , list );
612+ free (prefix );
613+ return ret ;
592614 }
593615 return 0 ;
594616}
@@ -686,15 +708,14 @@ static int handle_one_ref(const char *path,
686708 if (object -> type != OBJ_COMMIT )
687709 return 0 ;
688710 insert_by_date ((struct commit * )object , list );
689- object -> flags |= ONELINE_SEEN ;
690711 return 0 ;
691712}
692713
693- static int get_sha1_oneline (const char * prefix , unsigned char * sha1 )
714+ static int get_sha1_oneline (const char * prefix , unsigned char * sha1 ,
715+ struct commit_list * list )
694716{
695- struct commit_list * list = NULL , * backup = NULL , * l ;
696- int retval = -1 ;
697- char * temp_commit_buffer = NULL ;
717+ struct commit_list * backup = NULL , * l ;
718+ int found = 0 ;
698719 regex_t regex ;
699720
700721 if (prefix [0 ] == '!' ) {
@@ -706,41 +727,45 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
706727 if (regcomp (& regex , prefix , REG_EXTENDED ))
707728 die ("Invalid search pattern: %s" , prefix );
708729
709- for_each_ref ( handle_one_ref , & list );
710- for ( l = list ; l ; l = l -> next )
730+ for ( l = list ; l ; l = l -> next ) {
731+ l -> item -> object . flags |= ONELINE_SEEN ;
711732 commit_list_insert (l -> item , & backup );
733+ }
712734 while (list ) {
713- char * p ;
735+ char * p , * to_free = NULL ;
714736 struct commit * commit ;
715737 enum object_type type ;
716738 unsigned long size ;
739+ int matches ;
717740
718741 commit = pop_most_recent_commit (& list , ONELINE_SEEN );
719742 if (!parse_object (commit -> object .sha1 ))
720743 continue ;
721- free (temp_commit_buffer );
722744 if (commit -> buffer )
723745 p = commit -> buffer ;
724746 else {
725747 p = read_sha1_file (commit -> object .sha1 , & type , & size );
726748 if (!p )
727749 continue ;
728- temp_commit_buffer = p ;
750+ to_free = p ;
729751 }
730- if (!(p = strstr (p , "\n\n" )))
731- continue ;
732- if (!regexec (& regex , p + 2 , 0 , NULL , 0 )) {
752+
753+ p = strstr (p , "\n\n" );
754+ matches = p && !regexec (& regex , p + 2 , 0 , NULL , 0 );
755+ free (to_free );
756+
757+ if (matches ) {
733758 hashcpy (sha1 , commit -> object .sha1 );
734- retval = 0 ;
759+ found = 1 ;
735760 break ;
736761 }
737762 }
738763 regfree (& regex );
739- free (temp_commit_buffer );
740764 free_commit_list (list );
741765 for (l = backup ; l ; l = l -> next )
742766 clear_commit_marks (l -> item , ONELINE_SEEN );
743- return retval ;
767+ free_commit_list (backup );
768+ return found ? 0 : -1 ;
744769}
745770
746771struct grab_nth_branch_switch_cbdata {
@@ -1107,9 +1132,11 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
11071132 struct cache_entry * ce ;
11081133 char * new_path = NULL ;
11091134 int pos ;
1110- if (namelen > 2 && name [1 ] == '/' )
1111- /* don't need mode for commit */
1112- return get_sha1_oneline (name + 2 , sha1 );
1135+ if (namelen > 2 && name [1 ] == '/' ) {
1136+ struct commit_list * list = NULL ;
1137+ for_each_ref (handle_one_ref , & list );
1138+ return get_sha1_oneline (name + 2 , sha1 , list );
1139+ }
11131140 if (namelen < 3 ||
11141141 name [2 ] != ':' ||
11151142 name [1 ] < '0' || '3' < name [1 ])
0 commit comments