7
7
#include "refs.h"
8
8
#include "remote.h"
9
9
10
+ static int get_sha1_oneline (const char * , unsigned char * , struct commit_list * );
11
+
10
12
static int find_short_object_filename (int len , const char * name , unsigned char * sha1 )
11
13
{
12
14
struct alternate_object_database * alt ;
@@ -562,6 +564,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
562
564
expected_type = OBJ_BLOB ;
563
565
else if (sp [0 ] == '}' )
564
566
expected_type = OBJ_NONE ;
567
+ else if (sp [0 ] == '/' )
568
+ expected_type = OBJ_COMMIT ;
565
569
else
566
570
return -1 ;
567
571
@@ -576,19 +580,37 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
576
580
if (!o || (!o -> parsed && !parse_object (o -> sha1 )))
577
581
return -1 ;
578
582
hashcpy (sha1 , o -> sha1 );
583
+ return 0 ;
579
584
}
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
+
581
602
/*
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.
585
605
*/
586
- o = peel_to_type (name , len , o , expected_type );
587
- if (o ) {
588
- hashcpy (sha1 , o -> sha1 );
606
+ if (sp [1 ] == '}' )
589
607
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 ;
592
614
}
593
615
return 0 ;
594
616
}
@@ -686,15 +708,14 @@ static int handle_one_ref(const char *path,
686
708
if (object -> type != OBJ_COMMIT )
687
709
return 0 ;
688
710
insert_by_date ((struct commit * )object , list );
689
- object -> flags |= ONELINE_SEEN ;
690
711
return 0 ;
691
712
}
692
713
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 )
694
716
{
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 ;
698
719
regex_t regex ;
699
720
700
721
if (prefix [0 ] == '!' ) {
@@ -706,41 +727,45 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
706
727
if (regcomp (& regex , prefix , REG_EXTENDED ))
707
728
die ("Invalid search pattern: %s" , prefix );
708
729
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 ;
711
732
commit_list_insert (l -> item , & backup );
733
+ }
712
734
while (list ) {
713
- char * p ;
735
+ char * p , * to_free = NULL ;
714
736
struct commit * commit ;
715
737
enum object_type type ;
716
738
unsigned long size ;
739
+ int matches ;
717
740
718
741
commit = pop_most_recent_commit (& list , ONELINE_SEEN );
719
742
if (!parse_object (commit -> object .sha1 ))
720
743
continue ;
721
- free (temp_commit_buffer );
722
744
if (commit -> buffer )
723
745
p = commit -> buffer ;
724
746
else {
725
747
p = read_sha1_file (commit -> object .sha1 , & type , & size );
726
748
if (!p )
727
749
continue ;
728
- temp_commit_buffer = p ;
750
+ to_free = p ;
729
751
}
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 ) {
733
758
hashcpy (sha1 , commit -> object .sha1 );
734
- retval = 0 ;
759
+ found = 1 ;
735
760
break ;
736
761
}
737
762
}
738
763
regfree (& regex );
739
- free (temp_commit_buffer );
740
764
free_commit_list (list );
741
765
for (l = backup ; l ; l = l -> next )
742
766
clear_commit_marks (l -> item , ONELINE_SEEN );
743
- return retval ;
767
+ free_commit_list (backup );
768
+ return found ? 0 : -1 ;
744
769
}
745
770
746
771
struct grab_nth_branch_switch_cbdata {
@@ -1107,9 +1132,11 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
1107
1132
struct cache_entry * ce ;
1108
1133
char * new_path = NULL ;
1109
1134
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
+ }
1113
1140
if (namelen < 3 ||
1114
1141
name [2 ] != ':' ||
1115
1142
name [1 ] < '0' || '3' < name [1 ])
0 commit comments