@ -431,6 +431,7 @@ static inline int upstream_mark(const char *string, int len)
@@ -431,6 +431,7 @@ static inline int upstream_mark(const char *string, int len)
}
static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf);
static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
{
@ -448,7 +449,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
@@ -448,7 +449,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
unsigned char tmp_sha1[20];
char *real_ref = NULL;
int refs_found = 0;
int at, reflog_len;
int at, reflog_len, nth_prior = 0;
if (len == 40 && !get_sha1_hex(str, sha1)) {
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,8 +465,15 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
/* basic@{time or number or -number} format to query ref-log */
reflog_len = at = 0;
if (len && str[len-1] == '}') {
for (at = len-2; at >= 0; at--) {
for (at = len-4; at >= 0; at--) {
if (str[at] == '@' && str[at+1] == '{') {
if (str[at+2] == '-') {
if (at != 0)
/* @{-N} not at start */
return -1;
nth_prior = 1;
continue;
}
if (!upstream_mark(str + at, len - at)) {
reflog_len = (len-1) - (at+2);
len = at;
@ -479,20 +487,22 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
@@ -479,20 +487,22 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
if (len && ambiguous_path(str, len))
return -1;
if (!len && reflog_len) {
if (nth_prior) {
struct strbuf buf = STRBUF_INIT;
int ret;
/* try the @{-N} syntax for n-th checkout */
ret = interpret_branch_name(str+at, &buf);
if (ret > 0) {
/* substitute this branch name and restart */
return get_sha1_1(buf.buf, buf.len, sha1, 0);
} else if (ret == 0) {
return -1;
int detached;
if (interpret_nth_prior_checkout(str, &buf) > 0) {
detached = (buf.len == 40 && !get_sha1_hex(buf.buf, sha1));
strbuf_release(&buf);
if (detached)
return 0;
}
}
if (!len && reflog_len)
/* allow "@{...}" to mean the current branch reflog */
refs_found = dwim_ref("HEAD", 4, sha1, &real_ref);
} else if (reflog_len)
else if (reflog_len)
refs_found = dwim_log(str, len, sha1, &real_ref);
else
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,10 +521,6 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
unsigned long co_time;
int co_tz, co_cnt;
/* a @{-N} placed anywhere except the start is an error */
if (str[at+2] == '-')
return -1;
/* Is it asking for N-th entry, or approxidate? */
for (i = nth = 0; 0 <= nth && i < reflog_len; i++) {
char ch = str[at+2+i];
@ -996,6 +1002,38 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
@@ -996,6 +1002,38 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
return st;
}
/* parse @something syntax, when 'something' is not {.*} */
static int interpret_empty_at(const char *name, int namelen, int len, struct strbuf *buf)
{
if (len || name[1] == '{')
return -1;
strbuf_reset(buf);
strbuf_add(buf, "HEAD", 4);
return 1;
}
static int reinterpret(const char *name, int namelen, int len, struct strbuf *buf)
{
/* we have extra data, which might need further processing */
struct strbuf tmp = STRBUF_INIT;
int used = buf->len;
int ret;
strbuf_add(buf, name + len, namelen - len);
ret = interpret_branch_name(buf->buf, &tmp);
/* that data was not interpreted, remove our cruft */
if (ret < 0) {
strbuf_setlen(buf, used);
return len;
}
strbuf_reset(buf);
strbuf_addbuf(buf, &tmp);
strbuf_release(&tmp);
/* tweak for size of {-N} versus expanded ref name */
return ret - used + len;
}
/*
* This reads short-hand syntax that not only evaluates to a commit
* 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,36 +1063,27 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
int len = interpret_nth_prior_checkout(name, buf);
int tmp_len;
if (!len)
if (!len) {
return len; /* syntax Ok, not enough switches */
if (0 < len && len == namelen)
return len; /* consumed all */
else if (0 < len) {
/* we have extra data, which might need further processing */
struct strbuf tmp = STRBUF_INIT;
int used = buf->len;
int ret;
strbuf_add(buf, name + len, namelen - len);
ret = interpret_branch_name(buf->buf, &tmp);
/* that data was not interpreted, remove our cruft */
if (ret < 0) {
strbuf_setlen(buf, used);
return len;
}
strbuf_reset(buf);
strbuf_addbuf(buf, &tmp);
strbuf_release(&tmp);
/* tweak for size of {-N} versus expanded ref name */
return ret - used + len;
} else if (len > 0) {
if (len == namelen)
return len; /* consumed all */
else
return reinterpret(name, namelen, len, buf);
}
cp = strchr(name, '@');
if (!cp)
return -1;
len = interpret_empty_at(name, namelen, cp - name, buf);
if (len > 0)
return reinterpret(name, namelen, len, buf);
tmp_len = upstream_mark(cp, namelen - (cp - name));
if (!tmp_len)
return -1;
len = cp + tmp_len - name;
cp = xstrndup(name, cp - name);
upstream = branch_get(*cp ? cp : NULL);