From 58a05c74e7a9341af80eb98731d6b0dafe1b5c29 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Mon, 12 Oct 2009 00:27:04 -0500 Subject: [PATCH 1/3] Add tests for git check-ref-format The "git check-ref-format" command is a basic command various porcelains rely on. Test its functionality to make sure it does not unintentionally change. Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- t/t1402-check-ref-format.sh | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 t/t1402-check-ref-format.sh diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh new file mode 100644 index 0000000000..382bc6e823 --- /dev/null +++ b/t/t1402-check-ref-format.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +test_description='Test git check-ref-format' + +. ./test-lib.sh + +valid_ref() { + test_expect_success "ref name '$1' is valid" \ + "git check-ref-format '$1'" +} +invalid_ref() { + test_expect_success "ref name '$1' is not valid" \ + "test_must_fail git check-ref-format '$1'" +} + +valid_ref 'heads/foo' +invalid_ref 'foo' +valid_ref 'foo/bar/baz' +valid_ref 'refs///heads/foo' +invalid_ref 'heads/foo/' +invalid_ref './foo' +invalid_ref '.refs/foo' +invalid_ref 'heads/foo..bar' +invalid_ref 'heads/foo?bar' +valid_ref 'foo./bar' +invalid_ref 'heads/foo.lock' +valid_ref 'heads/foo@bar' +invalid_ref 'heads/v@{ation' +invalid_ref 'heads/foo\bar' + +test_expect_success "check-ref-format --branch @{-1}" ' + T=$(git write-tree) && + sha1=$(echo A | git commit-tree $T) && + git update-ref refs/heads/master $sha1 && + git update-ref refs/remotes/origin/master $sha1 + git checkout master && + git checkout origin/master && + git checkout master && + refname=$(git check-ref-format --branch @{-1}) && + test "$refname" = "$sha1" && + refname2=$(git check-ref-format --branch @{-2}) && + test "$refname2" = master' + +test_done From 38eedc634bc5d30e8a7a2356d9eb3ae95d9b1d75 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 12 Oct 2009 16:39:43 -0700 Subject: [PATCH 2/3] git check-ref-format --print Tolerating empty path components in ref names means each ref does not have a unique name. This creates difficulty for porcelains that want to see if two branches are equal. Add a helper associating to each ref a canonical name. If a user asks a porcelain to create a ref "refs/heads//master", the porcelain can run "git check-ref-format --print refs/heads//master" and only deal with "refs/heads/master" from then on. Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- Documentation/git-check-ref-format.txt | 23 ++++++++++++++++++----- builtin-check-ref-format.c | 10 ++++++++++ t/t1402-check-ref-format.sh | 17 +++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index 0b7982ea76..211ae1c3fa 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -9,6 +9,7 @@ SYNOPSIS -------- [verse] 'git check-ref-format' +'git check-ref-format' --print 'git check-ref-format' [--branch] DESCRIPTION @@ -63,16 +64,28 @@ reference name expressions (see linkgit:git-rev-parse[1]): . at-open-brace `@{` is used as a notation to access a reflog entry. +With the `--print` option, if 'refname' is acceptable, it prints the +canonicalized name of a hypothetical reference with that name. That is, +it prints 'refname' with any extra `/` characters removed. + With the `--branch` option, it expands a branch name shorthand and prints the name of the branch the shorthand refers to. -EXAMPLE -------- +EXAMPLES +-------- -git check-ref-format --branch @{-1}:: - -Print the name of the previous branch. +* Print the name of the previous branch: ++ +------------ +$ git check-ref-format --branch @{-1} +------------ +* Determine the reference name to use for a new branch: ++ +------------ +$ ref=$(git check-ref-format --print "refs/heads/$newbranch") || +die "we do not like '$newbranch' as a branch name." +------------ GIT --- diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c index f9381e07ea..b97b61a0a4 100644 --- a/builtin-check-ref-format.c +++ b/builtin-check-ref-format.c @@ -17,6 +17,16 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix) printf("%s\n", sb.buf + 11); exit(0); } + if (argc == 3 && !strcmp(argv[1], "--print")) { + char *refname = xmalloc(strlen(argv[2]) + 1); + + if (check_ref_format(argv[2])) + exit(1); + if (normalize_path_copy(refname, argv[2])) + die("Could not normalize ref name '%s'", argv[2]); + printf("%s\n", refname); + exit(0); + } if (argc != 2) usage("git check-ref-format refname"); return !!check_ref_format(argv[1]); diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh index 382bc6e823..eb45afb018 100644 --- a/t/t1402-check-ref-format.sh +++ b/t/t1402-check-ref-format.sh @@ -41,4 +41,21 @@ test_expect_success "check-ref-format --branch @{-1}" ' refname2=$(git check-ref-format --branch @{-2}) && test "$refname2" = master' +valid_ref_normalized() { + test_expect_success "ref name '$1' simplifies to '$2'" " + refname=\$(git check-ref-format --print '$1') && + test \"\$refname\" = '$2'" +} +invalid_ref_normalized() { + test_expect_success "check-ref-format --print rejects '$1'" " + test_must_fail git check-ref-format --print '$1'" +} + +valid_ref_normalized 'heads/foo' 'heads/foo' +valid_ref_normalized 'refs///heads/foo' 'refs/heads/foo' +invalid_ref_normalized 'foo' +invalid_ref_normalized 'heads/foo/../bar' +invalid_ref_normalized 'heads/./foo' +invalid_ref_normalized 'heads\foo' + test_done From 1ba447b8dc2ec4e6c8ebbbdaa449f38edc29ad3f Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Mon, 12 Oct 2009 00:33:01 -0500 Subject: [PATCH 3/3] check-ref-format: simplify --print implementation normalize_path_copy() is a complicated function, but most of its functionality will never apply to a ref name that has been checked with check_ref_format(). Signed-off-by: Jonathan Nieder Signed-off-by: Junio C Hamano --- builtin-check-ref-format.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c index b97b61a0a4..e3e7bdf52f 100644 --- a/builtin-check-ref-format.c +++ b/builtin-check-ref-format.c @@ -7,6 +7,28 @@ #include "builtin.h" #include "strbuf.h" +/* + * Replace each run of adjacent slashes in src with a single slash, + * and write the result to dst. + * + * This function is similar to normalize_path_copy(), but stripped down + * to meet check_ref_format's simpler needs. + */ +static void collapse_slashes(char *dst, const char *src) +{ + char ch; + char prev = '\0'; + + while ((ch = *src++) != '\0') { + if (prev == '/' && ch == prev) + continue; + + *dst++ = ch; + prev = ch; + } + *dst = '\0'; +} + int cmd_check_ref_format(int argc, const char **argv, const char *prefix) { if (argc == 3 && !strcmp(argv[1], "--branch")) { @@ -22,8 +44,7 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix) if (check_ref_format(argv[2])) exit(1); - if (normalize_path_copy(refname, argv[2])) - die("Could not normalize ref name '%s'", argv[2]); + collapse_slashes(refname, argv[2]); printf("%s\n", refname); exit(0); }