[prev in list] [next in list] [prev in thread] [next in thread]
List: git
Subject: [PATCH] for-each-ref: `:short` format for `refname`
From: Bert Wesarg <bert.wesarg () googlemail ! com>
Date: 2008-08-31 12:41:07
Message-ID: 1220186467-24623-1-git-send-email-bert.wesarg () googlemail ! com
[Download RAW message or body]
This strips from the refname the common directory prefix with the
matched pattern.
This is particular usefull for bash completion, to get refs without
`refs/heads` or `refs/tags`.
Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>
---
Documentation/git-for-each-ref.txt | 5 ++
builtin-for-each-ref.c | 74 +++++++++++++++++++++++++++++++----
t/t6300-for-each-ref.sh | 61 +++++++++++++++++++++++++++++
3 files changed, 131 insertions(+), 9 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index eae6c0e..deeae79 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -74,6 +74,11 @@ For all objects, the following names can be used:
refname::
The name of the ref (the part after $GIT_DIR/).
+ For a short name of the ref append `:short`. This will strip
+ the common directory prefix with the pattern which matches this ref.
+ I.e. for a the pattern `refs/heads` you get `master`, or for
+ `refs/tags/v1.5.[01].*` you get `v1.5.[01].*`.
+ This is particular usefull for bash completion.
objecttype::
The type of the object (`blob`, `tree`, `commit`, `tag`).
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index 21e92bb..946f79b 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -31,6 +31,7 @@ struct ref_sort {
struct refinfo {
char *refname;
+ const char *pattern; /* the pattern which matched this ref */
unsigned char objectname[20];
struct atom_value *value;
};
@@ -546,6 +547,40 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v
}
/*
+ * Use the matched pattern from ref to shorten the refname
+ */
+static char *get_short_ref(struct refinfo *ref)
+{
+ int rlen, plen, common = 0;
+
+ if (!ref->pattern)
+ return ref->refname;
+
+ rlen = strlen(ref->refname);
+ plen = strlen(ref->pattern);
+
+ if ((plen <= rlen) &&
+ !strncmp(ref->refname, ref->pattern, plen) &&
+ (ref->refname[plen] == '\0' ||
+ ref->refname[plen] == '/' ||
+ ref->pattern[plen - 1] == '/')) {
+ common = plen + (ref->refname[plen] == '/');
+ /* prevent stripping the whole refname */
+ if (common == rlen)
+ common = 0;
+ } else {
+ /* find the first wildcard and go back to the previous '/' */
+ common = strcspn(ref->pattern, "*?[");
+ while (common >= 0 && ref->pattern[common] != '/')
+ --common;
+ common++;
+ }
+
+ return ref->refname + common;
+}
+
+
+/*
* Parse the object referred by ref, and grab needed value.
*/
static void populate_value(struct refinfo *ref)
@@ -570,13 +605,33 @@ static void populate_value(struct refinfo *ref)
for (i = 0; i < used_atom_cnt; i++) {
const char *name = used_atom[i];
struct atom_value *v = &ref->value[i];
- if (!strcmp(name, "refname"))
- v->s = ref->refname;
- else if (!strcmp(name, "*refname")) {
- int len = strlen(ref->refname);
- char *s = xmalloc(len + 4);
- sprintf(s, "%s^{}", ref->refname);
- v->s = s;
+ int deref = 0;
+ if (*name == '*') {
+ deref = 1;
+ name++;
+ }
+ if (!prefixcmp(name, "refname")) {
+ const char *formatp = strchr(name, ':');
+ const char *refname = ref->refname;
+
+ /* look for "short" refname format */
+ if (formatp) {
+ formatp++;
+ if (!strcmp(formatp, "short"))
+ refname = get_short_ref(ref);
+ else
+ die("unknown refname format %s",
+ formatp);
+ }
+
+ if (!deref)
+ v->s = refname;
+ else {
+ int len = strlen(refname);
+ char *s = xmalloc(len + 4);
+ sprintf(s, "%s^{}", refname);
+ v->s = s;
+ }
}
}
@@ -641,9 +696,9 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f
struct grab_ref_cbdata *cb = cb_data;
struct refinfo *ref;
int cnt;
+ const char **pattern = cb->grab_pattern;
- if (*cb->grab_pattern) {
- const char **pattern;
+ if (*pattern) {
int namelen = strlen(refname);
for (pattern = cb->grab_pattern; *pattern; pattern++) {
const char *p = *pattern;
@@ -668,6 +723,7 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f
*/
ref = xcalloc(1, sizeof(*ref));
ref->refname = xstrdup(refname);
+ ref->pattern = *pattern;
hashcpy(ref->objectname, sha1);
cnt = cb->grab_cnt;
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 8ced593..a4a2fd3 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -262,6 +262,67 @@ for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do
"
done
+cat >expected <<\EOF
+master
+testtag
+master
+testtag
+EOF
+
+test_expect_success 'Check short refname format' '
+ (git for-each-ref --format="%(refname:short)" refs/heads &&
+ git for-each-ref --format="%(refname:short)" refs/tags &&
+ git for-each-ref --format="%(refname:short)" refs/heads/ &&
+ git for-each-ref --format="%(refname:short)" refs/tags/) >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+master
+testtag
+EOF
+
+test_expect_success 'Check short refname format with multiple patterns' '
+ (git for-each-ref --format="%(refname:short)" refs/heads refs/tags) >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+refs/heads/master
+refs/tags/testtag
+EOF
+
+test_expect_success 'Check short refname format without patterns' '
+ git for-each-ref --format="%(refname:short)" >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Check for invalid refname format' '
+ test_must_fail git for-each-ref --format="%(refname:INVALID)"
+'
+
+cat >expected <<\EOF
+heads/master
+master
+testtag
+EOF
+
+test_expect_success 'Check short refname format with wildcard pattern' '
+ (git for-each-ref --format="%(refname:short)" refs/*/m* &&
+ git for-each-ref --format="%(refname:short)" refs/heads/?aster &&
+ git for-each-ref --format="%(refname:short)" refs/tags/t[aeiou]sttag) >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<\EOF
+refs/heads/master
+EOF
+
+test_expect_success 'Check disabled short refname format with exact pattern' '
+ (git for-each-ref --format="%(refname:short)" refs/heads/master) >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'an unusual tag with an incomplete line' '
git tag -m "bogo" bogo &&
--
tg: (445cac1..) t/for-each-ref-refshort (depends on: master)
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic