This allows users to add abitrary sth^{%foo} syntax that translates from an SHA-1 to another SHA-1, where "foo" refers to an alias "sha1-foo" or "foo". If either is found, %sha1% in the alias will be replaced with SHA-1 of "sth". The alias command is supposed to print translated SHA-1 to stdout. Another syntax is sth^{%foo:args} where %arg% in the alias will be replaced with "args" from the syntax. This gives users much more flexibilty in extending SHA-1 syntax. I'm not sure if I should support multiple arguments though. My mind is still with the :/ syntax. So as an example, git config alias.sha1-topic 'rev-list --merges --grep=%arg% --max-count=1 %sha1%' git rev-parse origin/pu^{%topic:nd/struct-pathspec} would give me sha-1 of my topic. This is supposed to be faster than standard :/ syntax because it only searches merges. I can also make it more accurate to my liking by adjust --grep= freely. Unfortunately git-rev-list takes ~1 sec to run. Maybe I can detect rev-list command and run it internally without run_command(). The intention is that a similar syntax can be used for branch translation too, i.e ref@{%...}. One of the rising issues is that every time this syntax is evaluated, external process will be run again. Some cache might help. I should also take alias code out of git.c for reuse here. So comments? (This patch looks bad, I know) Signed-off-by: Nguyán ThÃi Ngác Duy <pclouds@xxxxxxxxx> --- sha1_name.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 87 insertions(+), 0 deletions(-) diff --git a/sha1_name.c b/sha1_name.c index c5c59ce..6b40cec 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -6,6 +6,7 @@ #include "tree-walk.h" #include "refs.h" #include "remote.h" +#include "run-command.h" static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *); @@ -529,6 +530,86 @@ struct object *peel_to_type(const char *name, int namelen, } } +static int peel_alias_onion(const char *name, int len, const char *sp, + unsigned char *sha1) +{ + int alias_len; + struct strbuf sb = STRBUF_INIT; + struct strbuf cmd = STRBUF_INIT; + struct child_process cp; + const char **argv; + int count, hex_len; + char *s, *arg; + char hex[40]; + + len--; /* remove the last '}' */ + arg = strchr(sp, ':'); + if (arg) + alias_len = arg - sp; + else + alias_len = len - (sp - name); + strbuf_add(&sb, "sha1-", 5); + strbuf_add(&sb, sp, alias_len); + s = alias_lookup(sb.buf); + if (!s) { + strbuf_reset(&sb); + strbuf_add(&sb, sp, alias_len); + s = alias_lookup(sb.buf); + } + strbuf_release(&sb); + if (!s) + return error("unable to find alias for %s", name); + + strbuf_attach(&cmd, s, strlen(s), strlen(s)+1); + s = strstr(cmd.buf, "%sha1%"); + if (!s) { + error("%%sha1%% not found, not an sha1 alias:\n%s", cmd.buf); + strbuf_release(&cmd); + return -1; + } + strbuf_splice(&cmd, s - cmd.buf, 6, sha1_to_hex(sha1), 40); + if (arg) { + int arg_len = len - (++arg - name); + s = strstr(cmd.buf, "%arg%"); + if (!s) { + error("%%arg%% not found, not an sha1 alias:\n%s", cmd.buf); + strbuf_release(&cmd); + return -1; + } + strbuf_splice(&cmd, s - cmd.buf, 5, arg, arg_len); + } + + count = split_cmdline(cmd.buf, &argv); + if (count < 0) { + error("Bad alias.%s string: %s", cmd.buf, split_cmdline_strerror(count)); + strbuf_release(&cmd); + return -1; + } + + memset(&cp, 0, sizeof(cp)); + cp.git_cmd = 1; + cp.in = 0; + cp.out = -1; + cp.argv = argv; + trace_argv_printf(argv, "trace: sha1 alias expansion: %s =>", cmd.buf); + if (start_command(&cp)) { + error("Failed to run %s", cmd.buf); + strbuf_release(&cmd); + return -1; + } + hex_len = xread(cp.out, hex, 40); + close(cp.out); + if (finish_command(&cp)) { + error("Failed to finish %s", cmd.buf); + strbuf_release(&cmd); + return -1; + } + strbuf_release(&cmd); + if (hex_len != 40 || get_sha1_hex(hex, sha1)) + return error("failed to get result SHA-1 from ...%s", sp-3); + return 0; +} + static int peel_onion(const char *name, int len, unsigned char *sha1) { unsigned char outer[20]; @@ -566,6 +647,12 @@ static int peel_onion(const char *name, int len, unsigned char *sha1) expected_type = OBJ_NONE; else if (sp[0] == '/') expected_type = OBJ_COMMIT; + else if (sp[0] == '%') { + if (get_sha1_1(name, sp - name - 2, outer)) + return -1; + hashcpy(sha1, outer); + return peel_alias_onion(name, len, sp + 1, sha1); + } else return -1; -- 1.7.3.3.476.g10a82 -- 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