9
9
10
10
static int get_sha1_oneline (const char * , unsigned char * , struct commit_list * );
11
11
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 )
13
70
{
14
71
struct alternate_object_database * alt ;
15
72
char hex [40 ];
16
- int found = 0 ;
17
73
static struct alternate_object_database * fakeent ;
18
74
19
75
if (!fakeent ) {
@@ -35,32 +91,27 @@ static int find_short_object_filename(int len, const char *hex_pfx, unsigned cha
35
91
fakeent -> next = alt_odb_list ;
36
92
37
93
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 ) {
39
95
struct dirent * de ;
40
96
DIR * dir ;
41
97
sprintf (alt -> name , "%.2s/" , hex_pfx );
42
98
dir = opendir (alt -> base );
43
99
if (!dir )
44
100
continue ;
45
- while ((de = readdir (dir )) != NULL ) {
101
+
102
+ while (!ds -> ambiguous && (de = readdir (dir )) != NULL ) {
103
+ unsigned char sha1 [20 ];
104
+
46
105
if (strlen (de -> d_name ) != 38 )
47
106
continue ;
48
107
if (memcmp (de -> d_name , hex_pfx + 2 , len - 2 ))
49
108
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 );
58
112
}
59
113
closedir (dir );
60
114
}
61
- if (found == 1 )
62
- return get_sha1_hex (hex , sha1 ) == 0 ;
63
- return found ;
64
115
}
65
116
66
117
static 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 *
78
129
return 1 ;
79
130
}
80
131
81
- static int unique_in_pack (int len ,
132
+ static void unique_in_pack (int len ,
82
133
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 )
86
136
{
87
137
uint32_t num , last , i , first = 0 ;
88
138
const unsigned char * current = NULL ;
@@ -113,63 +163,58 @@ static int unique_in_pack(int len,
113
163
* with an object name that could match "bin_pfx". See if we have
114
164
* 0, 1 or more objects that actually match(es).
115
165
*/
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 );
118
168
if (!match_sha (len , bin_pfx , current ))
119
169
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 );
130
171
}
131
- return seen_so_far ;
132
172
}
133
173
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 )
135
176
{
136
177
struct packed_git * p ;
137
- const unsigned char * found_sha1 = NULL ;
138
- int found = 0 ;
139
178
140
179
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 );
147
182
}
148
183
149
184
#define SHORT_NAME_NOT_FOUND (-1)
150
185
#define SHORT_NAME_AMBIGUOUS (-2)
151
186
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 )
154
189
{
155
- int has_unpacked , has_packed ;
156
- unsigned char unpacked_sha1 [ 20 ], packed_sha1 [ 20 ] ;
190
+ if ( ds -> ambiguous )
191
+ return SHORT_NAME_AMBIGUOUS ;
157
192
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 )
162
194
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 );
173
218
return 0 ;
174
219
}
175
220
@@ -179,6 +224,7 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
179
224
int i , status ;
180
225
char hex_pfx [40 ];
181
226
unsigned char bin_pfx [20 ];
227
+ struct disambiguate_state ds ;
182
228
183
229
if (len < MINIMUM_ABBREV || len > 40 )
184
230
return -1 ;
@@ -203,7 +249,13 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
203
249
bin_pfx [i >> 1 ] |= val ;
204
250
}
205
251
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
+
207
259
if (!quietly && (status == SHORT_NAME_AMBIGUOUS ))
208
260
return error ("short SHA1 %.*s is ambiguous." , len , hex_pfx );
209
261
return status ;
0 commit comments