99
1010static int get_sha1_oneline (const char * , unsigned char * , struct commit_list * );
1111
12- static int find_short_object_filename (int len , const char * hex_pfx , unsigned char * sha1 )
12+ typedef int (* disambiguate_hint_fn )(const unsigned char * , void * );
13+
14+ struct disambiguate_state {
15+ disambiguate_hint_fn fn ;
16+ void * cb_data ;
17+ unsigned char candidate [20 ];
18+ unsigned candidate_exists :1 ;
19+ unsigned candidate_checked :1 ;
20+ unsigned candidate_ok :1 ;
21+ unsigned disambiguate_fn_used :1 ;
22+ unsigned ambiguous :1 ;
23+ };
24+
25+ static void update_candidates (struct disambiguate_state * ds , const unsigned char * current )
26+ {
27+ if (!ds -> candidate_exists ) {
28+ /* this is the first candidate */
29+ hashcpy (ds -> candidate , current );
30+ ds -> candidate_exists = 1 ;
31+ return ;
32+ } else if (!hashcmp (ds -> candidate , current )) {
33+ /* the same as what we already have seen */
34+ return ;
35+ }
36+
37+ if (!ds -> fn ) {
38+ /* cannot disambiguate between ds->candidate and current */
39+ ds -> ambiguous = 1 ;
40+ return ;
41+ }
42+
43+ if (!ds -> candidate_checked ) {
44+ ds -> candidate_ok = ds -> fn (ds -> candidate , ds -> cb_data );
45+ ds -> disambiguate_fn_used = 1 ;
46+ ds -> candidate_checked = 1 ;
47+ }
48+
49+ if (!ds -> candidate_ok ) {
50+ /* discard the candidate; we know it does not satisify fn */
51+ hashcpy (ds -> candidate , current );
52+ ds -> candidate_checked = 0 ;
53+ return ;
54+ }
55+
56+ /* if we reach this point, we know ds->candidate satisfies fn */
57+ if (ds -> fn (current , ds -> cb_data )) {
58+ /*
59+ * if both current and candidate satisfy fn, we cannot
60+ * disambiguate.
61+ */
62+ ds -> candidate_ok = 0 ;
63+ ds -> ambiguous = 1 ;
64+ }
65+
66+ /* otherwise, current can be discarded and candidate is still good */
67+ }
68+
69+ static void find_short_object_filename (int len , const char * hex_pfx , struct disambiguate_state * ds )
1370{
1471 struct alternate_object_database * alt ;
1572 char hex [40 ];
16- int found = 0 ;
1773 static struct alternate_object_database * fakeent ;
1874
1975 if (!fakeent ) {
@@ -35,32 +91,27 @@ static int find_short_object_filename(int len, const char *hex_pfx, unsigned cha
3591 fakeent -> next = alt_odb_list ;
3692
3793 sprintf (hex , "%.2s" , hex_pfx );
38- for (alt = fakeent ; alt && found < 2 ; alt = alt -> next ) {
94+ for (alt = fakeent ; alt && ! ds -> ambiguous ; alt = alt -> next ) {
3995 struct dirent * de ;
4096 DIR * dir ;
4197 sprintf (alt -> name , "%.2s/" , hex_pfx );
4298 dir = opendir (alt -> base );
4399 if (!dir )
44100 continue ;
45- while ((de = readdir (dir )) != NULL ) {
101+
102+ while (!ds -> ambiguous && (de = readdir (dir )) != NULL ) {
103+ unsigned char sha1 [20 ];
104+
46105 if (strlen (de -> d_name ) != 38 )
47106 continue ;
48107 if (memcmp (de -> d_name , hex_pfx + 2 , len - 2 ))
49108 continue ;
50- if (!found ) {
51- memcpy (hex + 2 , de -> d_name , 38 );
52- found ++ ;
53- }
54- else if (memcmp (hex + 2 , de -> d_name , 38 )) {
55- found = 2 ;
56- break ;
57- }
109+ memcpy (hex + 2 , de -> d_name , 38 );
110+ if (!get_sha1_hex (hex , sha1 ))
111+ update_candidates (ds , sha1 );
58112 }
59113 closedir (dir );
60114 }
61- if (found == 1 )
62- return get_sha1_hex (hex , sha1 ) == 0 ;
63- return found ;
64115}
65116
66117static int match_sha (unsigned len , const unsigned char * a , const unsigned char * b )
@@ -78,11 +129,10 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char *
78129 return 1 ;
79130}
80131
81- static int unique_in_pack (int len ,
132+ static void unique_in_pack (int len ,
82133 const unsigned char * bin_pfx ,
83- struct packed_git * p ,
84- const unsigned char * * found_sha1 ,
85- int seen_so_far )
134+ struct packed_git * p ,
135+ struct disambiguate_state * ds )
86136{
87137 uint32_t num , last , i , first = 0 ;
88138 const unsigned char * current = NULL ;
@@ -113,63 +163,58 @@ static int unique_in_pack(int len,
113163 * with an object name that could match "bin_pfx". See if we have
114164 * 0, 1 or more objects that actually match(es).
115165 */
116- for (i = first ; i < num ; i ++ ) {
117- current = nth_packed_object_sha1 (p , first );
166+ for (i = first ; i < num && ! ds -> ambiguous ; i ++ ) {
167+ current = nth_packed_object_sha1 (p , i );
118168 if (!match_sha (len , bin_pfx , current ))
119169 break ;
120-
121- /* current matches */
122- if (!seen_so_far ) {
123- * found_sha1 = current ;
124- seen_so_far ++ ;
125- } else if (seen_so_far ) {
126- /* is it the same as the one previously found elsewhere? */
127- if (hashcmp (* found_sha1 , current ))
128- return 2 ; /* definitely not unique */
129- }
170+ update_candidates (ds , current );
130171 }
131- return seen_so_far ;
132172}
133173
134- static int find_short_packed_object (int len , const unsigned char * bin_pfx , unsigned char * sha1 )
174+ static void find_short_packed_object (int len , const unsigned char * bin_pfx ,
175+ struct disambiguate_state * ds )
135176{
136177 struct packed_git * p ;
137- const unsigned char * found_sha1 = NULL ;
138- int found = 0 ;
139178
140179 prepare_packed_git ();
141- for (p = packed_git ; p && found < 2 ; p = p -> next )
142- found = unique_in_pack (len , bin_pfx , p , & found_sha1 , found );
143-
144- if (found == 1 )
145- hashcpy (sha1 , found_sha1 );
146- return found ;
180+ for (p = packed_git ; p && !ds -> ambiguous ; p = p -> next )
181+ unique_in_pack (len , bin_pfx , p , ds );
147182}
148183
149184#define SHORT_NAME_NOT_FOUND (-1)
150185#define SHORT_NAME_AMBIGUOUS (-2)
151186
152- static int find_unique_short_object ( int len , char * hex_pfx ,
153- unsigned char * bin_pfx , unsigned char * sha1 )
187+ static int finish_object_disambiguation ( struct disambiguate_state * ds ,
188+ unsigned char * sha1 )
154189{
155- int has_unpacked , has_packed ;
156- unsigned char unpacked_sha1 [ 20 ], packed_sha1 [ 20 ] ;
190+ if ( ds -> ambiguous )
191+ return SHORT_NAME_AMBIGUOUS ;
157192
158- prepare_alt_odb ();
159- has_unpacked = find_short_object_filename (len , hex_pfx , unpacked_sha1 );
160- has_packed = find_short_packed_object (len , bin_pfx , packed_sha1 );
161- if (!has_unpacked && !has_packed )
193+ if (!ds -> candidate_exists )
162194 return SHORT_NAME_NOT_FOUND ;
163- if (1 < has_unpacked || 1 < has_packed )
164- return SHORT_NAME_AMBIGUOUS ;
165- if (has_unpacked != has_packed ) {
166- hashcpy (sha1 , (has_packed ? packed_sha1 : unpacked_sha1 ));
167- return 0 ;
168- }
169- /* Both have unique ones -- do they match? */
170- if (hashcmp (packed_sha1 , unpacked_sha1 ))
171- return SHORT_NAME_AMBIGUOUS ;
172- hashcpy (sha1 , packed_sha1 );
195+
196+ if (!ds -> candidate_checked )
197+ /*
198+ * If this is the only candidate, there is no point
199+ * calling the disambiguation hint callback.
200+ *
201+ * On the other hand, if the current candidate
202+ * replaced an earlier candidate that did _not_ pass
203+ * the disambiguation hint callback, then we do have
204+ * more than one objects that match the short name
205+ * given, so we should make sure this one matches;
206+ * otherwise, if we discovered this one and the one
207+ * that we previously discarded in the reverse order,
208+ * we would end up showing different results in the
209+ * same repository!
210+ */
211+ ds -> candidate_ok = (!ds -> disambiguate_fn_used ||
212+ ds -> fn (ds -> candidate , ds -> cb_data ));
213+
214+ if (!ds -> candidate_ok )
215+ return SHORT_NAME_NOT_FOUND ;
216+
217+ hashcpy (sha1 , ds -> candidate );
173218 return 0 ;
174219}
175220
@@ -179,6 +224,7 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
179224 int i , status ;
180225 char hex_pfx [40 ];
181226 unsigned char bin_pfx [20 ];
227+ struct disambiguate_state ds ;
182228
183229 if (len < MINIMUM_ABBREV || len > 40 )
184230 return -1 ;
@@ -203,7 +249,13 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
203249 bin_pfx [i >> 1 ] |= val ;
204250 }
205251
206- status = find_unique_short_object (i , hex_pfx , bin_pfx , sha1 );
252+ prepare_alt_odb ();
253+
254+ memset (& ds , 0 , sizeof (ds ));
255+ find_short_object_filename (len , hex_pfx , & ds );
256+ find_short_packed_object (len , bin_pfx , & ds );
257+ status = finish_object_disambiguation (& ds , sha1 );
258+
207259 if (!quietly && (status == SHORT_NAME_AMBIGUOUS ))
208260 return error ("short SHA1 %.*s is ambiguous." , len , hex_pfx );
209261 return status ;
0 commit comments