Skip to contentSkip to conversation

Make has_commit non-static

PATCH In review Jake Goulding 2 participants 5 messages Jun 15, 2016 2 messages not in the archive Documentation

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw

PATCH 3/3 Add --contains flag to git tag

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.

---

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(-)
Documentation/git-tag.txt +1 -1
index e44f543..533d18b 100644
@@ -12,7 +12,7 @@ SYNOPSIS
 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
 	<name> [<commit> | <object>]
 'git tag' -d <name>...
-'git tag' [-n[<num>]] -l [<pattern>]
+'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>]
 'git tag' -v <name>...
 
 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 <commit>::
+ Only list tags which contain the specified commit.
+
-m <msg>::
Use the given tag message (instead of prompting). If multiple -m options are given, their values are

builtin-tag.c +1 -0
index a398499..33424c0 100644
@@ -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)

t/t7004-tag.sh +0 -0
index f377fea..69501e2 100755
@@ -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 <<EOF
+v0.2.1
+v1.0
+v1.0.1
+v1.1.3
+v2.0
+EOF
+
+test_expect_success 'checking that first commit is in all tags (hash)' "
+ git tag -l --contains $hash1 v* >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 <<EOF
+v2.0
+EOF
+
+test_expect_success 'checking that second commit only has one tag' "
+ git tag -l --contains $hash2 v* >actual
+ test_cmp expected actual
+"
+
+
+cat > expected <<EOF
+EOF
+
+test_expect_success 'checking that third commit has no tags' "
+ git tag -l --contains $hash3 v* >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 <<EOF
+v3.0
+EOF
+
+test_expect_success 'checking that branch head only has one tag' "
+ git tag -l --contains $hash4 v* >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 <<EOF
+v4.0
+EOF
+
+test_expect_success 'checking that original branch head has one tag now' "
+ git tag -l --contains $hash3 v* >actual
+ test_cmp expected actual
+"
+
+cat > expected <<EOF
+v0.2.1
+v1.0
+v1.0.1
+v1.1.3
+v2.0
+v3.0
+v4.0
+EOF
+
+test_expect_success 'checking that initial commit is in all tags' "
+ git tag -l --contains $hash1 v* >actual
+ test_cmp expected actual
+"
+

 # mixing modes and options:

test_expect_success 'mixing incompatibles modes and options is forbidden' '

Signature · 1 line
1.6.0.4
#3 lore raw

Re: [PATCH 3/3] Add --contains flag to git tag

Quoted 9 lines · Jake Goulding
(quoted diff) +0 -1
@@ -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;

Here you can see a long line wrapped.

What does this hunk have to do with adding --contains option anyway?

Review static int show_reference(const char *refname, const · line 52

Quoted 12 lines
(quoted diff) +7 -0
@@ -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;

Drop this error() call, and just return silently. A tag that does not point at a commit is not an error at all.

#4 lore raw

PATCH 2/3 Make has_commit non-static

In reply to a message not in the archive

Moving has_commit from branch to a common location in preparation for using it in tag.

---
 builtin-branch.c |   15 ---------------
 commit.c         |   15 +++++++++++++++
 commit.h         |    1 +
 3 files changed, 16 insertions(+), 15 deletions(-)
builtin-branch.c +0 -1
index 82d6fb2..bb42911 100644
@@ -193,21 +193,6 @@ struct ref_list {
 	int kinds;
 };
 
-static int has_commit(struct commit *commit, struct commit_list

*with_commit)
-{
- if (!with_commit)
- return 1;
- while (with_commit) {
- struct commit *other;
-
- other = with_commit->item;
- with_commit = with_commit->next;
- if (in_merge_bases(other, &commit, 1))
- return 1;
- }
- return 0;
-}
-
static int append_ref(const char *refname, const unsigned char *sha1,
int flags, void *cb_data)
{
struct ref_list *ref_list = (struct ref_list*)(cb_data);

commit.c +0 -0
index c99db16..5ccb338 100644
@@ -705,6 +705,21 @@ struct commit_list *get_merge_bases(struct commit

*one, struct commit *two,
return get_merge_bases_many(one, 1, &two, cleanup);
}

+int has_commit(struct commit *commit, struct commit_list *with_commit) +{
+ if (!with_commit)
+ return 1;
+ while (with_commit) {
+ struct commit *other;
+
+ other = with_commit->item;
+ with_commit = with_commit->next;
+ if (in_merge_bases(other, &commit, 1))
+ return 1;
+ }
+ return 0;
+}
+
int in_merge_bases(struct commit *commit, struct commit **reference,
int num)
{
struct commit_list *bases, *b;

commit.h +1 -0
index 3a7b06a..1b8444f 100644
@@ -133,6 +133,7 @@ extern int is_repository_shallow(void);
 extern struct commit_list *get_shallow_commits(struct object_array *heads,
 		int depth, int shallow_flag, int not_shallow_flag);
 
+int has_commit(struct commit *, struct commit_list *);
 int in_merge_bases(struct commit *, struct commit **, int);
 
 extern int interactive_add(int argc, const char **argv, const char

*prefix);

Signature · 1 line
1.6.0.4
#5 lore raw
Quoted 2 lines · Jake Goulding

Moving has_commit from branch to a common location in preparation for using it in tag.

has_commit() may have been a good enough name when it was a static in builtin-branch.c but with much wider visibility, it is not specific enough.

Perhaps you would want to rename it to something more descriptive.

Also it seems that your patch is garbled and won't apply. A blank context line lost the leading (and only) SP, and long lines are wrapped.

Quoted 78 lines
---
 builtin-branch.c |   15 ---------------
 commit.c         |   15 +++++++++++++++
 commit.h         |    1 +
 3 files changed, 16 insertions(+), 15 deletions(-)
builtin-branch.c +0 -15
index 82d6fb2..bb42911 100644
@@ -193,21 +193,6 @@ struct ref_list {
 	int kinds;
 };
 
-static int has_commit(struct commit *commit, struct commit_list
 *with_commit)
-{
-	if (!with_commit)
-		return 1;
-	while (with_commit) {
-		struct commit *other;
-
-		other = with_commit->item;
-		with_commit = with_commit->next;
-		if (in_merge_bases(other, &commit, 1))
-			return 1;
-	}
-	return 0;
-}
-
 static int append_ref(const char *refname, const unsigned char *sha1,
 int flags, void *cb_data)

{

builtin-branch.c +0 -0
 	struct ref_list *ref_list = (struct ref_list*)(cb_data);
commit.c +15 -0
index c99db16..5ccb338 100644
@@ -705,6 +705,21 @@ struct commit_list *get_merge_bases(struct commit
 *one, struct commit *two,
 	return get_merge_bases_many(one, 1, &two, cleanup);
 }
 
+int has_commit(struct commit *commit, struct commit_list *with_commit)
+{
+	if (!with_commit)
+		return 1;
+	while (with_commit) {
+		struct commit *other;
+
+		other = with_commit->item;
+		with_commit = with_commit->next;
+		if (in_merge_bases(other, &commit, 1))
+			return 1;
+	}
+	return 0;
+}
+
 int in_merge_bases(struct commit *commit, struct commit **reference,
 int num)

{

commit.c +0 -0
 	struct commit_list *bases, *b;
commit.h +1 -0
index 3a7b06a..1b8444f 100644
@@ -133,6 +133,7 @@ extern int is_repository_shallow(void);
 extern struct commit_list *get_shallow_commits(struct object_array *heads,
 		int depth, int shallow_flag, int not_shallow_flag);
 
+int has_commit(struct commit *, struct commit_list *);
 int in_merge_bases(struct commit *, struct commit **, int);
 
 extern int interactive_add(int argc, const char **argv, const char

*prefix);

Signature · 1 line
1.6.0.4
#6 lore raw
Quoted 10 lines · Junio C Hamano
Quoted 2 lines · Jake Goulding

Moving has_commit from branch to a common location in preparation for using it in tag.

has_commit() may have been a good enough name when it was a static in builtin-branch.c but with much wider visibility, it is not specific enough.

Perhaps you would want to rename it to something more descriptive.

Sure - any suggestions?

The best I could come up with was "commit_has_any_in_commit_list"

Quoted 2 lines

Also it seems that your patch is garbled and won't apply. A blank context line lost the leading (and only) SP, and long lines are wrapped.

Yes - adventures in sending patches. Hopefully I'll have it fixed by the next round of patches. :-)

Quoted 79 lines
Quoted 79 lines
---
 builtin-branch.c |   15 ---------------
 commit.c         |   15 +++++++++++++++
 commit.h         |    1 +
 3 files changed, 16 insertions(+), 15 deletions(-)
builtin-branch.c +0 -15
index 82d6fb2..bb42911 100644
@@ -193,21 +193,6 @@ struct ref_list {
 	int kinds;
 };
 
-static int has_commit(struct commit *commit, struct commit_list
 *with_commit)
-{
-	if (!with_commit)
-		return 1;
-	while (with_commit) {
-		struct commit *other;
-
-		other = with_commit->item;
-		with_commit = with_commit->next;
-		if (in_merge_bases(other, &commit, 1))
-			return 1;
-	}
-	return 0;
-}
-
 static int append_ref(const char *refname, const unsigned char *sha1,
 int flags, void *cb_data)

{

builtin-branch.c +0 -0
 	struct ref_list *ref_list = (struct ref_list*)(cb_data);
commit.c +15 -0
index c99db16..5ccb338 100644
@@ -705,6 +705,21 @@ struct commit_list *get_merge_bases(struct commit
 *one, struct commit *two,
 	return get_merge_bases_many(one, 1, &two, cleanup);
 }
 
+int has_commit(struct commit *commit, struct commit_list *with_commit)
+{
+	if (!with_commit)
+		return 1;
+	while (with_commit) {
+		struct commit *other;
+
+		other = with_commit->item;
+		with_commit = with_commit->next;
+		if (in_merge_bases(other, &commit, 1))
+			return 1;
+	}
+	return 0;
+}
+
 int in_merge_bases(struct commit *commit, struct commit **reference,
 int num)

{

commit.c +0 -0
 	struct commit_list *bases, *b;
commit.h +1 -0
index 3a7b06a..1b8444f 100644
@@ -133,6 +133,7 @@ extern int is_repository_shallow(void);
 extern struct commit_list *get_shallow_commits(struct object_array *heads,
 		int depth, int shallow_flag, int not_shallow_flag);
 
+int has_commit(struct commit *, struct commit_list *);
 int in_merge_bases(struct commit *, struct commit **, int);
 
 extern int interactive_add(int argc, const char **argv, const char

*prefix);

Signature · 1 line
1.6.0.4