From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: kevin@sb.org, "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 5/5] get_sha1: allow custom ref mapping with $ref@{~alias} syntax
Date: Fri, 24 Dec 2010 21:07:49 +0700 [thread overview]
Message-ID: <1293199669-19016-6-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1293199669-19016-1-git-send-email-pclouds@gmail.com>
Similar to $SHA1^{~alias}, the alias is defined as ref.alias. It is
supposed to return something that can resolve to a ref.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/config.txt | 9 +++++
Documentation/revisions.txt | 5 +++
alias.c | 5 +++
cache.h | 1 +
sha1_name.c | 70 +++++++++++++++++++++++++++++++++++++++++-
t/t1512-rev-parse-at.sh | 63 ++++++++++++++++++++++++++++++++++++++
6 files changed, 151 insertions(+), 2 deletions(-)
create mode 100755 t/t1512-rev-parse-at.sh
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0c4fb66..a20b467 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -597,6 +597,15 @@ sha1.*::
alias command will be substituted with 'extra'. The command is
supposed to return an extended SHA-1 syntax.
+ref.*::
+ Ref translation aliases. These aliases are similar to alias.*
+ but each will correspond to a '@\{{tilde}alias\}' syntax (see
+ linkgit:gitrevisions[7]). '%ref%' in the alias command will be
+ substituted with the ref before the '@'. If
+ '@\{{tilde}alias:extra\}' syntax is used, '%arg%' in the alias
+ command will be substituted with 'extra'. The command is supposed
+ to return a ref.
+
am.keepcr::
If true, git-am will call git-mailsplit for patches in mbox format
with parameter '--keep-cr'. In this case git-mailsplit will
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 413f91c..86b0b63 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -80,6 +80,11 @@ the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
the branch the ref is set to build on top of. Missing ref defaults
to the current branch.
+* A ref followed by '@\{{tilde}alias\}' will invoke the corresponding
+ alias command, specified in config (see linkgit:git-config[1],
+ key 'ref.*'). The command is supposed to return a ref. The
+ result ref can contain '@\{..\}' syntax.
+
* A suffix '{caret}' to a revision parameter (e.g. 'HEAD{caret}') means the first parent of
that commit object. '{caret}<n>' means the <n>th parent (i.e.
'rev{caret}'
diff --git a/alias.c b/alias.c
index 29a9903..242401e 100644
--- a/alias.c
+++ b/alias.c
@@ -36,6 +36,11 @@ char *sha1_alias_lookup(const char *alias)
return generic_alias_lookup(alias, "sha1.");
}
+char *ref_alias_lookup(const char *alias)
+{
+ return generic_alias_lookup(alias, "ref.");
+}
+
#define SPLIT_CMDLINE_BAD_ENDING 1
#define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
static const char *split_cmdline_errors[] = {
diff --git a/cache.h b/cache.h
index 56a1b18..1d4ce65 100644
--- a/cache.h
+++ b/cache.h
@@ -1121,6 +1121,7 @@ struct alias_param {
char *alias_lookup(const char *alias);
char *sha1_alias_lookup(const char *alias);
+char *ref_alias_lookup(const char *alias);
int split_cmdline(char *cmdline, const char ***argv);
/* Takes a negative value returned by split_cmdline */
const char *split_cmdline_strerror(int cmdline_errno);
diff --git a/sha1_name.c b/sha1_name.c
index cdf14c7..2734f24 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -359,7 +359,8 @@ 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 (!upstream_mark(str + at, len - at)) {
+ if (!upstream_mark(str + at, len - at) &&
+ str[at+2] != '~') {
reflog_len = (len-1) - (at+2);
len = at;
}
@@ -994,6 +995,69 @@ static int interpret_at_upstream(const char *at, struct strbuf *real_ref)
return len;
}
+static int interpret_at_alias(const char *at, struct strbuf *real_ref)
+{
+ struct alias_param *params, *param;
+ struct strbuf alias = STRBUF_INIT;
+ struct strbuf cmd = STRBUF_INIT;
+ char *s;
+ int ret, len, arg_len = 0;
+
+ if (at[1] != '{' || at[2] != '~')
+ return -1;
+ len = strcspn(at + 3, ":}");
+ if (!len)
+ return error("$ref@{~alias} syntax with no alias");
+ if (at[3 + len] == ':') {
+ s = strchr(at + 3 + len + 1, '}');
+ if (!s)
+ return error("$ref@{~alias} does not end with }");
+ arg_len = s - at - (3 + len + 1);
+ }
+ strbuf_add(&alias, at + 3, len);
+ s = ref_alias_lookup(alias.buf);
+ if (!s) {
+ ret = error("unable to find ref alias '%s'", alias.buf);
+ goto done;
+ }
+
+ strbuf_attach(&cmd, s, strlen(s), strlen(s)+1);
+ extract_alias_params(cmd.buf, ¶ms);
+ param = lookup_alias_param(params, "%ref%");
+ if (param && real_ref->len)
+ param->value = xstrdup(real_ref->buf);
+ else if (param) {
+ ret = error("%%ref%% not found in alias '%s'", cmd.buf);
+ goto done;
+ }
+ else if (real_ref->len) {
+ ret = error("%%ref%% is required but alias '%s' is not followed by a ref", cmd.buf);
+ goto done;
+ }
+ param = lookup_alias_param(params, "%arg%");
+ if (param && arg_len) {
+ param->value = xstrndup(at + len + 4, arg_len);
+ len += arg_len + 1;
+ }
+ else if (param) {
+ ret = error("Alias '%s' needs arguments", alias.buf);
+ goto done;
+ }
+ else if (arg_len) {
+ ret = error("Arguments are given but alias '%s' does not need them", alias.buf);
+ goto done;
+ }
+ expand_alias_params(&cmd, params);
+ free_alias_params(params);
+
+ trace_printf("trace: ref alias expansion: %s => %s\n", alias.buf, cmd.buf);
+ ret = get_alias_oneline(alias.buf, cmd.buf, real_ref) ? -1 : len + 4;
+done:
+ strbuf_release(&alias);
+ strbuf_release(&cmd);
+ return ret;
+}
+
/*
* 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
@@ -1035,6 +1099,8 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
if (len == -1)
len = interpret_at_upstream(cp, buf);
+ if (len == -1)
+ len = interpret_at_alias(cp, buf);
if (len == -1) {
strbuf_reset(buf);
return -1;
@@ -1044,7 +1110,7 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
return len; /* syntax Ok, not enough switches */
used += len;
- if (used == namelen)
+ if (used == namelen && !strstr(buf->buf, "@{"))
return used; /* consumed all */
/* we have extra data, which might need further processing */
diff --git a/t/t1512-rev-parse-at.sh b/t/t1512-rev-parse-at.sh
new file mode 100755
index 0000000..6594146
--- /dev/null
+++ b/t/t1512-rev-parse-at.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+test_description='tests for $ref@{something}'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit foo &&
+ git branch foo &&
+ test_commit bar &&
+ git branch bar &&
+ test_commit zoo-bar &&
+ git branch zoo/bar &&
+ test_commit zoo-zoo-bar &&
+ git branch zoo/zoo/bar
+'
+
+test_expect_success 'ref@{~}' '
+ test_must_fail git rev-parse HEAD@{~}
+'
+
+test_expect_success 'ref@{~non-existent}' '
+ test_must_fail git rev-parse HEAD@{~non-existent}
+'
+
+test_expect_success 'ref@{~simple}' '
+ git config ref.simple "symbolic-ref %ref%" &&
+ test_must_fail git rev-parse HEAD@{~simple:something} &&
+ git rev-parse HEAD@{~simple} >actual &&
+ git rev-parse HEAD >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'ref@{~external}' '
+ git config ref.external "!echo zoo/%ref%" &&
+ test_must_fail git rev-parse bar@{~external:something} &&
+ git rev-parse bar@{~external} >actual &&
+ git rev-parse zoo/bar >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'ref@{~witharg:args}' '
+ git config ref.witharg "!echo %ref%/%arg%" &&
+ test_must_fail git rev-parse zoo@{~witharg} &&
+ git rev-parse zoo@{~witharg:bar} >actual &&
+ git rev-parse zoo/bar >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'ref@{~external}@{~external}' '
+ git rev-parse bar@{~external}@{~external} >actual &&
+ git rev-parse zoo/zoo/bar >expected &&
+ test_cmp expected actual
+'
+
+test_expect_success 'ref@{~mapping}' '
+ git config ref.mapping "!echo %ref%@{~external}@{~external}" &&
+ git rev-parse bar@{~mapping} >actual &&
+ git rev-parse zoo/zoo/bar >expected &&
+ test_cmp expected actual
+'
+
+test_done
--
1.7.3.3.476.g10a82
prev parent reply other threads:[~2010-12-24 14:09 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-24 14:07 [PATCH 0/5] Custom extended SHA-1 syntax Nguyễn Thái Ngọc Duy
2010-12-24 14:07 ` [PATCH 1/5] alias: add functions to do param substitution and alias running Nguyễn Thái Ngọc Duy
2010-12-24 14:07 ` [PATCH 2/5] get_sha1: allow custom SHA-1 mapping with $SHA1^{~alias} syntax Nguyễn Thái Ngọc Duy
2010-12-24 14:07 ` [PATCH 3/5] sha1_name: move interpret_nth_prior_checkout closer to interpret_branch_name Nguyễn Thái Ngọc Duy
2010-12-24 14:07 ` [PATCH 4/5] interpret_branch_name: takes @{u} code out and reorder the function Nguyễn Thái Ngọc Duy
2010-12-24 14:07 ` Nguyễn Thái Ngọc Duy [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1293199669-19016-6-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
--cc=kevin@sb.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).