@@ -333,6 +333,30 @@ static int do_for_each_ref_in_arrays(struct ref_array *array1,
333
333
return 0 ;
334
334
}
335
335
336
+ /*
337
+ * Return true iff refname1 and refname2 conflict with each other.
338
+ * Two reference names conflict if one of them exactly matches the
339
+ * leading components of the other; e.g., "foo/bar" conflicts with
340
+ * both "foo" and with "foo/bar/baz" but not with "foo/bar" or
341
+ * "foo/barbados".
342
+ */
343
+ static int names_conflict (const char * refname1 , const char * refname2 )
344
+ {
345
+ int len1 = strlen (refname1 );
346
+ int len2 = strlen (refname2 );
347
+ int cmplen ;
348
+ const char * lead ;
349
+
350
+ if (len1 < len2 ) {
351
+ cmplen = len1 ;
352
+ lead = refname2 ;
353
+ } else {
354
+ cmplen = len2 ;
355
+ lead = refname1 ;
356
+ }
357
+ return !strncmp (refname1 , refname2 , cmplen ) && lead [cmplen ] == '/' ;
358
+ }
359
+
336
360
/*
337
361
* Return true iff a reference named refname could be created without
338
362
* conflicting with the name of an existing reference. If oldrefname
@@ -343,20 +367,15 @@ static int do_for_each_ref_in_arrays(struct ref_array *array1,
343
367
static int is_refname_available (const char * refname , const char * oldrefname ,
344
368
struct ref_array * array )
345
369
{
346
- int i , namlen = strlen ( refname ); /* e.g. 'foo/bar' */
370
+ int i ;
347
371
for (i = 0 ; i < array -> nr ; i ++ ) {
348
372
struct ref_entry * entry = array -> refs [i ];
349
- /* entry->name could be 'foo' or 'foo/bar/baz' */
350
- if (!oldrefname || strcmp (oldrefname , entry -> name )) {
351
- int len = strlen (entry -> name );
352
- int cmplen = (namlen < len ) ? namlen : len ;
353
- const char * lead = (namlen < len ) ? entry -> name : refname ;
354
- if (!strncmp (refname , entry -> name , cmplen ) &&
355
- lead [cmplen ] == '/' ) {
356
- error ("'%s' exists; cannot create '%s'" ,
357
- entry -> name , refname );
358
- return 0 ;
359
- }
373
+ if (oldrefname && !strcmp (oldrefname , entry -> name ))
374
+ continue ;
375
+ if (names_conflict (refname , entry -> name )) {
376
+ error ("'%s' exists; cannot create '%s'" ,
377
+ entry -> name , refname );
378
+ return 0 ;
360
379
}
361
380
}
362
381
return 1 ;
@@ -1333,36 +1352,45 @@ struct ref_lock *lock_any_ref_for_update(const char *refname,
1333
1352
return lock_ref_sha1_basic (refname , old_sha1 , flags , NULL );
1334
1353
}
1335
1354
1355
+ struct repack_without_ref_sb {
1356
+ const char * refname ;
1357
+ int fd ;
1358
+ };
1359
+
1360
+ static int repack_without_ref_fn (const char * refname , const unsigned char * sha1 ,
1361
+ int flags , void * cb_data )
1362
+ {
1363
+ struct repack_without_ref_sb * data = cb_data ;
1364
+ char line [PATH_MAX + 100 ];
1365
+ int len ;
1366
+
1367
+ if (!strcmp (data -> refname , refname ))
1368
+ return 0 ;
1369
+ len = snprintf (line , sizeof (line ), "%s %s\n" ,
1370
+ sha1_to_hex (sha1 ), refname );
1371
+ /* this should not happen but just being defensive */
1372
+ if (len > sizeof (line ))
1373
+ die ("too long a refname '%s'" , refname );
1374
+ write_or_die (data -> fd , line , len );
1375
+ return 0 ;
1376
+ }
1377
+
1336
1378
static struct lock_file packlock ;
1337
1379
1338
1380
static int repack_without_ref (const char * refname )
1339
1381
{
1340
- struct ref_array * packed ;
1341
- int fd , i ;
1342
-
1343
- packed = get_packed_refs (get_ref_cache (NULL ));
1382
+ struct repack_without_ref_sb data ;
1383
+ struct ref_array * packed = get_packed_refs (get_ref_cache (NULL ));
1384
+ sort_ref_array (packed );
1344
1385
if (search_ref_array (packed , refname ) == NULL )
1345
1386
return 0 ;
1346
- fd = hold_lock_file_for_update (& packlock , git_path ("packed-refs" ), 0 );
1347
- if (fd < 0 ) {
1387
+ data .refname = refname ;
1388
+ data .fd = hold_lock_file_for_update (& packlock , git_path ("packed-refs" ), 0 );
1389
+ if (data .fd < 0 ) {
1348
1390
unable_to_lock_error (git_path ("packed-refs" ), errno );
1349
1391
return error ("cannot delete '%s' from packed refs" , refname );
1350
1392
}
1351
-
1352
- for (i = 0 ; i < packed -> nr ; i ++ ) {
1353
- char line [PATH_MAX + 100 ];
1354
- int len ;
1355
- struct ref_entry * ref = packed -> refs [i ];
1356
-
1357
- if (!strcmp (refname , ref -> name ))
1358
- continue ;
1359
- len = snprintf (line , sizeof (line ), "%s %s\n" ,
1360
- sha1_to_hex (ref -> sha1 ), ref -> name );
1361
- /* this should not happen but just being defensive */
1362
- if (len > sizeof (line ))
1363
- die ("too long a refname '%s'" , ref -> name );
1364
- write_or_die (fd , line , len );
1365
- }
1393
+ do_for_each_ref_in_array (packed , 0 , "" , repack_without_ref_fn , 0 , 0 , & data );
1366
1394
return commit_lock_file (& packlock );
1367
1395
}
1368
1396
0 commit comments