git-tag: Add --contains option
This functions similarly to "git branch --contains"; it will show all tags that contain the specified commit, by sharing the same logic. The patch also adds documentation and tests for the new option. Signed-off-by: Jake Goulding <goulding@vivisimo.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jake Goulding committed
Jan 26, 2009 at 09:13 UTC
32c35cfb1e9c8523b9d60e5095f1c49ebaef0279
3 files changed
+146
-3
Documentation/git-tag.txt
+4
-1
@@ -12,7 +12,7 @@ SYNOPSIS
12
'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
13
<name> [<commit> | <object>]
14
'git tag' -d <name>...
15
-'git tag' [-n[<num>]] -l [<pattern>]
15
+'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>]
16
'git tag' -v <name>...
17
18
DESCRIPTION
@@ -68,6 +68,9 @@ OPTIONS
68
List tags with names that match the given pattern (or all if no pattern is given).
69
Typing "git tag" without arguments, also lists all tags.
70
71
+--contains <commit>::
72
+ Only list tags which contain the specified commit.
73
+
74
-m <msg>::
75
Use the given tag message (instead of prompting).
76
If multiple `-m` options are given, their values are
builtin-tag.c
+27
-2
@@ -26,6 +26,7 @@ static char signingkey[1000];
26
struct tag_filter {
27
const char *pattern;
28
int lines;
29
+ struct commit_list *with_commit;
30
};
31
32
#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
@@ -42,6 +43,16 @@ static int show_reference(const char *refname, const unsigned char *sha1,
43
char *buf, *sp, *eol;
44
size_t len;
45
46
+ if (filter->with_commit) {
47
+ struct commit *commit;
48
+
49
+ commit = lookup_commit_reference_gently(sha1, 1);
50
+ if (!commit)
51
+ return 0;
52
+ if (!is_descendant_of(commit, filter->with_commit))
53
+ return 0;
54
+ }
55
+
56
if (!filter->lines) {
57
printf("%s\n", refname);
58
return 0;
@@ -79,7 +90,8 @@ static int show_reference(const char *refname, const unsigned char *sha1,
90
return 0;
91
}
92
82
-static int list_tags(const char *pattern, int lines)
93
+static int list_tags(const char *pattern, int lines,
94
+ struct commit_list *with_commit)
95
{
96
struct tag_filter filter;
97
@@ -88,6 +100,7 @@ static int list_tags(const char *pattern, int lines)
100
101
filter.pattern = pattern;
102
filter.lines = lines;
103
+ filter.with_commit = with_commit;
104
105
for_each_tag_ref(show_reference, (void *) &filter);
106
@@ -360,6 +373,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
373
list = 0, delete = 0, verify = 0;
374
const char *msgfile = NULL, *keyid = NULL;
375
struct msg_arg msg = { 0, STRBUF_INIT };
376
+ struct commit_list *with_commit = NULL;
377
struct option options[] = {
378
OPT_BOOLEAN('l', NULL, &list, "list tag names"),
379
{ OPTION_INTEGER, 'n', NULL, &lines, NULL,
@@ -378,6 +392,14 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
392
OPT_STRING('u', NULL, &keyid, "key-id",
393
"use another key to sign the tag"),
394
OPT_BOOLEAN('f', NULL, &force, "replace the tag if exists"),
395
+
396
+ OPT_GROUP("Tag listing options"),
397
+ {
398
+ OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
399
+ "print only tags that contain the commit",
400
+ PARSE_OPT_LASTARG_DEFAULT,
401
+ parse_opt_with_commit, (intptr_t)"HEAD",
402
+ },
403
OPT_END()
404
};
405
@@ -402,9 +424,12 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
424
if (list + delete + verify > 1)
425
usage_with_options(git_tag_usage, options);
426
if (list)
405
- return list_tags(argv[0], lines == -1 ? 0 : lines);
427
+ return list_tags(argv[0], lines == -1 ? 0 : lines,
428
+ with_commit);
429
if (lines != -1)
430
die("-n option is only allowed with -l.");
431
+ if (with_commit)
432
+ die("--contains option is only allowed with -l.");
433
if (delete)
434
return for_each_tag_name(argv, delete_tag);
435
if (verify)
t/t7004-tag.sh
+115
@@ -1090,6 +1090,121 @@ test_expect_success 'filename for the message is relative to cwd' '
1090
git cat-file tag tag-from-subdir-2 | grep "in sub directory"
1091
'
1092
1093
+# create a few more commits to test --contains
1094
+
1095
+hash1=$(git rev-parse HEAD)
1096
+
1097
+test_expect_success 'creating second commit and tag' '
1098
+ echo foo-2.0 >foo &&
1099
+ git add foo &&
1100
+ git commit -m second
1101
+ git tag v2.0
1102
+'
1103
+
1104
+hash2=$(git rev-parse HEAD)
1105
+
1106
+test_expect_success 'creating third commit without tag' '
1107
+ echo foo-dev >foo &&
1108
+ git add foo &&
1109
+ git commit -m third
1110
+'
1111
+
1112
+hash3=$(git rev-parse HEAD)
1113
+
1114
+# simple linear checks of --continue
1115
+
1116
+cat > expected <<EOF
1117
+v0.2.1
1118
+v1.0
1119
+v1.0.1
1120
+v1.1.3
1121
+v2.0
1122
+EOF
1123
+
1124
+test_expect_success 'checking that first commit is in all tags (hash)' "
1125
+ git tag -l --contains $hash1 v* >actual
1126
+ test_cmp expected actual
1127
+"
1128
+
1129
+# other ways of specifying the commit
1130
+test_expect_success 'checking that first commit is in all tags (tag)' "
1131
+ git tag -l --contains v1.0 v* >actual
1132
+ test_cmp expected actual
1133
+"
1134
+
1135
+test_expect_success 'checking that first commit is in all tags (relative)' "
1136
+ git tag -l --contains HEAD~2 v* >actual
1137
+ test_cmp expected actual
1138
+"
1139
+
1140
+cat > expected <<EOF
1141
+v2.0
1142
+EOF
1143
+
1144
+test_expect_success 'checking that second commit only has one tag' "
1145
+ git tag -l --contains $hash2 v* >actual
1146
+ test_cmp expected actual
1147
+"
1148
+
1149
+
1150
+cat > expected <<EOF
1151
+EOF
1152
+
1153
+test_expect_success 'checking that third commit has no tags' "
1154
+ git tag -l --contains $hash3 v* >actual
1155
+ test_cmp expected actual
1156
+"
1157
+
1158
+# how about a simple merge?
1159
+
1160
+test_expect_success 'creating simple branch' '
1161
+ git branch stable v2.0 &&
1162
+ git checkout stable &&
1163
+ echo foo-3.0 > foo &&
1164
+ git commit foo -m fourth
1165
+ git tag v3.0
1166
+'
1167
+
1168
+hash4=$(git rev-parse HEAD)
1169
+
1170
+cat > expected <<EOF
1171
+v3.0
1172
+EOF
1173
+
1174
+test_expect_success 'checking that branch head only has one tag' "
1175
+ git tag -l --contains $hash4 v* >actual
1176
+ test_cmp expected actual
1177
+"
1178
+
1179
+test_expect_success 'merging original branch into this branch' '
1180
+ git merge --strategy=ours master &&
1181
+ git tag v4.0
1182
+'
1183
+
1184
+cat > expected <<EOF
1185
+v4.0
1186
+EOF
1187
+
1188
+test_expect_success 'checking that original branch head has one tag now' "
1189
+ git tag -l --contains $hash3 v* >actual
1190
+ test_cmp expected actual
1191
+"
1192
+
1193
+cat > expected <<EOF
1194
+v0.2.1
1195
+v1.0
1196
+v1.0.1
1197
+v1.1.3
1198
+v2.0
1199
+v3.0
1200
+v4.0
1201
+EOF
1202
+
1203
+test_expect_success 'checking that initial commit is in all tags' "
1204
+ git tag -l --contains $hash1 v* >actual
1205
+ test_cmp expected actual
1206
+"
1207
+
1208
# mixing modes and options:
1209
1210
test_expect_success 'mixing incompatibles modes and options is forbidden' '