This allows users to add new @{..} alias via ref-at.* config variables. The rewrite rule is printf-alike. My itch is I usually work on a topic and only want to see commits in that topic. So I make a tag to the topic's base, then do git log base/my-topic.. That is a lot of keystrokes, and my mind is small enough sometimes I don't even remember the topic name, stucking at "base/ what?" Now I have "ref-at.base = base/%(tip)" in my gitconfig and I only need to do "git log @{base}..". This is probably not the best way to do though. Any advice? Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- cache.h | 3 ++ config.c | 3 ++ sha1_name.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/cache.h b/cache.h index be02a42..bad577d 100644 --- a/cache.h +++ b/cache.h @@ -1112,4 +1112,7 @@ extern struct startup_info *startup_info; /* builtin/merge.c */ int checkout_fast_forward(const unsigned char *from, const unsigned char *to); +/* sha1_name.c */ +extern int git_ref_at_config(const char *var, const char *value); + #endif /* CACHE_H */ diff --git a/config.c b/config.c index cdcf583..b560f51 100644 --- a/config.c +++ b/config.c @@ -720,6 +720,9 @@ int git_default_config(const char *var, const char *value, void *dummy) if (!prefixcmp(var, "advice.")) return git_default_advice_config(var, value); + if (!strncmp(var, "ref-at.", 7)) + return git_ref_at_config(var, value); + if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) { pager_use_color = git_config_bool(var,value); return 0; diff --git a/sha1_name.c b/sha1_name.c index 7b7e617..c9987f4 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -7,6 +7,84 @@ #include "refs.h" #include "remote.h" +struct ref_at { + const char *mark; + const char *format; +}; + +static struct ref_at *ref_at; +static int ref_at_nr; + +int git_ref_at_config(const char *var, const char *value) +{ + ref_at_nr++; + ref_at = xrealloc(ref_at, sizeof(*ref_at)*ref_at_nr); + ref_at[ref_at_nr-1].mark = xstrdup(var+7); /* ref-at. */ + ref_at[ref_at_nr-1].format = xstrdup(value); + return 0; +} + +static int substitute_ref_at(struct strbuf *sb, const char *name) +{ + int i; + const char *at = strchr(name, '@'); + const char *p, *p2; + + if (!at || at[1] != '{') + return -1; + for (i = 0; i < ref_at_nr; i++) { + int len = strlen(ref_at[i].mark); + if (!(at[len+2] == '}' && !strncmp(at+2, ref_at[i].mark, len))) + continue; + + p = ref_at[i].format; + while (*p) { + if (*p != '%') { + strbuf_addch(sb, *p); + p++; + continue; + } + if (p[1] == '%') { + strbuf_addch(sb, '%'); + p += 2; + continue; + } + if (p[1] != '(') { + error("ref-at.%s: '%%%c' not supported", ref_at[i].mark, p[1]); + return -1; + } + p += 2; + p2 = strchr(p, ')'); + if (!p2) + return -1; + if (!strncmp(p, "branch", p2-p)) { + strbuf_add(sb, name, at-name); + p = p2+1; + continue; + } + if (!strncmp(p, "tip", p2-p)) { + if (at == name || !strncmp(name, "HEAD", at-name)) { + unsigned char sha1[20]; + int flag; + const char *real_ref = resolve_ref("HEAD", sha1, 0, &flag); + if (!strncmp(real_ref, "refs/heads/", 11)) + strbuf_addstr(sb, real_ref+11); + else + strbuf_addstr(sb, real_ref); + } + else + strbuf_add(sb, name, p2-p); + p = p2+1; + continue; + } + error("ref-at.%s: '%%(%.*s)' is not supported", ref_at[i].mark, p2-p, p); + return -1; + } + return 1; + } + return 0; +} + static int find_short_object_filename(int len, const char *name, unsigned char *sha1) { struct alternate_object_database *alt; @@ -346,6 +424,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) char *real_ref = NULL; int refs_found = 0; int at, reflog_len; + struct strbuf new_str = STRBUF_INIT; if (len == 40 && !get_sha1_hex(str, sha1)) return 0; @@ -355,6 +434,11 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) if (len && str[len-1] == '}') { for (at = len-2; at >= 0; at--) { if (str[at] == '@' && str[at+1] == '{') { + if (substitute_ref_at(&new_str, str) >= 0) { + str = new_str.buf; + len = new_str.len; + break; + } if (!upstream_mark(str + at, len - at)) { reflog_len = (len-1) - (at+2); len = at; @@ -366,7 +450,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) /* Accept only unambiguous ref paths. */ if (len && ambiguous_path(str, len)) - return -1; + goto failed; if (!len && reflog_len) { struct strbuf buf = STRBUF_INIT; @@ -374,10 +458,11 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) /* try the @{-N} syntax for n-th checkout */ ret = interpret_branch_name(str+at, &buf); if (ret > 0) { + strbuf_release(&new_str); /* substitute this branch name and restart */ return get_sha1_1(buf.buf, buf.len, sha1); } else if (ret == 0) { - return -1; + goto failed; } /* allow "@{...}" to mean the current branch reflog */ refs_found = dwim_ref("HEAD", 4, sha1, &real_ref); @@ -387,7 +472,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) refs_found = dwim_ref(str, len, sha1, &real_ref); if (!refs_found) - return -1; + goto failed; if (warn_ambiguous_refs && refs_found > 1) warning(warn_msg, len, str); @@ -400,7 +485,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) /* a @{-N} placed anywhere except the start is an error */ if (str[at+2] == '-') - return -1; + goto failed; /* Is it asking for N-th entry, or approxidate? */ for (i = nth = 0; 0 <= nth && i < reflog_len; i++) { @@ -421,7 +506,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) at_time = approxidate_careful(tmp, &errors); free(tmp); if (errors) - return -1; + goto failed; } if (read_ref_at(real_ref, at_time, nth, sha1, NULL, &co_time, &co_tz, &co_cnt)) { @@ -438,7 +523,12 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) } free(real_ref); + strbuf_release(&new_str); return 0; + +failed: + strbuf_release(&new_str); + return -1; } static int get_parent(const char *name, int len, -- 1.7.1.rc1.69.g24c2f7 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html