From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jake Goulding Subject: [PATCH 3/3] Add --contains flag to git tag Date: Thu, 22 Jan 2009 19:48:46 -0500 Message-ID: <497913EE.9040608@vivisimo.com> References: <1232671630-19683-1-git-send-email-goulding@vivisimo.com> <1232671630-19683-2-git-send-email-goulding@vivisimo.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit To: git@vger.kernel.org X-From: git-owner@vger.kernel.org Fri Jan 23 01:51:18 2009 Return-path: Envelope-to: gcvg-git-2@gmane.org Received: from vger.kernel.org ([209.132.176.167]) by lo.gmane.org with esmtp (Exim 4.50) id 1LQAGQ-0004rh-GA for gcvg-git-2@gmane.org; Fri, 23 Jan 2009 01:51:14 +0100 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759223AbZAWAtu (ORCPT ); Thu, 22 Jan 2009 19:49:50 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1759200AbZAWAtu (ORCPT ); Thu, 22 Jan 2009 19:49:50 -0500 Received: from scalix.vivisimo.com ([207.97.211.28]:57464 "EHLO mail.vivisimo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1759192AbZAWAtt (ORCPT ); Thu, 22 Jan 2009 19:49:49 -0500 Received: from mail.office.vivisimo.com (mail.office.vivisimo.com [206.210.75.84]) by mail.vivisimo.com (Postfix) with ESMTP id 2656D853836 for ; Thu, 22 Jan 2009 19:49:48 -0500 (EST) Received: from localhost (localhost.localdomain [127.0.0.1]) by mail.office.vivisimo.com (Postfix) with ESMTP id 070CA2E68CF for ; Thu, 22 Jan 2009 19:49:48 -0500 (EST) X-Virus-Scanned: amavisd-new at vivisimo.com Received: from mail.office.vivisimo.com ([127.0.0.1]) by localhost (mail.office.vivisimo.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 84YwlsQ5ypvx for ; Thu, 22 Jan 2009 19:49:42 -0500 (EST) Received: from [192.168.0.20] (unknown [192.168.0.20]) by mail.office.vivisimo.com (Postfix) with ESMTP id C28C32E68D7 for ; Thu, 22 Jan 2009 19:48:46 -0500 (EST) User-Agent: Thunderbird 2.0.0.19 (X11/20090105) In-Reply-To: <1232671630-19683-2-git-send-email-goulding@vivisimo.com> Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Archived-At: This functions similar to git branch --contains - it will show all tags that contain the specified commit. Indeed, it uses the same lookup mechanisms as git branch. Also adding documentation and tests for new option. Signed-off-by: Jake Goulding --- Reworked with feedback from the list. Moved commit testing inside of the regex match, instead of before. Moved test cases into existing test. Squashed code / doc / test into one commit. Documentation/git-tag.txt | 5 ++- builtin-tag.c | 32 +++++++++++- t/t7004-tag.sh | 115 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 4 deletions(-) diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index e44f543..533d18b 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -12,7 +12,7 @@ SYNOPSIS 'git tag' [-a | -s | -u ] [-f] [-m | -F ] [ | ] 'git tag' -d ... -'git tag' [-n[]] -l [] +'git tag' [-n[]] -l [--contains ] [] 'git tag' -v ... DESCRIPTION @@ -68,6 +68,9 @@ OPTIONS List tags with names that match the given pattern (or all if no pattern is given). Typing "git tag" without arguments, also lists all tags. +--contains :: + Only list tags which contain the specified commit. + -m :: Use the given tag message (instead of prompting). If multiple `-m` options are given, their values are diff --git a/builtin-tag.c b/builtin-tag.c index a398499..33424c0 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -26,6 +26,7 @@ static char signingkey[1000]; struct tag_filter { const char *pattern; int lines; + struct commit_list *with_commit; }; #define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----" @@ -34,7 +35,6 @@ static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct tag_filter *filter = cb_data; - if (!fnmatch(filter->pattern, refname, 0)) { int i; unsigned long size; @@ -42,6 +42,18 @@ static int show_reference(const char *refname, const unsigned char *sha1, char *buf, *sp, *eol; size_t len; + if (filter->with_commit) { + struct commit *commit; + + commit = lookup_commit_reference_gently(sha1, 1); + if (!commit) { + error("tag '%s' does not point at a commit", refname); + return 0; + } + if (!has_commit(commit, filter->with_commit)) + return 0; + } + if (!filter->lines) { printf("%s\n", refname); return 0; @@ -79,7 +91,8 @@ static int show_reference(const char *refname, const unsigned char *sha1, return 0; } -static int list_tags(const char *pattern, int lines) +static int list_tags(const char *pattern, int lines, + struct commit_list *with_commit) { struct tag_filter filter; @@ -88,6 +101,7 @@ static int list_tags(const char *pattern, int lines) filter.pattern = pattern; filter.lines = lines; + filter.with_commit = with_commit; for_each_tag_ref(show_reference, (void *) &filter); @@ -360,6 +374,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) list = 0, delete = 0, verify = 0; const char *msgfile = NULL, *keyid = NULL; struct msg_arg msg = { 0, STRBUF_INIT }; + struct commit_list *with_commit = NULL; struct option options[] = { OPT_BOOLEAN('l', NULL, &list, "list tag names"), { OPTION_INTEGER, 'n', NULL, &lines, NULL, @@ -378,6 +393,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT_STRING('u', NULL, &keyid, "key-id", "use another key to sign the tag"), OPT_BOOLEAN('f', NULL, &force, "replace the tag if exists"), + + OPT_GROUP("Tag listing options"), + { + OPTION_CALLBACK, 0, "contains", &with_commit, "commit", + "print only tags that contain the commit", + PARSE_OPT_LASTARG_DEFAULT, + parse_opt_with_commit, (intptr_t)"HEAD", + }, OPT_END() }; @@ -402,9 +425,12 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (list + delete + verify > 1) usage_with_options(git_tag_usage, options); if (list) - return list_tags(argv[0], lines == -1 ? 0 : lines); + return list_tags(argv[0], lines == -1 ? 0 : lines, + with_commit); if (lines != -1) die("-n option is only allowed with -l."); + if (with_commit) + die("--contains option is only allowed with -l."); if (delete) return for_each_tag_name(argv, delete_tag); if (verify) diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index f377fea..69501e2 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1090,6 +1090,121 @@ test_expect_success 'filename for the message is relative to cwd' ' git cat-file tag tag-from-subdir-2 | grep "in sub directory" ' +# create a few more commits to test --contains + +hash1=$(git rev-parse HEAD) + +test_expect_success 'creating second commit and tag' ' + echo foo-2.0 >foo && + git add foo && + git commit -m second + git tag v2.0 +' + +hash2=$(git rev-parse HEAD) + +test_expect_success 'creating third commit without tag' ' + echo foo-dev >foo && + git add foo && + git commit -m third +' + +hash3=$(git rev-parse HEAD) + +# simple linear checks of --continue + +cat > expected <actual + test_cmp expected actual +" + +# other ways of specifying the commit +test_expect_success 'checking that first commit is in all tags (tag)' " + git tag -l --contains v1.0 v* >actual + test_cmp expected actual +" + +test_expect_success 'checking that first commit is in all tags (relative)' " + git tag -l --contains HEAD~2 v* >actual + test_cmp expected actual +" + +cat > expected <actual + test_cmp expected actual +" + + +cat > expected <actual + test_cmp expected actual +" + +# how about a simple merge? + +test_expect_success 'creating simple branch' ' + git branch stable v2.0 && + git checkout stable && + echo foo-3.0 > foo && + git commit foo -m fourth + git tag v3.0 +' + +hash4=$(git rev-parse HEAD) + +cat > expected <actual + test_cmp expected actual +" + +test_expect_success 'merging original branch into this branch' ' + git merge --strategy=ours master && + git tag v4.0 +' + +cat > expected <actual + test_cmp expected actual +" + +cat > expected <actual + test_cmp expected actual +" + # mixing modes and options: test_expect_success 'mixing incompatibles modes and options is forbidden' ' -- 1.6.0.4