{"thread":{"id":"2078","subject":"[PATCH] Add git-findtags","startedAt":"2005-10-12T03:19:29Z","lastAt":"2005-10-13T05:18:00Z","messageCount":3,"participants":["Martin Langhoff","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"9992","messageId":"1129087169926-git-send-email-martin@catalyst.net.nz","threadId":"2078","inReplyTo":null,"subject":"[PATCH] Add git-findtags","fromName":"Martin Langhoff","fromEmail":"martin@catalyst.net.nz","sentAt":"2005-10-12T03:19:29Z","receivedAt":"2005-10-12T03:19:29Z","isPatch":true,"sender":{"key":"martin@laptop.org","avatar":null},"body":"A short perl script that will walk the tag refs, tag objects, and even commit\nobjects in its quest to figure out whether the given SHA1 (for a commit or\ntree) was ever tagged.\n\nUsage: git-findtags.perl [ -t ] <commit-or-tree-sha1>\n\nSigned-off-by: Martin Langhoff <martin@catalyst.net.nz>\n\n\n---\n\n Makefile          |    3 ++\n git-findtags.perl |   70 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 72 insertions(+), 1 deletions(-)\n create mode 100755 git-findtags.perl\n\napplies-to: ef9b5c2cb61cf509adf2f5ef37fa1db517291f48\n58597ae99b77a690a788d2f096cecc1b7ae809fd\ndiff --git a/Makefile b/Makefile\nindex 8697d52..a5d9cd4 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -93,7 +93,8 @@ SCRIPT_SH = \\\n \n SCRIPT_PERL = \\\n \tgit-archimport.perl git-cvsimport.perl git-relink.perl \\\n-\tgit-rename.perl git-shortlog.perl git-fmt-merge-msg.perl\n+\tgit-rename.perl git-shortlog.perl git-fmt-merge-msg.perl \\\n+\tgit-findtags.perl\n \n SCRIPT_PYTHON = \\\n \tgit-merge-recursive.py\ndiff --git a/git-findtags.perl b/git-findtags.perl\nnew file mode 100755\nindex 0000000..40eb284\n--- /dev/null\n+++ b/git-findtags.perl\n@@ -0,0 +1,70 @@\n+#!/usr/bin/perl -w\n+#\n+# Copyright (c) 2005 Martin Langhoff\n+#\n+# Walk the tags and find if they match a commit\n+# expects a SHA1 of a commit. Option -t enables \n+# searching trees too.\n+#\n+\n+use strict;\n+use File::Basename;\n+use Getopt::Std;\n+\n+my $git_dir = $ENV{GIT_DIR} || '.git';\n+\n+# options\n+our $opt_t;\n+getopts(\"t\") || usage();\n+\n+my @tagfiles   = `find $git_dir/refs/tags -follow -type f`; # haystack\n+my $target = shift @ARGV;                     # needle\n+\n+unless ($target) { \n+    usage();\n+}\n+\n+\n+foreach my $tagfile (@tagfiles) {\n+    chomp $tagfile;\n+    my $tagid = quickread($tagfile);\n+    chomp $tagid;\n+\n+    # grab the first 2 lines (the whole tag could be large)\n+    my $tagobj = `git-cat-file tag $tagid | head -n2 `;\n+    if ($tagobj =~  m/^type commit$/m) { # only deal with commits\n+\n+\tif ($tagobj =~ m/^object $target$/m) { # match on the commit\n+\t    print basename($tagfile) . \"\\n\";\n+\n+\t} elsif ( $opt_t &&                      # follow the commit\n+\t\t $tagobj =~ m/^object (\\S+)$/m) { # and try to match trees\n+\t    my $commitid = $1;\n+\t    my $commitobj = `git-cat-file commit $commitid | head -n1`;\n+\t    chomp $commitobj;\n+\t    $commitobj =~ m/^tree (\\S+)$/;\n+\t    my $treeid = $1;\n+\t    if ($target eq $treeid) {\n+\t\tprint  basename($tagfile) . \"\\n\";\n+\t    }\n+\t}\n+    }\n+}\n+\n+sub quickread {\n+    my $file = shift;\n+    local $/; undef $/; # slurp mode\n+    open FILE, \"<$file\"\n+\tor die \"Cannot open $file : $!\";\n+    my $content = <FILE>;\n+    close FILE;\n+    return $content;\n+}\n+\n+sub usage {\n+\tprint STDERR <<END;\n+Usage: ${\\basename $0}     # find tags for a commit or tree\n+       [ -t ] <commit-or-tree-sha1>\n+END\n+\texit(1);\n+}\n---\n0.99.8.GIT\n"},{"id":"9999","messageId":"7vek6rmhw5.fsf@assigned-by-dhcp.cox.net","threadId":"2078","inReplyTo":"1129087169926-git-send-email-martin@catalyst.net.nz","subject":"Re: [PATCH] Add git-findtags","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-12T05:19:38Z","receivedAt":"2005-10-12T05:19:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin Langhoff <martin@catalyst.net.nz> writes:\n\n> +my @tagfiles   = `find $git_dir/refs/tags -follow -type f`; # haystack\n\nPlease do this with File::Find(), unless you have a compelling\nreason not to.  $git_dir could contain shell metacharacters\nand/or whitespace.\n\n> +    # grab the first 2 lines (the whole tag could be large)\n> +    my $tagobj = `git-cat-file tag $tagid | head -n2 `;\n\nCareful; $tagfile could be a lightweight tag, and you would want\nto consider it a hit if ($tagid eq $target).\n\nBTW, does `` in Perl behave well upon SIGPIPE (hehe, we now have\nMerlyn on the list so I can ask these silly Perl questions ;-))?\n\n> +    if ($tagobj =~  m/^type commit$/m) { # only deal with commits\n> +\n> +\tif ($tagobj =~ m/^object $target$/m) { # match on the commit\n> +\t    print basename($tagfile) . \"\\n\";\n\nPlease show \"tags/bl/ah\" when \".git/refs/tags/bl/ah\" points at\nthe target, not just \"ah\".  Alternatively, \"bl/ah\" may also be\nacceptable, since this command is about tags.\n\n> +\t} elsif ( $opt_t &&                      # follow the commit\n> +\t\t $tagobj =~ m/^object (\\S+)$/m) { # and try to match trees\n\nI am not sure how useful '-t' would be in practice.  If it is, I\nwonder if it would also be useful to look for a subtree match..\n\n> +sub quickread {\n> +    my $file = shift;\n> +    local $/; undef $/; # slurp mode\n\nNit -- \"local $/;\" without \"undef $/;\" would do just fine.\n\nBTW, wouldn't it be easier for this particular script, and more\nuseful in general, if something like what 'git-rev-parse' does\nfor commit objects when given \"REV^0\" is supported for tags?\n\nI am uncertain the about syntax/notation, but just like \"^0\" is\na postfix operator for \"peel the onion repeatedly until you get\na commit, or barf if you ended up with a non-commit\", maybe if\nwe had \"peel the onion repeatedly until you get a non-tag\"\noperator, let's call it '%', then you could say something like\nthis:\n\n        # This is pseudo-code -- it does not handle tagname with\n        # embedded $IFS letter very well.\n\n        # list local refs\n\tgit-rev-parse --symbolic --all |\n\n        # limit only to tags\n        sed -ne '/^refs\\/tags\\/p' |\n        while read tagname\n        do\n        \tif test $(git-rev-parse --verify \"${tagname}%\") = \"$target\"\n\t\tthen\n                \techo \"$tagname\"\n\t\tfi\n\tdone\n"},{"id":"10053","messageId":"7vbr1u6lmf.fsf@assigned-by-dhcp.cox.net","threadId":"2078","inReplyTo":"46a038f90510122117mb466722n531dc66bac141ea1@mail.gmail.com","subject":"Re: [PATCH] Add git-findtags","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-13T05:18:00Z","receivedAt":"2005-10-13T05:18:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin Langhoff <martin.langhoff@gmail.com> writes:\n\n> On 10/12/05, Junio C Hamano <junkio@cox.net> wrote:\n>> Martin Langhoff <martin@catalyst.net.nz> writes:\n>\n> I'm preparing a better patch based on your comments, but File::Find is\n> _not_ my friend, really. I really feel stupid after failing for 1hr to\n> use it.\n\nSomething like this?\n\n    use strict;\n    use File::Find qw(find);\n\n    my $git_dir = $ENV{GIT_DIR} || '.git';\n\n    my @tagfiles = ();\n    find({\n        follow => 1,\n        wanted => sub {\n            if (-f _) {\n                push @tagfiles, $File::Find::name;\n            }\n        } }, \"$git_dir/refs/tags\");\n\n    for (@tagfiles) {\n        print \"$_\\n\";\n    }\n\n>> BTW, wouldn't it be easier for this particular script, and more\n>> useful in general, if something like what 'git-rev-parse' does\n>> for commit objects when given \"REV^0\" is supported for tags?\n>\n> I don't quite follow...\n\nWhat I meant is this.\n\nThere is an existing notation \"^0\" which is a postfix\n\"dereference until you get a commit\" operator.\n\n\tgit-rev-parse --verify refs/tags/v0.99^0\n\tgit-cat-file -t refs/tags/v0.99^0\n\ndoes:\n\n\t1. reads SHA1 from \"refs/tags/v0.99\", finds the object;\n\n        2. if it is a tag object, find the object pointed by it;\n           if the result is still a tag object, then dereference\n           it repeatedly;\n\n        3. if the resulting object is a commit, let the caller\n           to use it; otherwise barf.\n\nWhat _might_ be useful for your application is a similar\noperator, say, \"refs/tags/junio-gpg-pub%\", that does:\n\n\t1. reads SHA1 from \"refs/tags/junio-gpg-pub\", finds the\n           object;\n\n        2. if it is a tag object, find the object pointed by it;\n           if the result is still a tag object, then dereference\n           it repeatedly;\n\n\t3. do not worry about the type of the result.  Just\n           output it.\n\nInstead of reserving yet another letter '%', it might be better\nto use something like \"refs/tags/junio-gpg-pub^{tag}\" as a\nnotation for this.  If you had something like this, you would\nnot have to read tag objects yourself and dereference them by\nhand.\n"}]}