@@ -431,6 +431,7 @@ static inline int upstream_mark(const char *string, int len)
431
431
}
432
432
433
433
static int get_sha1_1 (const char * name , int len , unsigned char * sha1 , unsigned lookup_flags );
434
+ static int interpret_nth_prior_checkout (const char * name , struct strbuf * buf );
434
435
435
436
static int get_sha1_basic (const char * str , int len , unsigned char * sha1 )
436
437
{
@@ -448,7 +449,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
448
449
unsigned char tmp_sha1 [20 ];
449
450
char * real_ref = NULL ;
450
451
int refs_found = 0 ;
451
- int at , reflog_len ;
452
+ int at , reflog_len , nth_prior = 0 ;
452
453
453
454
if (len == 40 && !get_sha1_hex (str , sha1 )) {
454
455
refs_found = dwim_ref (str , len , tmp_sha1 , & real_ref );
@@ -464,8 +465,15 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
464
465
/* basic@{time or number or -number} format to query ref-log */
465
466
reflog_len = at = 0 ;
466
467
if (len && str [len - 1 ] == '}' ) {
467
- for (at = len - 2 ; at >= 0 ; at -- ) {
468
+ for (at = len - 4 ; at >= 0 ; at -- ) {
468
469
if (str [at ] == '@' && str [at + 1 ] == '{' ) {
470
+ if (str [at + 2 ] == '-' ) {
471
+ if (at != 0 )
472
+ /* @{-N} not at start */
473
+ return -1 ;
474
+ nth_prior = 1 ;
475
+ continue ;
476
+ }
469
477
if (!upstream_mark (str + at , len - at )) {
470
478
reflog_len = (len - 1 ) - (at + 2 );
471
479
len = at ;
@@ -479,20 +487,22 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
479
487
if (len && ambiguous_path (str , len ))
480
488
return -1 ;
481
489
482
- if (! len && reflog_len ) {
490
+ if (nth_prior ) {
483
491
struct strbuf buf = STRBUF_INIT ;
484
- int ret ;
485
- /* try the @{-N} syntax for n-th checkout */
486
- ret = interpret_branch_name (str + at , & buf );
487
- if (ret > 0 ) {
488
- /* substitute this branch name and restart */
489
- return get_sha1_1 (buf .buf , buf .len , sha1 , 0 );
490
- } else if (ret == 0 ) {
491
- return -1 ;
492
+ int detached ;
493
+
494
+ if (interpret_nth_prior_checkout (str , & buf ) > 0 ) {
495
+ detached = (buf .len == 40 && !get_sha1_hex (buf .buf , sha1 ));
496
+ strbuf_release (& buf );
497
+ if (detached )
498
+ return 0 ;
492
499
}
500
+ }
501
+
502
+ if (!len && reflog_len )
493
503
/* allow "@{...}" to mean the current branch reflog */
494
504
refs_found = dwim_ref ("HEAD" , 4 , sha1 , & real_ref );
495
- } else if (reflog_len )
505
+ else if (reflog_len )
496
506
refs_found = dwim_log (str , len , sha1 , & real_ref );
497
507
else
498
508
refs_found = dwim_ref (str , len , sha1 , & real_ref );
@@ -511,10 +521,6 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
511
521
unsigned long co_time ;
512
522
int co_tz , co_cnt ;
513
523
514
- /* a @{-N} placed anywhere except the start is an error */
515
- if (str [at + 2 ] == '-' )
516
- return -1 ;
517
-
518
524
/* Is it asking for N-th entry, or approxidate? */
519
525
for (i = nth = 0 ; 0 <= nth && i < reflog_len ; i ++ ) {
520
526
char ch = str [at + 2 + i ];
@@ -996,6 +1002,38 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
996
1002
return st ;
997
1003
}
998
1004
1005
+ /* parse @something syntax, when 'something' is not {.*} */
1006
+ static int interpret_empty_at (const char * name , int namelen , int len , struct strbuf * buf )
1007
+ {
1008
+ if (len || name [1 ] == '{' )
1009
+ return -1 ;
1010
+
1011
+ strbuf_reset (buf );
1012
+ strbuf_add (buf , "HEAD" , 4 );
1013
+ return 1 ;
1014
+ }
1015
+
1016
+ static int reinterpret (const char * name , int namelen , int len , struct strbuf * buf )
1017
+ {
1018
+ /* we have extra data, which might need further processing */
1019
+ struct strbuf tmp = STRBUF_INIT ;
1020
+ int used = buf -> len ;
1021
+ int ret ;
1022
+
1023
+ strbuf_add (buf , name + len , namelen - len );
1024
+ ret = interpret_branch_name (buf -> buf , & tmp );
1025
+ /* that data was not interpreted, remove our cruft */
1026
+ if (ret < 0 ) {
1027
+ strbuf_setlen (buf , used );
1028
+ return len ;
1029
+ }
1030
+ strbuf_reset (buf );
1031
+ strbuf_addbuf (buf , & tmp );
1032
+ strbuf_release (& tmp );
1033
+ /* tweak for size of {-N} versus expanded ref name */
1034
+ return ret - used + len ;
1035
+ }
1036
+
999
1037
/*
1000
1038
* This reads short-hand syntax that not only evaluates to a commit
1001
1039
* object name, but also can act as if the end user spelled the name
@@ -1025,36 +1063,27 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
1025
1063
int len = interpret_nth_prior_checkout (name , buf );
1026
1064
int tmp_len ;
1027
1065
1028
- if (!len )
1066
+ if (!len ) {
1029
1067
return len ; /* syntax Ok, not enough switches */
1030
- if (0 < len && len == namelen )
1031
- return len ; /* consumed all */
1032
- else if (0 < len ) {
1033
- /* we have extra data, which might need further processing */
1034
- struct strbuf tmp = STRBUF_INIT ;
1035
- int used = buf -> len ;
1036
- int ret ;
1037
-
1038
- strbuf_add (buf , name + len , namelen - len );
1039
- ret = interpret_branch_name (buf -> buf , & tmp );
1040
- /* that data was not interpreted, remove our cruft */
1041
- if (ret < 0 ) {
1042
- strbuf_setlen (buf , used );
1043
- return len ;
1044
- }
1045
- strbuf_reset (buf );
1046
- strbuf_addbuf (buf , & tmp );
1047
- strbuf_release (& tmp );
1048
- /* tweak for size of {-N} versus expanded ref name */
1049
- return ret - used + len ;
1068
+ } else if (len > 0 ) {
1069
+ if (len == namelen )
1070
+ return len ; /* consumed all */
1071
+ else
1072
+ return reinterpret (name , namelen , len , buf );
1050
1073
}
1051
1074
1052
1075
cp = strchr (name , '@' );
1053
1076
if (!cp )
1054
1077
return -1 ;
1078
+
1079
+ len = interpret_empty_at (name , namelen , cp - name , buf );
1080
+ if (len > 0 )
1081
+ return reinterpret (name , namelen , len , buf );
1082
+
1055
1083
tmp_len = upstream_mark (cp , namelen - (cp - name ));
1056
1084
if (!tmp_len )
1057
1085
return -1 ;
1086
+
1058
1087
len = cp + tmp_len - name ;
1059
1088
cp = xstrndup (name , cp - name );
1060
1089
upstream = branch_get (* cp ? cp : NULL );
0 commit comments