Change the revision parsing logic to match ^{commit}, ^{tree}, ^{blob} etc. case-insensitively. Before this change supplying anything except the lower-case forms emits an "unknown revision or path not in the working tree" error. This change makes upper-case & mixed-case versions equivalent to the lower-case versions. The rationale for this change is the same as for making @{upstream} and related suffixes case-insensitive in "rev-parse: match @{upstream}, @{u} and @{push} case-insensitively", but unlike those suffixes this change introduces the potential confusion of accepting TREE or BLOB here, but not as an argument to e.g. "cat-file -t <type>" or "hash-object -t <type>". Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> --- Documentation/revisions.txt | 5 +++++ git-compat-util.h | 1 + sha1_name.c | 10 +++++----- strbuf.c | 9 +++++++++ t/t1450-fsck.sh | 7 +++++++ t/t1511-rev-parse-caret.sh | 13 +++++++++++++ 6 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt index 5fe90e411d..136e26c05d 100644 --- a/Documentation/revisions.txt +++ b/Documentation/revisions.txt @@ -162,6 +162,11 @@ it does not have to be dereferenced even once to get to an object. + 'rev{caret}\{tag\}' can be used to ensure that 'rev' identifies an existing tag object. ++ +The {caret}{<type>} part is matched case-insensitively. So +e.g. '{caret}\{commit\}' can be equivalently specified as +'{caret}\{COMMIT\}', '{caret}\{Commit\}' etc., '{caret}\{tree\}' as +'{caret}\{TREE\}' and so forth. '<rev>{caret}{}', e.g. 'v0.99.8{caret}{}':: A suffix '{caret}' followed by an empty brace pair diff --git a/git-compat-util.h b/git-compat-util.h index 8a4a3f85e7..4a03934ef3 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -448,6 +448,7 @@ extern void set_die_is_recursing_routine(int (*routine)(void)); extern void set_error_handle(FILE *); extern int starts_with(const char *str, const char *prefix); +extern int starts_with_icase(const char *str, const char *prefix); /* * If the string "str" begins with the string found in "prefix", return 1. diff --git a/sha1_name.c b/sha1_name.c index 2deb9bfdf6..107246bd2d 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -821,15 +821,15 @@ static int peel_onion(const char *name, int len, unsigned char *sha1, return -1; sp++; /* beginning of type name, or closing brace for empty */ - if (starts_with(sp, "commit}")) + if (starts_with_icase(sp, "commit}")) expected_type = OBJ_COMMIT; - else if (starts_with(sp, "tag}")) + else if (starts_with_icase(sp, "tag}")) expected_type = OBJ_TAG; - else if (starts_with(sp, "tree}")) + else if (starts_with_icase(sp, "tree}")) expected_type = OBJ_TREE; - else if (starts_with(sp, "blob}")) + else if (starts_with_icase(sp, "blob}")) expected_type = OBJ_BLOB; - else if (starts_with(sp, "object}")) + else if (starts_with_icase(sp, "object}")) expected_type = OBJ_ANY; else if (sp[0] == '}') expected_type = OBJ_NONE; diff --git a/strbuf.c b/strbuf.c index ace58e7367..7d4a59bca6 100644 --- a/strbuf.c +++ b/strbuf.c @@ -11,6 +11,15 @@ int starts_with(const char *str, const char *prefix) return 0; } +int starts_with_icase(const char *str, const char *prefix) +{ + for (; ; str++, prefix++) + if (!*prefix) + return 1; + else if (tolower(*str) != tolower(*prefix)) + return 0; +} + /* * Used as the default ->buf value, so that people can always assume * buf is non NULL and ->buf is NUL terminated even for a freshly diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 33a51c9a67..b6c1989671 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -505,6 +505,13 @@ test_expect_success 'fsck notices missing tagged object' ' test_must_fail git -C missing fsck ' +test_expect_success 'fsck notices missing tagged object with case insensitive {blob}' ' + create_repo_missing tag^{BLOB} && + test_must_fail git -C missing fsck && + create_repo_missing tag^{BloB} && + test_must_fail git -C missing fsck +' + test_expect_success 'fsck notices ref pointing to missing commit' ' create_repo_missing HEAD && test_must_fail git -C missing fsck diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh index e0a49a651f..56750f99c6 100755 --- a/t/t1511-rev-parse-caret.sh +++ b/t/t1511-rev-parse-caret.sh @@ -48,6 +48,10 @@ test_expect_success 'ref^{commit}' ' git rev-parse ref >expected && git rev-parse ref^{commit} >actual && test_cmp expected actual && + git rev-parse ref^{COMMIT} >actual && + test_cmp expected actual && + git rev-parse ref^{CoMMiT} >actual && + test_cmp expected actual && git rev-parse commit-tag^{commit} >actual && test_cmp expected actual && test_must_fail git rev-parse tree-tag^{commit} && @@ -58,6 +62,10 @@ test_expect_success 'ref^{tree}' ' echo $TREE_SHA1 >expected && git rev-parse ref^{tree} >actual && test_cmp expected actual && + git rev-parse ref^{TREE} >actual && + test_cmp expected actual && + git rev-parse ref^{TrEe} >actual && + test_cmp expected actual && git rev-parse commit-tag^{tree} >actual && test_cmp expected actual && git rev-parse tree-tag^{tree} >actual && @@ -67,8 +75,13 @@ test_expect_success 'ref^{tree}' ' test_expect_success 'ref^{tag}' ' test_must_fail git rev-parse HEAD^{tag} && + test_must_fail git rev-parse HEAD^{TAG} && git rev-parse commit-tag >expected && git rev-parse commit-tag^{tag} >actual && + test_cmp expected actual && + git rev-parse commit-tag^{TAG} >actual && + test_cmp expected actual && + git rev-parse commit-tag^{Tag} >actual && test_cmp expected actual ' -- 2.11.0