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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.