From 358ddb62cfd03bba1ca2f1ae8e81b9510f42ea9a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 15 Sep 2006 11:19:32 -0700 Subject: [PATCH 1/8] Add "git show-ref" builtin command It's kind of like "git peek-remote", but works only locally (and thus avoids the whole overhead of git_connect()) and has some extra verification features. For example, it allows you to filter the results, and to choose whether you want the tag dereferencing or not. You can also use it to just test whether a particular ref exists. For example: git show-ref master will show all references called "master", whether tags or heads or anything else, and regardless of how deep in the reference naming hierarchy they are (so it would show "refs/heads/master" but also "refs/remote/other-repo/master"). When using the "--verify" flag, the command requires an exact ref path: git show-ref --verify refs/heads/master will only match the exact branch called "master". If nothing matches, show-ref will return an error code of 1, and in the case of verification, it will show an error message. For scripting, you can ask it to be quiet with the "--quiet" flag, which allows you to do things like git-show-ref --quiet --verify -- "refs/heads/$headname" || echo "$headname is not a valid branch" to check whether a particular branch exists or not (notice how we don't actually want to show any results, and we want to use the full refname for it in order to not trigger the problem with ambiguous partial matches). To show only tags, or only proper branch heads, use "--tags" and/or "--heads" respectively (using both means that it shows tags _and_ heads, but not other random references under the refs/ subdirectory). To do automatic tag object dereferencing, use the "-d" or "--dereference" flag, so you can do git show-ref --tags --dereference to get a listing of all tags together with what they dereference. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- Makefile | 3 +- builtin-show-ref.c | 112 +++++++++++++++++++++++++++++++++++++++++++++ builtin.h | 1 + git.c | 1 + 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 builtin-show-ref.c diff --git a/Makefile b/Makefile index 7b3114f3aa..c3651384c2 100644 --- a/Makefile +++ b/Makefile @@ -295,7 +295,8 @@ BUILTIN_OBJS = \ builtin-upload-tar.o \ builtin-verify-pack.o \ builtin-write-tree.o \ - builtin-zip-tree.o + builtin-zip-tree.o \ + builtin-show-ref.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz diff --git a/builtin-show-ref.c b/builtin-show-ref.c new file mode 100644 index 0000000000..161b2367ea --- /dev/null +++ b/builtin-show-ref.c @@ -0,0 +1,112 @@ +#include "cache.h" +#include "refs.h" +#include "object.h" +#include "tag.h" + +static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--deref] [--tags] [--heads] [--] [pattern*]"; + +static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0, found_match = 0, verify = 0, quiet = 0; +static const char **pattern; + +static int show_ref(const char *refname, const unsigned char *sha1) +{ + struct object *obj; + + if (tags_only || heads_only) { + int match; + + match = heads_only && !strncmp(refname, "refs/heads/", 11); + match |= tags_only && !strncmp(refname, "refs/tags/", 10); + if (!match) + return 0; + } + if (pattern) { + int reflen = strlen(refname); + const char **p = pattern, *m; + while ((m = *p++) != NULL) { + int len = strlen(m); + if (len > reflen) + continue; + if (memcmp(m, refname + reflen - len, len)) + continue; + if (len == reflen) + goto match; + /* "--verify" requires an exact match */ + if (verify) + continue; + if (refname[reflen - len - 1] == '/') + goto match; + } + return 0; + } + +match: + found_match++; + obj = parse_object(sha1); + if (!obj) { + if (quiet) + return 0; + die("git-show-ref: bad ref %s (%s)", refname, sha1_to_hex(sha1)); + } + if (quiet) + return 0; + printf("%s %s\n", sha1_to_hex(sha1), refname); + if (deref_tags && obj->type == OBJ_TAG) { + obj = deref_tag(obj, refname, 0); + printf("%s %s^{}\n", sha1_to_hex(obj->sha1), refname); + } + return 0; +} + +int cmd_show_ref(int argc, const char **argv, const char *prefix) +{ + int i; + + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (*arg != '-') { + pattern = argv + i; + break; + } + if (!strcmp(arg, "--")) { + pattern = argv + i + 1; + if (!*pattern) + pattern = NULL; + break; + } + if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet")) { + quiet = 1; + continue; + } + if (!strcmp(arg, "-h") || !strcmp(arg, "--head")) { + show_head = 1; + continue; + } + if (!strcmp(arg, "-d") || !strcmp(arg, "--dereference")) { + deref_tags = 1; + continue; + } + if (!strcmp(arg, "--verify")) { + verify = 1; + continue; + } + if (!strcmp(arg, "--tags")) { + tags_only = 1; + continue; + } + if (!strcmp(arg, "--heads")) { + heads_only = 1; + continue; + } + usage(show_ref_usage); + } + if (show_head) + head_ref(show_ref); + for_each_ref(show_ref); + if (!found_match) { + if (verify && !quiet) + die("No match"); + return 1; + } + return 0; +} diff --git a/builtin.h b/builtin.h index 398eafbf99..a7242beebb 100644 --- a/builtin.h +++ b/builtin.h @@ -60,5 +60,6 @@ extern int cmd_version(int argc, const char **argv, const char *prefix); extern int cmd_whatchanged(int argc, const char **argv, const char *prefix); extern int cmd_write_tree(int argc, const char **argv, const char *prefix); extern int cmd_verify_pack(int argc, const char **argv, const char *prefix); +extern int cmd_show_ref(int argc, const char **argv, const char *prefix); #endif diff --git a/git.c b/git.c index 8c182a5f55..fedd53683e 100644 --- a/git.c +++ b/git.c @@ -266,6 +266,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER }, { "write-tree", cmd_write_tree, RUN_SETUP }, { "verify-pack", cmd_verify_pack }, + { "show-ref", cmd_show_ref, RUN_SETUP }, }; int i; From 305e22c36e674924de6decb29e8a4c22292b5054 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 15 Sep 2006 14:56:55 -0700 Subject: [PATCH 2/8] Teach "git checkout" to use git-show-ref That way, it doesn't care how the refs are stored any more Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- git-checkout.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-checkout.sh b/git-checkout.sh index 580a9e8a23..f03620b054 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -22,7 +22,7 @@ while [ "$#" != "0" ]; do shift [ -z "$newbranch" ] && die "git checkout: -b needs a branch name" - [ -e "$GIT_DIR/refs/heads/$newbranch" ] && + git-show-ref --verify --quiet -- "refs/heads/$newbranch" && die "git checkout: branch $newbranch already exists" git-check-ref-format "heads/$newbranch" || die "git checkout: we do not like '$newbranch' as a branch name." @@ -51,7 +51,8 @@ while [ "$#" != "0" ]; do fi new="$rev" new_name="$arg^0" - if [ -f "$GIT_DIR/refs/heads/$arg" ]; then + if git-show-ref --verify --quiet -- "refs/heads/$arg" + then branch="$arg" fi elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null) From c40abef89f746ef7b9b7815b12b740e2f22905c8 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Sun, 17 Sep 2006 06:20:24 +0200 Subject: [PATCH 3/8] Add [-s|--hash] option to Linus' show-ref. With this option only the sha1 hash of the ref should be printed. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- builtin-show-ref.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/builtin-show-ref.c b/builtin-show-ref.c index 161b2367ea..577d934273 100644 --- a/builtin-show-ref.c +++ b/builtin-show-ref.c @@ -3,9 +3,10 @@ #include "object.h" #include "tag.h" -static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--deref] [--tags] [--heads] [--] [pattern*]"; +static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--deref] [-s|--hash] [--tags] [--heads] [--] [pattern*]"; -static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0, found_match = 0, verify = 0, quiet = 0; +static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0, + found_match = 0, verify = 0, quiet = 0, hash_only = 0; static const char **pattern; static int show_ref(const char *refname, const unsigned char *sha1) @@ -50,7 +51,10 @@ match: } if (quiet) return 0; - printf("%s %s\n", sha1_to_hex(sha1), refname); + if (hash_only) + printf("%s\n", sha1_to_hex(sha1)); + else + printf("%s %s\n", sha1_to_hex(sha1), refname); if (deref_tags && obj->type == OBJ_TAG) { obj = deref_tag(obj, refname, 0); printf("%s %s^{}\n", sha1_to_hex(obj->sha1), refname); @@ -86,6 +90,10 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix) deref_tags = 1; continue; } + if (!strcmp(arg, "-s") || !strcmp(arg, "--hash")) { + hash_only = 1; + continue; + } if (!strcmp(arg, "--verify")) { verify = 1; continue; From ee1a9b2f1824100bbac8d23e7dea1a6e9e85fb21 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Sun, 17 Sep 2006 06:32:24 +0200 Subject: [PATCH 4/8] Use Linus' show ref in "git-branch.sh". Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- git-branch.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-branch.sh b/git-branch.sh index e0501ec23f..2600e9c4a8 100755 --- a/git-branch.sh +++ b/git-branch.sh @@ -21,7 +21,7 @@ delete_branch () { ,,) die "What branch are you on anyway?" ;; esac - branch=$(cat "$GIT_DIR/refs/heads/$branch_name") && + branch=$(git-show-ref --verify --hash -- "refs/heads/$branch_name") && branch=$(git-rev-parse --verify "$branch^0") || die "Seriously, what branch are you talking about?" case "$option" in @@ -112,7 +112,7 @@ rev=$(git-rev-parse --verify "$head") || exit git-check-ref-format "heads/$branchname" || die "we do not like '$branchname' as a branch name." -if [ -e "$GIT_DIR/refs/heads/$branchname" ] +if git-show-ref --verify --quiet -- "refs/heads/$branchname" then if test '' = "$force" then From 582c5b09be6336e74a366ad900ca7ec3a5d1572d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 18 Sep 2006 00:35:07 -0700 Subject: [PATCH 5/8] gitignore: git-show-ref is a generated file. Signed-off-by: Junio C Hamano --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0d608fe12a..f53e0b247c 100644 --- a/.gitignore +++ b/.gitignore @@ -102,6 +102,7 @@ git-shortlog git-show git-show-branch git-show-index +git-show-ref git-ssh-fetch git-ssh-pull git-ssh-push From c0990ff36f0b9b8e806c8f649a0888d05bb22c37 Mon Sep 17 00:00:00 2001 From: Jonas Fonseca Date: Mon, 18 Sep 2006 14:32:41 +0200 Subject: [PATCH 6/8] Add man page for git-show-ref Signed-off-by: Jonas Fonseca Signed-off-by: Junio C Hamano --- Documentation/git-show-ref.txt | 136 +++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 Documentation/git-show-ref.txt diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt new file mode 100644 index 0000000000..529ea17c90 --- /dev/null +++ b/Documentation/git-show-ref.txt @@ -0,0 +1,136 @@ +git-show-ref(1) +=============== + +NAME +---- +git-show-ref - List references in a local repository + +SYNOPSIS +-------- +[verse] +'git-show-ref' [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] + [--tags] [--heads] [--] ... + +DESCRIPTION +----------- + +Displays references available in a local repository along with the associated +commit IDs. Results can be filtered using a pattern and tags can be +dereferenced into object IDs. Additionally, it can be used to test whether a +particular ref exists. + +Use of this utility is encouraged in favor of directly accessing files under +in the `.git` directory. + +OPTIONS +------- + +-h, --head:: + + Show the HEAD reference. + +--tags, --heads:: + + Limit to only "refs/heads" and "refs/tags", respectively. These + options are not mutually exclusive; when given both, references stored + in "refs/heads" and "refs/tags" are displayed. + +-d, --dereference:: + + Dereference tags into object IDs. They will be shown with "^{}" + appended. + +--verify:: + + Enable stricter reference checking by requiring an exact ref path. + Aside from returning an error code of 1, it will also print an error + message if '--quiet' was not specified. + +-q, --quiet:: + + Do not print any results to stdout. When combined with '--verify' this + can be used to silently check if a reference exists. + +:: + + Show references matching one or more patterns. + +OUTPUT +------ + +The output is in the format: '' '' ''. + +----------------------------------------------------------------------------- +$ git show-ref --head --dereference +832e76a9899f560a90ffd62ae2ce83bbeff58f54 HEAD +832e76a9899f560a90ffd62ae2ce83bbeff58f54 refs/heads/master +832e76a9899f560a90ffd62ae2ce83bbeff58f54 refs/heads/origin +3521017556c5de4159da4615a39fa4d5d2c279b5 refs/tags/v0.99.9c +6ddc0964034342519a87fe013781abf31c6db6ad refs/tags/v0.99.9c^{} +055e4ae3ae6eb344cbabf2a5256a49ea66040131 refs/tags/v1.0rc4 +423325a2d24638ddcc82ce47be5e40be550f4507 refs/tags/v1.0rc4^{} +... +----------------------------------------------------------------------------- + +EXAMPLE +------- + +To show all references called "master", whether tags or heads or anything +else, and regardless of how deep in the reference naming hierarchy they are, +use: + +----------------------------------------------------------------------------- + git show-ref master +----------------------------------------------------------------------------- + +This will show "refs/heads/master" but also "refs/remote/other-repo/master", +if such references exists. + +When using the '--verify' flag, the command requires an exact path: + +----------------------------------------------------------------------------- + git show-ref --verify refs/heads/master +----------------------------------------------------------------------------- + +will only match the exact branch called "master". + +If nothing matches, gitlink:git-show-ref[1] will return an error code of 1, +and in the case of verification, it will show an error message. + +For scripting, you can ask it to be quiet with the "--quiet" flag, which +allows you to do things like + +----------------------------------------------------------------------------- + git-show-ref --quiet --verify -- "refs/heads/$headname" || + echo "$headname is not a valid branch" +----------------------------------------------------------------------------- + +to check whether a particular branch exists or not (notice how we don't +actually want to show any results, and we want to use the full refname for it +in order to not trigger the problem with ambiguous partial matches). + +To show only tags, or only proper branch heads, use "--tags" and/or "--heads" +respectively (using both means that it shows tags and heads, but not other +random references under the refs/ subdirectory). + +To do automatic tag object dereferencing, use the "-d" or "--dereference" +flag, so you can do + +----------------------------------------------------------------------------- + git show-ref --tags --dereference +----------------------------------------------------------------------------- + +to get a listing of all tags together with what they dereference. + +SEE ALSO +-------- +gitlink:git-ls-remote[1], gitlink:git-peek-remote[1] + +AUTHORS +------- +Written by Linus Torvalds . +Man page by Jonas Fonseca . + +GIT +--- +Part of the gitlink:git[7] suite From 9581e0fca225927dbcbdf03fe70a1d2711ddc6b9 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Wed, 20 Sep 2006 06:14:54 +0200 Subject: [PATCH 7/8] Document git-show-ref [-s|--hash] option. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- Documentation/git-show-ref.txt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt index 529ea17c90..b724d832c8 100644 --- a/Documentation/git-show-ref.txt +++ b/Documentation/git-show-ref.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git-show-ref' [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] - [--tags] [--heads] [--] ... + [-s|--hash] [--tags] [--heads] [--] ... DESCRIPTION ----------- @@ -40,6 +40,12 @@ OPTIONS Dereference tags into object IDs. They will be shown with "^{}" appended. +-s, --hash:: + + Only show the SHA1 hash, not the reference name. When also using + --dereference the dereferenced tag will still be shown after the SHA1, + this maybe a bug. + --verify:: Enable stricter reference checking by requiring an exact ref path. @@ -72,6 +78,16 @@ $ git show-ref --head --dereference ... ----------------------------------------------------------------------------- +When using --hash (and not --dereference) the output format is: '' + +----------------------------------------------------------------------------- +$ git show-ref --heads --hash +2e3ba0114a1f52b47df29743d6915d056be13278 +185008ae97960c8d551adcd9e23565194651b5d1 +03adf42c988195b50e1a1935ba5fcbc39b2b029b +... +----------------------------------------------------------------------------- + EXAMPLE ------- From 9c13359aaf3176428603cc9dfbdf30da889ab3d3 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Wed, 20 Sep 2006 06:21:25 +0200 Subject: [PATCH 8/8] Fix show-ref usage for --dereference. Signed-off-by: Christian Couder Signed-off-by: Junio C Hamano --- builtin-show-ref.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-show-ref.c b/builtin-show-ref.c index 577d934273..fab359bb42 100644 --- a/builtin-show-ref.c +++ b/builtin-show-ref.c @@ -3,7 +3,7 @@ #include "object.h" #include "tag.h" -static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--deref] [-s|--hash] [--tags] [--heads] [--] [pattern*]"; +static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash] [--tags] [--heads] [--] [pattern*]"; static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0, found_match = 0, verify = 0, quiet = 0, hash_only = 0;