Git development
 help / color / mirror / Atom feed
* [PATCH v2 1/5] doc: add documentation for OPT_STRING_LIST
From: Jacob Keller @ 2017-01-18  0:03 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000345.31196-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Commit c8ba16391655 ("parse-options: add OPT_STRING_LIST helper",
2011-06-09) added the OPT_STRING_LIST as a way to accumulate a repeated
list of strings. However, this was not documented in the
api-parse-options documentation. Add documentation now so that future
developers may learn of its existence.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/technical/api-parse-options.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 27bd701c0d68..6914f54f5f44 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -168,6 +168,11 @@ There are some macros to easily define options:
 	Introduce an option with string argument.
 	The string argument is put into `str_var`.
 
+`OPT_STRING_LIST(short, long, &list, arg_str, description)`::
+	Introduce an option with string argument.
+	The string argument is stored as an element in `&list` which must be a
+	struct string_list. Reset the list using `--no-option`.
+
 `OPT_INTEGER(short, long, &int_var, description)`::
 	Introduce an option with integer argument.
 	The integer is put into `int_var`.
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* [PATCH v2 5/5] describe: teach describe negative pattern matches
From: Jacob Keller @ 2017-01-18  0:03 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000345.31196-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Teach git-describe the `--exclude` option which will allow specifying
a glob pattern of tags to ignore. This can be combined with the
`--match` patterns to enable more flexibility in determining which tags
to consider.

For example, suppose you wish to find the first official release tag
that contains a certain commit. If we assume that official release tags
are of the form "v*" and pre-release candidates include "*rc*" in their
name, we can now find the first tag that introduces commit abcdef via:

  git describe --contains --match="v*" --exclude="*rc*"

Add documentation and tests for this change.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/git-describe.txt |  8 ++++++++
 builtin/describe.c             | 21 +++++++++++++++++++++
 t/t6120-describe.sh            |  8 ++++++++
 3 files changed, 37 insertions(+)

diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index 7ad41e2f6ade..21a43b78924a 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -88,6 +88,14 @@ OPTIONS
 	patterns will be considered. Use `--no-match` to clear and reset the
 	list of patterns.
 
+--exclude <pattern>::
+	Do not consider tags matching the given `glob(7)` pattern, excluding
+	the "refs/tags/" prefix. This can be used to narrow the tag space and
+	find only tags matching some meaningful criteria. If given multiple
+	times, a list of patterns will be accumulated and tags matching any
+	of the patterns will be excluded. Use `--no-exclude` to clear and
+	reset the list of patterns.
+
 --always::
 	Show uniquely abbreviated commit object as fallback.
 
diff --git a/builtin/describe.c b/builtin/describe.c
index 5cc9e9abe798..6769446e1f57 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -29,6 +29,7 @@ static int max_candidates = 10;
 static struct hashmap names;
 static int have_util;
 static struct string_list patterns = STRING_LIST_INIT_NODUP;
+static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
 static int always;
 static const char *dirty;
 
@@ -130,6 +131,22 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
 		return 0;
 
 	/*
+	 * If we're given exclude patterns, first exclude any tag which match
+	 * any of the exclude pattern.
+	 */
+	if (exclude_patterns.nr) {
+		struct string_list_item *item;
+
+		if (!is_tag)
+			return 0;
+
+		for_each_string_list_item(item, &exclude_patterns) {
+			if (!wildmatch(item->string, path + 10, 0, NULL))
+				return 0;
+		}
+	}
+
+	/*
 	 * If we're given patterns, accept only tags which match at least one
 	 * pattern.
 	 */
@@ -421,6 +438,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 			    N_("consider <n> most recent tags (default: 10)")),
 		OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
 			   N_("only consider tags matching <pattern>")),
+		OPT_STRING_LIST(0, "exclude", &exclude_patterns, N_("pattern"),
+			   N_("do not consider tags matching <pattern>")),
 		OPT_BOOL(0, "always",        &always,
 			N_("show abbreviated commit object as fallback")),
 		{OPTION_STRING, 0, "dirty",  &dirty, N_("mark"),
@@ -458,6 +477,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 			argv_array_push(&args, "--tags");
 			for_each_string_list_item(item, &patterns)
 				argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
+			for_each_string_list_item(item, &exclude_patterns)
+				argv_array_pushf(&args, "--exclude=refs/tags/%s", item->string);
 		}
 		if (argc)
 			argv_array_pushv(&args, argv);
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 9e5db9b87a1f..167491fd5b0d 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -218,6 +218,14 @@ test_expect_success 'describe --contains and --match' '
 	test_cmp expect actual
 '
 
+test_expect_success 'describe --exclude' '
+	echo "c~1" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	test_must_fail git describe --contains --match="B" $tagged_commit &&
+	git describe --contains --match="?" --exclude="A" $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'describe --contains and --no-match' '
 	echo "A^0" >expect &&
 	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* Re: [PATCH v6 4/6] builtin/tag: add --format argument for tag -v
From: Junio C Hamano @ 2017-01-18  0:05 UTC (permalink / raw)
  To: santiago; +Cc: git, peff, sunshine, walters, Lukas Puehringer
In-Reply-To: <20170117233723.23897-5-santiago@nyu.edu>

santiago@nyu.edu writes:

> -static int for_each_tag_name(const char **argv, each_tag_name_fn fn)
> +static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
> +		void *cb_data)
>  {
>  	const char **p;
>  	char ref[PATH_MAX];
>  	int had_error = 0;
>  	unsigned char sha1[20];
>  
> +

Why?  I'll remove this while queuing.

>  	for (p = argv; *p; p++) {
>  		if (snprintf(ref, sizeof(ref), "refs/tags/%s", *p)
>  					>= sizeof(ref)) {

^ permalink raw reply

* [PATCH v2 4/5] describe: teach --match to accept multiple patterns
From: Jacob Keller @ 2017-01-18  0:03 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000345.31196-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Teach `--match` to be accepted multiple times, accumulating a list of
patterns to match into a string list. Each pattern is inclusive, such
that a tag need only match one of the provided patterns to be
considered for matching.

This extension is useful as it enables more flexibility in what tags
match, and may avoid the need to run the describe command multiple
times to get the same result.

Add tests and update the documentation for this change.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/git-describe.txt |  5 ++++-
 builtin/describe.c             | 30 +++++++++++++++++++++++-------
 t/t6120-describe.sh            | 19 +++++++++++++++++++
 3 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index e4ac448ff565..7ad41e2f6ade 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -83,7 +83,10 @@ OPTIONS
 --match <pattern>::
 	Only consider tags matching the given `glob(7)` pattern,
 	excluding the "refs/tags/" prefix.  This can be used to avoid
-	leaking private tags from the repository.
+	leaking private tags from the repository. If given multiple times, a
+	list of patterns will be accumulated, and tags matching any of the
+	patterns will be considered. Use `--no-match` to clear and reset the
+	list of patterns.
 
 --always::
 	Show uniquely abbreviated commit object as fallback.
diff --git a/builtin/describe.c b/builtin/describe.c
index 01490a157efc..5cc9e9abe798 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -28,7 +28,7 @@ static int abbrev = -1; /* unspecified */
 static int max_candidates = 10;
 static struct hashmap names;
 static int have_util;
-static const char *pattern;
+static struct string_list patterns = STRING_LIST_INIT_NODUP;
 static int always;
 static const char *dirty;
 
@@ -129,9 +129,24 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
 	if (!all && !is_tag)
 		return 0;
 
-	/* Accept only tags that match the pattern, if given */
-	if (pattern && (!is_tag || wildmatch(pattern, path + 10, 0, NULL)))
-		return 0;
+	/*
+	 * If we're given patterns, accept only tags which match at least one
+	 * pattern.
+	 */
+	if (patterns.nr) {
+		struct string_list_item *item;
+
+		if (!is_tag)
+			return 0;
+
+		for_each_string_list_item(item, &patterns) {
+			if (!wildmatch(item->string, path + 10, 0, NULL))
+				break;
+
+			/* If we get here, no pattern matched. */
+			return 0;
+		}
+	}
 
 	/* Is it annotated? */
 	if (!peel_ref(path, peeled.hash)) {
@@ -404,7 +419,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 			    N_("only output exact matches"), 0),
 		OPT_INTEGER(0, "candidates", &max_candidates,
 			    N_("consider <n> most recent tags (default: 10)")),
-		OPT_STRING(0, "match",       &pattern, N_("pattern"),
+		OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
 			   N_("only consider tags matching <pattern>")),
 		OPT_BOOL(0, "always",        &always,
 			N_("show abbreviated commit object as fallback")),
@@ -430,6 +445,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 		die(_("--long is incompatible with --abbrev=0"));
 
 	if (contains) {
+		struct string_list_item *item;
 		struct argv_array args;
 
 		argv_array_init(&args);
@@ -440,8 +456,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 			argv_array_push(&args, "--always");
 		if (!all) {
 			argv_array_push(&args, "--tags");
-			if (pattern)
-				argv_array_pushf(&args, "--refs=refs/tags/%s", pattern);
+			for_each_string_list_item(item, &patterns)
+				argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
 		}
 		if (argc)
 			argv_array_pushv(&args, argv);
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 85f269411cb3..9e5db9b87a1f 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -182,6 +182,10 @@ check_describe "test2-lightweight-*" --tags --match="test2-*"
 
 check_describe "test2-lightweight-*" --long --tags --match="test2-*" HEAD^
 
+check_describe "test1-lightweight-*" --long --tags --match="test1-*" --match="test2-*" HEAD^
+
+check_describe "test2-lightweight-*" --long --tags --match="test1-*" --no-match --match="test2-*" HEAD^
+
 test_expect_success 'name-rev with exact tags' '
 	echo A >expect &&
 	tag_object=$(git rev-parse refs/tags/A) &&
@@ -206,4 +210,19 @@ test_expect_success 'describe --contains with the exact tags' '
 	test_cmp expect actual
 '
 
+test_expect_success 'describe --contains and --match' '
+	echo "A^0" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	test_must_fail git describe --contains --match="B" $tagged_commit &&
+	git describe --contains --match="B" --match="A" $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'describe --contains and --no-match' '
+	echo "A^0" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	git describe --contains --match="B" --no-match $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* Re: [PATCH v6 0/6] Add --format to tag verification
From: Junio C Hamano @ 2017-01-18  0:07 UTC (permalink / raw)
  To: santiago; +Cc: git, peff, sunshine, walters
In-Reply-To: <20170117233723.23897-1-santiago@nyu.edu>

santiago@nyu.edu writes:

> From: Santiago Torres <santiago@nyu.edu>
>
> This is the sixth iteration of [1][2][3][4][5], and as a result of the
> discussion in [5]. The main goal of this patch series is to bring
> --format to git tag verification so that upper-layer tools can inspect
> the content of a tag and make decisions based on it.
>
> In this re-woll we:
>
> * Changed the call interface so printing is done outside of verification. 
>
> * Fixed a couple of whitespace issues and whatnot. 

With the small code structure change Peff suggested the result looks
much easier to read.  I didn't spot any more problems.

Will replace what has been sitting in my tree.  Thanks.

^ permalink raw reply

* [PATCH v2 3/5] name-rev: add support to exclude refs by pattern match
From: Jacob Keller @ 2017-01-18  0:03 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000345.31196-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Extend name-rev further to support matching refs by adding `--exclude`
patterns. These patterns will limit the scope of refs by excluding any
ref that matches at least one exclude pattern. Checking the exclude refs
shall happen first, before checking the include --refs patterns. This
will allow more flexibility to matching certain kinds of references.

Add tests and update Documentation for this change.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/git-name-rev.txt       |  7 +++++++
 builtin/name-rev.c                   | 14 +++++++++++++-
 t/t6007-rev-list-cherry-pick-file.sh | 12 ++++++++++++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index 7433627db12d..301b4a8d55e6 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -30,6 +30,13 @@ OPTIONS
 	given multiple times, use refs whose names match any of the given shell
 	patterns. Use `--no-refs` to clear any previous ref patterns given.
 
+--exclude=<pattern>::
+	Do not use any ref whose name matches a given shell pattern. The
+	pattern can be one of branch name, tag name or fully qualified ref
+	name. If given multiple times, exclude refs that match any of the given
+	shell patterns. Use `--no-exclude` to clear the list of exclude
+	patterns.
+
 --all::
 	List all commits reachable from all refs
 
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 000a2a700ed3..da4a0d7c0fdf 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -109,6 +109,7 @@ struct name_ref_data {
 	int tags_only;
 	int name_only;
 	struct string_list ref_filters;
+	struct string_list exclude_filters;
 };
 
 static struct tip_table {
@@ -150,6 +151,15 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
 	if (data->tags_only && !starts_with(path, "refs/tags/"))
 		return 0;
 
+	if (data->exclude_filters.nr) {
+		struct string_list_item *item;
+
+		for_each_string_list_item(item, &data->exclude_filters) {
+			if (subpath_matches(path, item->string) >= 0)
+				return 0;
+		}
+	}
+
 	if (data->ref_filters.nr) {
 		struct string_list_item *item;
 		int matched = 0;
@@ -323,12 +333,14 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 {
 	struct object_array revs = OBJECT_ARRAY_INIT;
 	int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
-	struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP };
+	struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
 	struct option opts[] = {
 		OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
 		OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
 		OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
 				   N_("only use refs matching <pattern>")),
+		OPT_STRING_LIST(0, "exclude", &data.exclude_filters, N_("pattern"),
+				   N_("ignore refs matching <pattern>")),
 		OPT_GROUP(""),
 		OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
 		OPT_BOOL(0, "stdin", &transform_stdin, N_("read from stdin")),
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index f724ff24044b..83838d0da208 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -118,6 +118,18 @@ test_expect_success 'name-rev --refs excludes non-matched patterns' '
 	test_cmp actual.named expect
 '
 
+cat >expect <<EOF
+<tags/F
+EOF
+
+test_expect_success 'name-rev --exclude excludes matched patterns' '
+	git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+	git name-rev --stdin --name-only --refs="*tags/*" --exclude="*E" \
+		<actual >actual.named &&
+	test_cmp actual.named expect
+'
+
 test_expect_success 'name-rev --no-refs clears the refs list' '
 	git rev-list --left-right --cherry-pick F...E -- bar >expect &&
 	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* [PATCH v2 2/5] name-rev: extend --refs to accept multiple patterns
From: Jacob Keller @ 2017-01-18  0:03 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000345.31196-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Teach git name-rev to take a string list of patterns from --refs instead
of only a single pattern. The list of patterns will be matched
inclusively, such that a ref only needs to match one pattern to be
included. If a ref will only be excluded if it does not match any of the
patterns.

Add tests and documentation for this change. The tests do use
dynamically generated output as part of the expected output because the
expected output is the raw commit-id and it seemed like a bad idea to
hardcode that into a tests expected output.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/git-name-rev.txt       |  4 +++-
 builtin/name-rev.c                   | 41 +++++++++++++++++++++++++-----------
 t/t6007-rev-list-cherry-pick-file.sh | 26 +++++++++++++++++++++++
 3 files changed, 58 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index ca28fb8e2a07..7433627db12d 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -26,7 +26,9 @@ OPTIONS
 
 --refs=<pattern>::
 	Only use refs whose names match a given shell pattern.  The pattern
-	can be one of branch name, tag name or fully qualified ref name.
+	can be one of branch name, tag name or fully qualified ref name. If
+	given multiple times, use refs whose names match any of the given shell
+	patterns. Use `--no-refs` to clear any previous ref patterns given.
 
 --all::
 	List all commits reachable from all refs
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index cd89d48b65e8..000a2a700ed3 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -108,7 +108,7 @@ static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
 struct name_ref_data {
 	int tags_only;
 	int name_only;
-	const char *ref_filter;
+	struct string_list ref_filters;
 };
 
 static struct tip_table {
@@ -150,16 +150,33 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
 	if (data->tags_only && !starts_with(path, "refs/tags/"))
 		return 0;
 
-	if (data->ref_filter) {
-		switch (subpath_matches(path, data->ref_filter)) {
-		case -1: /* did not match */
-			return 0;
-		case 0:  /* matched fully */
-			break;
-		default: /* matched subpath */
-			can_abbreviate_output = 1;
-			break;
+	if (data->ref_filters.nr) {
+		struct string_list_item *item;
+		int matched = 0;
+
+		/* See if any of the patterns match. */
+		for_each_string_list_item(item, &data->ref_filters) {
+			/*
+			 * We want to check every pattern even if we already
+			 * found a match, just in case one of the later
+			 * patterns could abbreviate the output.
+			 */
+			switch (subpath_matches(path, item->string)) {
+			case -1: /* did not match */
+				break;
+			case 0: /* matched fully */
+				matched = 1;
+				break;
+			default: /* matched subpath */
+				matched = 1;
+				can_abbreviate_output = 1;
+				break;
+			}
 		}
+
+		/* If none of the patterns matched, stop now */
+		if (!matched)
+			return 0;
 	}
 
 	add_to_tip_table(oid->hash, path, can_abbreviate_output);
@@ -306,11 +323,11 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 {
 	struct object_array revs = OBJECT_ARRAY_INIT;
 	int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
-	struct name_ref_data data = { 0, 0, NULL };
+	struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP };
 	struct option opts[] = {
 		OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
 		OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
-		OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"),
+		OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
 				   N_("only use refs matching <pattern>")),
 		OPT_GROUP(""),
 		OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index 1408b608eb03..f724ff24044b 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -99,6 +99,32 @@ test_expect_success '--cherry-pick bar does not come up empty (II)' '
 	test_cmp actual.named expect
 '
 
+test_expect_success 'name-rev multiple --refs combine inclusive' '
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" \
+		<actual >actual.named &&
+	test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+EOF
+
+test_expect_success 'name-rev --refs excludes non-matched patterns' '
+	git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+	git name-rev --stdin --name-only --refs="*tags/F" \
+		<actual >actual.named &&
+	test_cmp actual.named expect
+'
+
+test_expect_success 'name-rev --no-refs clears the refs list' '
+	git rev-list --left-right --cherry-pick F...E -- bar >expect &&
+	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
+		<actual >actual &&
+	test_cmp actual expect
+'
+
 cat >expect <<EOF
 +tags/F
 =tags/D
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* Re: [PATCH] transport submodules: correct error message
From: Stefan Beller @ 2017-01-18  0:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git@vger.kernel.org, Heiko Voigt, Dave Borowitz
In-Reply-To: <xmqq8tq9ckxo.fsf@gitster.mtv.corp.google.com>

On Tue, Jan 17, 2017 at 3:42 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> Trying to push with --recurse-submodules=on-demand would run into
>> the same problem. To fix this issue
>>     1) specifically mention that we looked for branches on the remote.
>
> That makes an incorrect statement ("not found on any remote"---we
> did not inspect all of the said remote, only heads and tags) into an
> irrelevant statement ("not found on any remote branch"---the end
> user would say "so what?  I know it exists there, it's just that not
> all remote refs have corresponding tracking ref locally on our side").

eh. So to be correct we need to tell the user we did not find any match on
a "remote-tracking branch" as the gitglossary puts it.

>
> Perhaps it may be an improvement.
>
>>     2) advertise pushing without recursing into submodules. ("Use this
>>        command to make the error message go away")
>
> Not mentioning "on-demand" may be an improvement for those who do
> use set-up like Dave has,

Daves setup is not a special setup; it is just git@next (later than
1863e05af5) in a repo that happens to have submodules; using
Gerrit as the code review system.

> where remote tracking information is
> incomplete if you only look at heads and refs, in the sense that we
> no longer suggest ineffective workaround.

s/ineffective/an effective/ ?

Yes. I think this is a problem in general with Git and Gerrit, as they have
different assumptions of the refs/ namespace.
(You can obtain all Gerrit changes in flight via fetching the refs/changes/*
similar to you pushing all git.git working branches not to all repositories,
but only https://github.com/gitster/git/)

> But would it be an improvement to suggest --no-recurse-submodules?

Well it is certainly better than the current situation, the user DID
use --recurse-submodules but still git refuses and advises to use
--recurse-submodules, which is understandable with background
knowledge, but very confusing at least.

The hint for --no-recurse-submodules can be understood as:
  "I told you there is something fishy with submodules, now you
  can just ignore this warning and murk up your history as you like."
which let's me question the correctness of assumptions in
1863e05af5^2.

> This issue seems like a property of the particular set-up, as
> opposed to being a one-off issue.  The next, subsequent

until Dave got the changes in the submodules reviewed and they
appear on a target branch, then fetching them, then the warning will
be gone.

> and probably
> all future pushes from that repository will have the same issue
> because the root cause is not due to the relative position of
> commits we have locally vs the tips of remote, but due to the way
> remote tracking is set-up, no?

Yes; ideally we'd have a remote-tracking ref for each change
pushed to Gerrit.

>
> If that is the case, perhaps configuring push.recurseSubmodules to
> turn this off (especially because you plan to turn the defaul to
> "check") and not giving the command line option would give a more
> pleasant end-user experience, I suspect.

I though about going another way and adding another new value
to the enum, such that

    git push --recurse-submodules=sameRefSpecButNoCheck \
        origin HEAD:refs/for/master

works for Gerrit users.

If such a thing exists, then the check is the safest-but-inconvenient
option (in all setups I'd think), and users can switch to either
sameRefSpecButNoCheck (Gerrit) or on-demand (github et al)

^ permalink raw reply

* [PATCH v3 4/5] describe: teach --match to accept multiple patterns
From: Jacob Keller @ 2017-01-18  0:09 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000930.5431-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Teach `--match` to be accepted multiple times, accumulating a list of
patterns to match into a string list. Each pattern is inclusive, such
that a tag need only match one of the provided patterns to be
considered for matching.

This extension is useful as it enables more flexibility in what tags
match, and may avoid the need to run the describe command multiple
times to get the same result.

Add tests and update the documentation for this change.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/git-describe.txt |  5 ++++-
 builtin/describe.c             | 30 +++++++++++++++++++++++-------
 t/t6120-describe.sh            | 19 +++++++++++++++++++
 3 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index e4ac448ff565..7ad41e2f6ade 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -83,7 +83,10 @@ OPTIONS
 --match <pattern>::
 	Only consider tags matching the given `glob(7)` pattern,
 	excluding the "refs/tags/" prefix.  This can be used to avoid
-	leaking private tags from the repository.
+	leaking private tags from the repository. If given multiple times, a
+	list of patterns will be accumulated, and tags matching any of the
+	patterns will be considered. Use `--no-match` to clear and reset the
+	list of patterns.
 
 --always::
 	Show uniquely abbreviated commit object as fallback.
diff --git a/builtin/describe.c b/builtin/describe.c
index 01490a157efc..5cc9e9abe798 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -28,7 +28,7 @@ static int abbrev = -1; /* unspecified */
 static int max_candidates = 10;
 static struct hashmap names;
 static int have_util;
-static const char *pattern;
+static struct string_list patterns = STRING_LIST_INIT_NODUP;
 static int always;
 static const char *dirty;
 
@@ -129,9 +129,24 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
 	if (!all && !is_tag)
 		return 0;
 
-	/* Accept only tags that match the pattern, if given */
-	if (pattern && (!is_tag || wildmatch(pattern, path + 10, 0, NULL)))
-		return 0;
+	/*
+	 * If we're given patterns, accept only tags which match at least one
+	 * pattern.
+	 */
+	if (patterns.nr) {
+		struct string_list_item *item;
+
+		if (!is_tag)
+			return 0;
+
+		for_each_string_list_item(item, &patterns) {
+			if (!wildmatch(item->string, path + 10, 0, NULL))
+				break;
+
+			/* If we get here, no pattern matched. */
+			return 0;
+		}
+	}
 
 	/* Is it annotated? */
 	if (!peel_ref(path, peeled.hash)) {
@@ -404,7 +419,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 			    N_("only output exact matches"), 0),
 		OPT_INTEGER(0, "candidates", &max_candidates,
 			    N_("consider <n> most recent tags (default: 10)")),
-		OPT_STRING(0, "match",       &pattern, N_("pattern"),
+		OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
 			   N_("only consider tags matching <pattern>")),
 		OPT_BOOL(0, "always",        &always,
 			N_("show abbreviated commit object as fallback")),
@@ -430,6 +445,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 		die(_("--long is incompatible with --abbrev=0"));
 
 	if (contains) {
+		struct string_list_item *item;
 		struct argv_array args;
 
 		argv_array_init(&args);
@@ -440,8 +456,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 			argv_array_push(&args, "--always");
 		if (!all) {
 			argv_array_push(&args, "--tags");
-			if (pattern)
-				argv_array_pushf(&args, "--refs=refs/tags/%s", pattern);
+			for_each_string_list_item(item, &patterns)
+				argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
 		}
 		if (argc)
 			argv_array_pushv(&args, argv);
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 85f269411cb3..9e5db9b87a1f 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -182,6 +182,10 @@ check_describe "test2-lightweight-*" --tags --match="test2-*"
 
 check_describe "test2-lightweight-*" --long --tags --match="test2-*" HEAD^
 
+check_describe "test1-lightweight-*" --long --tags --match="test1-*" --match="test2-*" HEAD^
+
+check_describe "test2-lightweight-*" --long --tags --match="test1-*" --no-match --match="test2-*" HEAD^
+
 test_expect_success 'name-rev with exact tags' '
 	echo A >expect &&
 	tag_object=$(git rev-parse refs/tags/A) &&
@@ -206,4 +210,19 @@ test_expect_success 'describe --contains with the exact tags' '
 	test_cmp expect actual
 '
 
+test_expect_success 'describe --contains and --match' '
+	echo "A^0" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	test_must_fail git describe --contains --match="B" $tagged_commit &&
+	git describe --contains --match="B" --match="A" $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'describe --contains and --no-match' '
+	echo "A^0" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	git describe --contains --match="B" --no-match $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* [PATCH v3 5/5] describe: teach describe negative pattern matches
From: Jacob Keller @ 2017-01-18  0:09 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000930.5431-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Teach git-describe the `--exclude` option which will allow specifying
a glob pattern of tags to ignore. This can be combined with the
`--match` patterns to enable more flexibility in determining which tags
to consider.

For example, suppose you wish to find the first official release tag
that contains a certain commit. If we assume that official release tags
are of the form "v*" and pre-release candidates include "*rc*" in their
name, we can now find the first tag that introduces commit abcdef via:

  git describe --contains --match="v*" --exclude="*rc*"

Add documentation and tests for this change.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/git-describe.txt |  8 ++++++++
 builtin/describe.c             | 21 +++++++++++++++++++++
 t/t6120-describe.sh            |  8 ++++++++
 3 files changed, 37 insertions(+)

diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index 7ad41e2f6ade..21a43b78924a 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -88,6 +88,14 @@ OPTIONS
 	patterns will be considered. Use `--no-match` to clear and reset the
 	list of patterns.
 
+--exclude <pattern>::
+	Do not consider tags matching the given `glob(7)` pattern, excluding
+	the "refs/tags/" prefix. This can be used to narrow the tag space and
+	find only tags matching some meaningful criteria. If given multiple
+	times, a list of patterns will be accumulated and tags matching any
+	of the patterns will be excluded. Use `--no-exclude` to clear and
+	reset the list of patterns.
+
 --always::
 	Show uniquely abbreviated commit object as fallback.
 
diff --git a/builtin/describe.c b/builtin/describe.c
index 5cc9e9abe798..6769446e1f57 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -29,6 +29,7 @@ static int max_candidates = 10;
 static struct hashmap names;
 static int have_util;
 static struct string_list patterns = STRING_LIST_INIT_NODUP;
+static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
 static int always;
 static const char *dirty;
 
@@ -130,6 +131,22 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
 		return 0;
 
 	/*
+	 * If we're given exclude patterns, first exclude any tag which match
+	 * any of the exclude pattern.
+	 */
+	if (exclude_patterns.nr) {
+		struct string_list_item *item;
+
+		if (!is_tag)
+			return 0;
+
+		for_each_string_list_item(item, &exclude_patterns) {
+			if (!wildmatch(item->string, path + 10, 0, NULL))
+				return 0;
+		}
+	}
+
+	/*
 	 * If we're given patterns, accept only tags which match at least one
 	 * pattern.
 	 */
@@ -421,6 +438,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 			    N_("consider <n> most recent tags (default: 10)")),
 		OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
 			   N_("only consider tags matching <pattern>")),
+		OPT_STRING_LIST(0, "exclude", &exclude_patterns, N_("pattern"),
+			   N_("do not consider tags matching <pattern>")),
 		OPT_BOOL(0, "always",        &always,
 			N_("show abbreviated commit object as fallback")),
 		{OPTION_STRING, 0, "dirty",  &dirty, N_("mark"),
@@ -458,6 +477,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 			argv_array_push(&args, "--tags");
 			for_each_string_list_item(item, &patterns)
 				argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
+			for_each_string_list_item(item, &exclude_patterns)
+				argv_array_pushf(&args, "--exclude=refs/tags/%s", item->string);
 		}
 		if (argc)
 			argv_array_pushv(&args, argv);
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 9e5db9b87a1f..167491fd5b0d 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -218,6 +218,14 @@ test_expect_success 'describe --contains and --match' '
 	test_cmp expect actual
 '
 
+test_expect_success 'describe --exclude' '
+	echo "c~1" >expect &&
+	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
+	test_must_fail git describe --contains --match="B" $tagged_commit &&
+	git describe --contains --match="?" --exclude="A" $tagged_commit >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'describe --contains and --no-match' '
 	echo "A^0" >expect &&
 	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* [PATCH v3 0/5] extend git-describe pattern matching
From: Jacob Keller @ 2017-01-18  0:09 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller

From: Jacob Keller <jacob.keller@gmail.com>

** v3 fixes a minor typo in one of the test cases, so please ignore v2
   I left the interdiff as between v1 and v3 instead of v2 **

Teach git describe and git name-rev the ability to match multiple
patterns inclusively. Additionally, teach these commands to also accept
negative patterns to exclude any refs which match.

The pattern lists for positive and negative patterns are inclusive. This
means that for the positive patterns, a reference will be considered as
long as it matches at least one of the match patterns. It need not match
all given patterns. Additionally for negative patterns, we will not
consider any ref which matches any negative pattern, even if it matches
one of the positive patterns.

Together this allows the ability to express far more sets of tags than a
single match pattern alone. It does not provide quite the same depth as
would teaching full regexp but it is simpler and easy enough to
understand.

- v2
* use --exclude instead of --discard
* use modern style in tests

- v3
* fix broken test (sorry for the thrash!)

I chose *not* to implement the suggestion of ordered values for exclude
and match, since this is not how the current implementation of
git-describe worked, and it didn't really make sense to me what was
being requested. I looked at the interface for git-log, and it appears
that the command accepts multiple invocations of --branches, --remotes,
and similar. I do not believe these need to be identical interfaces. I
welcome feedback on this decision, but I am not convinced yet that the
ordered arguments are worth the trouble.

diff --git c/Documentation/git-describe.txt w/Documentation/git-describe.txt
index a89bbde207b2..21a43b78924a 100644
--- c/Documentation/git-describe.txt
+++ w/Documentation/git-describe.txt
@@ -88,12 +88,12 @@ OPTIONS
	patterns will be considered. Use `--no-match` to clear and reset the
	list of patterns.
 
---discard <pattern>::
+--exclude <pattern>::
	Do not consider tags matching the given `glob(7)` pattern, excluding
	the "refs/tags/" prefix. This can be used to narrow the tag space and
	find only tags matching some meaningful criteria. If given multiple
	times, a list of patterns will be accumulated and tags matching any
-	of the patterns will be discarded. Use `--no-discard` to clear and
+	of the patterns will be excluded. Use `--no-exclude` to clear and
	reset the list of patterns.
 
 --always::
diff --git c/Documentation/git-name-rev.txt w/Documentation/git-name-rev.txt
index 9b46e5ea9aae..301b4a8d55e6 100644
--- c/Documentation/git-name-rev.txt
+++ w/Documentation/git-name-rev.txt
@@ -30,11 +30,11 @@ OPTIONS
	given multiple times, use refs whose names match any of the given shell
	patterns. Use `--no-refs` to clear any previous ref patterns given.
 
---discard=<pattern>::
+--exclude=<pattern>::
	Do not use any ref whose name matches a given shell pattern. The
	pattern can be one of branch name, tag name or fully qualified ref
-	name. If given multiple times, discard refs that match any of the given
-	shell patterns. Use `--no-discards` to clear the list of discard
+	name. If given multiple times, exclude refs that match any of the given
+	shell patterns. Use `--no-exclude` to clear the list of exclude
	patterns.
 
 --all::
diff --git c/Documentation/technical/api-parse-options.txt w/Documentation/technical/api-parse-options.txt
index 15e876e4c804..6914f54f5f44 100644
--- c/Documentation/technical/api-parse-options.txt
+++ w/Documentation/technical/api-parse-options.txt
@@ -169,9 +169,9 @@ There are some macros to easily define options:
	The string argument is put into `str_var`.
 
 `OPT_STRING_LIST(short, long, &list, arg_str, description)`::
-	Introduce an option with a string argument. Repeated invocations
-	accumulate into a list of strings. Reset and clear the list with
-	`--no-option`.
+	Introduce an option with string argument.
+	The string argument is stored as an element in `&list` which must be a
+	struct string_list. Reset the list using `--no-option`.
 
 `OPT_INTEGER(short, long, &int_var, description)`::
	Introduce an option with integer argument.
diff --git c/builtin/describe.c w/builtin/describe.c
index c09288ee6321..6769446e1f57 100644
--- c/builtin/describe.c
+++ w/builtin/describe.c
@@ -29,7 +29,7 @@ static int max_candidates = 10;
 static struct hashmap names;
 static int have_util;
 static struct string_list patterns = STRING_LIST_INIT_NODUP;
-static struct string_list discard_patterns = STRING_LIST_INIT_NODUP;
+static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
 static int always;
 static const char *dirty;
 
@@ -131,16 +131,16 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
		return 0;
 
	/*
-	 * If we're given discard patterns, first discard any tag which match
-	 * any of the discard pattern.
+	 * If we're given exclude patterns, first exclude any tag which match
+	 * any of the exclude pattern.
	 */
-	if (discard_patterns.nr) {
+	if (exclude_patterns.nr) {
		struct string_list_item *item;
 
		if (!is_tag)
			return 0;
 
-		for_each_string_list_item(item, &discard_patterns) {
+		for_each_string_list_item(item, &exclude_patterns) {
			if (!wildmatch(item->string, path + 10, 0, NULL))
				return 0;
		}
@@ -438,7 +438,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
			    N_("consider <n> most recent tags (default: 10)")),
		OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
			   N_("only consider tags matching <pattern>")),
-		OPT_STRING_LIST(0, "discard", &discard_patterns, N_("pattern"),
+		OPT_STRING_LIST(0, "exclude", &exclude_patterns, N_("pattern"),
			   N_("do not consider tags matching <pattern>")),
		OPT_BOOL(0, "always",        &always,
			N_("show abbreviated commit object as fallback")),
@@ -477,8 +477,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
			argv_array_push(&args, "--tags");
			for_each_string_list_item(item, &patterns)
				argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
-			for_each_string_list_item(item, &discard_patterns)
-				argv_array_pushf(&args, "--discard=refs/tags/%s", item->string);
+			for_each_string_list_item(item, &exclude_patterns)
+				argv_array_pushf(&args, "--exclude=refs/tags/%s", item->string);
		}
		if (argc)
			argv_array_pushv(&args, argv);
diff --git c/builtin/name-rev.c w/builtin/name-rev.c
index 86479c17a7c9..da4a0d7c0fdf 100644
--- c/builtin/name-rev.c
+++ w/builtin/name-rev.c
@@ -109,7 +109,7 @@ struct name_ref_data {
	int tags_only;
	int name_only;
	struct string_list ref_filters;
-	struct string_list discard_filters;
+	struct string_list exclude_filters;
 };
 
 static struct tip_table {
@@ -151,10 +151,10 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
	if (data->tags_only && !starts_with(path, "refs/tags/"))
		return 0;
 
-	if (data->discard_filters.nr) {
+	if (data->exclude_filters.nr) {
		struct string_list_item *item;
 
-		for_each_string_list_item(item, &data->discard_filters) {
+		for_each_string_list_item(item, &data->exclude_filters) {
			if (subpath_matches(path, item->string) >= 0)
				return 0;
		}
@@ -339,7 +339,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
		OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
		OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
				   N_("only use refs matching <pattern>")),
-		OPT_STRING_LIST(0, "discard", &data.discard_filters, N_("pattern"),
+		OPT_STRING_LIST(0, "exclude", &data.exclude_filters, N_("pattern"),
				   N_("ignore refs matching <pattern>")),
		OPT_GROUP(""),
		OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
diff --git c/t/t6007-rev-list-cherry-pick-file.sh w/t/t6007-rev-list-cherry-pick-file.sh
index 8a4c35f6ffee..83838d0da208 100755
--- c/t/t6007-rev-list-cherry-pick-file.sh
+++ w/t/t6007-rev-list-cherry-pick-file.sh
@@ -100,42 +100,43 @@ test_expect_success '--cherry-pick bar does not come up empty (II)' '
 '
 
 test_expect_success 'name-rev multiple --refs combine inclusive' '
-	git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" \
-		< actual > actual.named &&
+		<actual >actual.named &&
	test_cmp actual.named expect
 '
 
 cat >expect <<EOF
 <tags/F
-$(git rev-list --left-right --right-only --cherry-pick F...E -- bar)
 EOF
 
 test_expect_success 'name-rev --refs excludes non-matched patterns' '
-	git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+	git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
	git name-rev --stdin --name-only --refs="*tags/F" \
-		< actual > actual.named &&
-	test_cmp actual.named expect
-'
-
-test_expect_success 'name-rev --discard excludes matched patterns' '
-	git rev-list --left-right --cherry-pick F...E -- bar > actual &&
-	git name-rev --stdin --name-only --refs="*tags/*" --discard="*E" \
-		< actual > actual.named &&
+		<actual >actual.named &&
	test_cmp actual.named expect
 '
 
 cat >expect <<EOF
-$(git rev-list --left-right --cherry-pick F...E -- bar)
+<tags/F
 EOF
 
-test_expect_success 'name-rev --no-refs clears the refs list' '
-	git rev-list --left-right --cherry-pick F...E -- bar > actual &&
-	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
-		< actual > actual.named &&
+test_expect_success 'name-rev --exclude excludes matched patterns' '
+	git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+	git name-rev --stdin --name-only --refs="*tags/*" --exclude="*E" \
+		<actual >actual.named &&
	test_cmp actual.named expect
 '
 
+test_expect_success 'name-rev --no-refs clears the refs list' '
+	git rev-list --left-right --cherry-pick F...E -- bar >expect &&
+	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
+		<expect >actual &&
+	test_cmp actual expect
+'
+
 cat >expect <<EOF
 +tags/F
 =tags/D
diff --git c/t/t6120-describe.sh w/t/t6120-describe.sh
index 4e4a9f2e5305..167491fd5b0d 100755
--- c/t/t6120-describe.sh
+++ w/t/t6120-describe.sh
@@ -218,11 +218,11 @@ test_expect_success 'describe --contains and --match' '
	test_cmp expect actual
 '
 
-test_expect_success 'describe --discard' '
+test_expect_success 'describe --exclude' '
	echo "c~1" >expect &&
	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
	test_must_fail git describe --contains --match="B" $tagged_commit &&
-	git describe --contains --match="?" --discard="A" $tagged_commit >actual &&
+	git describe --contains --match="?" --exclude="A" $tagged_commit >actual &&
	test_cmp expect actual
 '
 

Jacob Keller (5):
  doc: add documentation for OPT_STRING_LIST
  name-rev: extend --refs to accept multiple patterns
  name-rev: add support to exclude refs by pattern match
  describe: teach --match to accept multiple patterns
  describe: teach describe negative pattern matches

 Documentation/git-describe.txt                | 13 ++++++-
 Documentation/git-name-rev.txt                | 11 +++++-
 Documentation/technical/api-parse-options.txt |  5 +++
 builtin/describe.c                            | 51 ++++++++++++++++++++++----
 builtin/name-rev.c                            | 53 +++++++++++++++++++++------
 t/t6007-rev-list-cherry-pick-file.sh          | 38 +++++++++++++++++++
 t/t6120-describe.sh                           | 27 ++++++++++++++
 7 files changed, 177 insertions(+), 21 deletions(-)

-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* [PATCH v3 3/5] name-rev: add support to exclude refs by pattern match
From: Jacob Keller @ 2017-01-18  0:09 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000930.5431-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Extend name-rev further to support matching refs by adding `--exclude`
patterns. These patterns will limit the scope of refs by excluding any
ref that matches at least one exclude pattern. Checking the exclude refs
shall happen first, before checking the include --refs patterns. This
will allow more flexibility to matching certain kinds of references.

Add tests and update Documentation for this change.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/git-name-rev.txt       |  7 +++++++
 builtin/name-rev.c                   | 14 +++++++++++++-
 t/t6007-rev-list-cherry-pick-file.sh | 12 ++++++++++++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index 7433627db12d..301b4a8d55e6 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -30,6 +30,13 @@ OPTIONS
 	given multiple times, use refs whose names match any of the given shell
 	patterns. Use `--no-refs` to clear any previous ref patterns given.
 
+--exclude=<pattern>::
+	Do not use any ref whose name matches a given shell pattern. The
+	pattern can be one of branch name, tag name or fully qualified ref
+	name. If given multiple times, exclude refs that match any of the given
+	shell patterns. Use `--no-exclude` to clear the list of exclude
+	patterns.
+
 --all::
 	List all commits reachable from all refs
 
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 000a2a700ed3..da4a0d7c0fdf 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -109,6 +109,7 @@ struct name_ref_data {
 	int tags_only;
 	int name_only;
 	struct string_list ref_filters;
+	struct string_list exclude_filters;
 };
 
 static struct tip_table {
@@ -150,6 +151,15 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
 	if (data->tags_only && !starts_with(path, "refs/tags/"))
 		return 0;
 
+	if (data->exclude_filters.nr) {
+		struct string_list_item *item;
+
+		for_each_string_list_item(item, &data->exclude_filters) {
+			if (subpath_matches(path, item->string) >= 0)
+				return 0;
+		}
+	}
+
 	if (data->ref_filters.nr) {
 		struct string_list_item *item;
 		int matched = 0;
@@ -323,12 +333,14 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 {
 	struct object_array revs = OBJECT_ARRAY_INIT;
 	int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
-	struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP };
+	struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
 	struct option opts[] = {
 		OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
 		OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
 		OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
 				   N_("only use refs matching <pattern>")),
+		OPT_STRING_LIST(0, "exclude", &data.exclude_filters, N_("pattern"),
+				   N_("ignore refs matching <pattern>")),
 		OPT_GROUP(""),
 		OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
 		OPT_BOOL(0, "stdin", &transform_stdin, N_("read from stdin")),
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index d9827a6389a3..29597451967d 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -118,6 +118,18 @@ test_expect_success 'name-rev --refs excludes non-matched patterns' '
 	test_cmp actual.named expect
 '
 
+cat >expect <<EOF
+<tags/F
+EOF
+
+test_expect_success 'name-rev --exclude excludes matched patterns' '
+	git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+	git name-rev --stdin --name-only --refs="*tags/*" --exclude="*E" \
+		<actual >actual.named &&
+	test_cmp actual.named expect
+'
+
 test_expect_success 'name-rev --no-refs clears the refs list' '
 	git rev-list --left-right --cherry-pick F...E -- bar >expect &&
 	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* [PATCH v3 2/5] name-rev: extend --refs to accept multiple patterns
From: Jacob Keller @ 2017-01-18  0:09 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000930.5431-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Teach git name-rev to take a string list of patterns from --refs instead
of only a single pattern. The list of patterns will be matched
inclusively, such that a ref only needs to match one pattern to be
included. If a ref will only be excluded if it does not match any of the
patterns.

Add tests and documentation for this change. The tests do use
dynamically generated output as part of the expected output because the
expected output is the raw commit-id and it seemed like a bad idea to
hardcode that into a tests expected output.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/git-name-rev.txt       |  4 +++-
 builtin/name-rev.c                   | 41 +++++++++++++++++++++++++-----------
 t/t6007-rev-list-cherry-pick-file.sh | 26 +++++++++++++++++++++++
 3 files changed, 58 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index ca28fb8e2a07..7433627db12d 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -26,7 +26,9 @@ OPTIONS
 
 --refs=<pattern>::
 	Only use refs whose names match a given shell pattern.  The pattern
-	can be one of branch name, tag name or fully qualified ref name.
+	can be one of branch name, tag name or fully qualified ref name. If
+	given multiple times, use refs whose names match any of the given shell
+	patterns. Use `--no-refs` to clear any previous ref patterns given.
 
 --all::
 	List all commits reachable from all refs
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index cd89d48b65e8..000a2a700ed3 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -108,7 +108,7 @@ static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
 struct name_ref_data {
 	int tags_only;
 	int name_only;
-	const char *ref_filter;
+	struct string_list ref_filters;
 };
 
 static struct tip_table {
@@ -150,16 +150,33 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
 	if (data->tags_only && !starts_with(path, "refs/tags/"))
 		return 0;
 
-	if (data->ref_filter) {
-		switch (subpath_matches(path, data->ref_filter)) {
-		case -1: /* did not match */
-			return 0;
-		case 0:  /* matched fully */
-			break;
-		default: /* matched subpath */
-			can_abbreviate_output = 1;
-			break;
+	if (data->ref_filters.nr) {
+		struct string_list_item *item;
+		int matched = 0;
+
+		/* See if any of the patterns match. */
+		for_each_string_list_item(item, &data->ref_filters) {
+			/*
+			 * We want to check every pattern even if we already
+			 * found a match, just in case one of the later
+			 * patterns could abbreviate the output.
+			 */
+			switch (subpath_matches(path, item->string)) {
+			case -1: /* did not match */
+				break;
+			case 0: /* matched fully */
+				matched = 1;
+				break;
+			default: /* matched subpath */
+				matched = 1;
+				can_abbreviate_output = 1;
+				break;
+			}
 		}
+
+		/* If none of the patterns matched, stop now */
+		if (!matched)
+			return 0;
 	}
 
 	add_to_tip_table(oid->hash, path, can_abbreviate_output);
@@ -306,11 +323,11 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 {
 	struct object_array revs = OBJECT_ARRAY_INIT;
 	int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
-	struct name_ref_data data = { 0, 0, NULL };
+	struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP };
 	struct option opts[] = {
 		OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
 		OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
-		OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"),
+		OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
 				   N_("only use refs matching <pattern>")),
 		OPT_GROUP(""),
 		OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index 1408b608eb03..d9827a6389a3 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -99,6 +99,32 @@ test_expect_success '--cherry-pick bar does not come up empty (II)' '
 	test_cmp actual.named expect
 '
 
+test_expect_success 'name-rev multiple --refs combine inclusive' '
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" \
+		<actual >actual.named &&
+	test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+EOF
+
+test_expect_success 'name-rev --refs excludes non-matched patterns' '
+	git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+	git name-rev --stdin --name-only --refs="*tags/F" \
+		<actual >actual.named &&
+	test_cmp actual.named expect
+'
+
+test_expect_success 'name-rev --no-refs clears the refs list' '
+	git rev-list --left-right --cherry-pick F...E -- bar >expect &&
+	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
+		<expect >actual &&
+	test_cmp actual expect
+'
+
 cat >expect <<EOF
 +tags/F
 =tags/D
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* [PATCH v3 1/5] doc: add documentation for OPT_STRING_LIST
From: Jacob Keller @ 2017-01-18  0:09 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller
In-Reply-To: <20170118000930.5431-1-jacob.e.keller@intel.com>

From: Jacob Keller <jacob.keller@gmail.com>

Commit c8ba16391655 ("parse-options: add OPT_STRING_LIST helper",
2011-06-09) added the OPT_STRING_LIST as a way to accumulate a repeated
list of strings. However, this was not documented in the
api-parse-options documentation. Add documentation now so that future
developers may learn of its existence.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
 Documentation/technical/api-parse-options.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 27bd701c0d68..6914f54f5f44 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -168,6 +168,11 @@ There are some macros to easily define options:
 	Introduce an option with string argument.
 	The string argument is put into `str_var`.
 
+`OPT_STRING_LIST(short, long, &list, arg_str, description)`::
+	Introduce an option with string argument.
+	The string argument is stored as an element in `&list` which must be a
+	struct string_list. Reset the list using `--no-option`.
+
 `OPT_INTEGER(short, long, &int_var, description)`::
 	Introduce an option with integer argument.
 	The integer is put into `int_var`.
-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* [PATCH v2 0/5] extend git-describe pattern matching
From: Jacob Keller @ 2017-01-18  0:03 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Johannes Schindelin, Junio C Hamano, Jacob Keller

From: Jacob Keller <jacob.keller@gmail.com>

Teach git describe and git name-rev the ability to match multiple
patterns inclusively. Additionally, teach these commands to also accept
negative patterns to exclude any refs which match.

The pattern lists for positive and negative patterns are inclusive. This
means that for the positive patterns, a reference will be considered as
long as it matches at least one of the match patterns. It need not match
all given patterns. Additionally for negative patterns, we will not
consider any ref which matches any negative pattern, even if it matches
one of the positive patterns.

Together this allows the ability to express far more sets of tags than a
single match pattern alone. It does not provide quite the same depth as
would teaching full regexp but it is simpler and easy enough to
understand.

- v2
* use --exclude instead of --discard
* use modern style in tests

I chose *not* to implement the suggestion of ordered values for exclude
and match, since this is not how the current implementation of
git-describe worked, and it didn't really make sense to me what was
being requested. I looked at the interface for git-log, and it appears
that the command accepts multiple invocations of --branches, --remotes,
and similar. I do not believe these need to be identical interfaces. I
welcome feedback on this decision, but I am not convinced yet that the
ordered arguments are worth the trouble.

diff --git c/Documentation/git-describe.txt w/Documentation/git-describe.txt
index a89bbde207b2..21a43b78924a 100644
--- c/Documentation/git-describe.txt
+++ w/Documentation/git-describe.txt
@@ -88,12 +88,12 @@ OPTIONS
	patterns will be considered. Use `--no-match` to clear and reset the
	list of patterns.
 
---discard <pattern>::
+--exclude <pattern>::
	Do not consider tags matching the given `glob(7)` pattern, excluding
	the "refs/tags/" prefix. This can be used to narrow the tag space and
	find only tags matching some meaningful criteria. If given multiple
	times, a list of patterns will be accumulated and tags matching any
-	of the patterns will be discarded. Use `--no-discard` to clear and
+	of the patterns will be excluded. Use `--no-exclude` to clear and
	reset the list of patterns.
 
 --always::
diff --git c/Documentation/git-name-rev.txt w/Documentation/git-name-rev.txt
index 9b46e5ea9aae..301b4a8d55e6 100644
--- c/Documentation/git-name-rev.txt
+++ w/Documentation/git-name-rev.txt
@@ -30,11 +30,11 @@ OPTIONS
	given multiple times, use refs whose names match any of the given shell
	patterns. Use `--no-refs` to clear any previous ref patterns given.
 
---discard=<pattern>::
+--exclude=<pattern>::
	Do not use any ref whose name matches a given shell pattern. The
	pattern can be one of branch name, tag name or fully qualified ref
-	name. If given multiple times, discard refs that match any of the given
-	shell patterns. Use `--no-discards` to clear the list of discard
+	name. If given multiple times, exclude refs that match any of the given
+	shell patterns. Use `--no-exclude` to clear the list of exclude
	patterns.
 
 --all::
diff --git c/Documentation/technical/api-parse-options.txt w/Documentation/technical/api-parse-options.txt
index 15e876e4c804..6914f54f5f44 100644
--- c/Documentation/technical/api-parse-options.txt
+++ w/Documentation/technical/api-parse-options.txt
@@ -169,9 +169,9 @@ There are some macros to easily define options:
	The string argument is put into `str_var`.
 
 `OPT_STRING_LIST(short, long, &list, arg_str, description)`::
-	Introduce an option with a string argument. Repeated invocations
-	accumulate into a list of strings. Reset and clear the list with
-	`--no-option`.
+	Introduce an option with string argument.
+	The string argument is stored as an element in `&list` which must be a
+	struct string_list. Reset the list using `--no-option`.
 
 `OPT_INTEGER(short, long, &int_var, description)`::
	Introduce an option with integer argument.
diff --git c/builtin/describe.c w/builtin/describe.c
index c09288ee6321..6769446e1f57 100644
--- c/builtin/describe.c
+++ w/builtin/describe.c
@@ -29,7 +29,7 @@ static int max_candidates = 10;
 static struct hashmap names;
 static int have_util;
 static struct string_list patterns = STRING_LIST_INIT_NODUP;
-static struct string_list discard_patterns = STRING_LIST_INIT_NODUP;
+static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
 static int always;
 static const char *dirty;
 
@@ -131,16 +131,16 @@ static int get_name(const char *path, const struct object_id *oid, int flag, voi
		return 0;
 
	/*
-	 * If we're given discard patterns, first discard any tag which match
-	 * any of the discard pattern.
+	 * If we're given exclude patterns, first exclude any tag which match
+	 * any of the exclude pattern.
	 */
-	if (discard_patterns.nr) {
+	if (exclude_patterns.nr) {
		struct string_list_item *item;
 
		if (!is_tag)
			return 0;
 
-		for_each_string_list_item(item, &discard_patterns) {
+		for_each_string_list_item(item, &exclude_patterns) {
			if (!wildmatch(item->string, path + 10, 0, NULL))
				return 0;
		}
@@ -438,7 +438,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
			    N_("consider <n> most recent tags (default: 10)")),
		OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
			   N_("only consider tags matching <pattern>")),
-		OPT_STRING_LIST(0, "discard", &discard_patterns, N_("pattern"),
+		OPT_STRING_LIST(0, "exclude", &exclude_patterns, N_("pattern"),
			   N_("do not consider tags matching <pattern>")),
		OPT_BOOL(0, "always",        &always,
			N_("show abbreviated commit object as fallback")),
@@ -477,8 +477,8 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
			argv_array_push(&args, "--tags");
			for_each_string_list_item(item, &patterns)
				argv_array_pushf(&args, "--refs=refs/tags/%s", item->string);
-			for_each_string_list_item(item, &discard_patterns)
-				argv_array_pushf(&args, "--discard=refs/tags/%s", item->string);
+			for_each_string_list_item(item, &exclude_patterns)
+				argv_array_pushf(&args, "--exclude=refs/tags/%s", item->string);
		}
		if (argc)
			argv_array_pushv(&args, argv);
diff --git c/builtin/name-rev.c w/builtin/name-rev.c
index 86479c17a7c9..da4a0d7c0fdf 100644
--- c/builtin/name-rev.c
+++ w/builtin/name-rev.c
@@ -109,7 +109,7 @@ struct name_ref_data {
	int tags_only;
	int name_only;
	struct string_list ref_filters;
-	struct string_list discard_filters;
+	struct string_list exclude_filters;
 };
 
 static struct tip_table {
@@ -151,10 +151,10 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
	if (data->tags_only && !starts_with(path, "refs/tags/"))
		return 0;
 
-	if (data->discard_filters.nr) {
+	if (data->exclude_filters.nr) {
		struct string_list_item *item;
 
-		for_each_string_list_item(item, &data->discard_filters) {
+		for_each_string_list_item(item, &data->exclude_filters) {
			if (subpath_matches(path, item->string) >= 0)
				return 0;
		}
@@ -339,7 +339,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
		OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
		OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
				   N_("only use refs matching <pattern>")),
-		OPT_STRING_LIST(0, "discard", &data.discard_filters, N_("pattern"),
+		OPT_STRING_LIST(0, "exclude", &data.exclude_filters, N_("pattern"),
				   N_("ignore refs matching <pattern>")),
		OPT_GROUP(""),
		OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
diff --git c/t/t6007-rev-list-cherry-pick-file.sh w/t/t6007-rev-list-cherry-pick-file.sh
index 8a4c35f6ffee..83838d0da208 100755
--- c/t/t6007-rev-list-cherry-pick-file.sh
+++ w/t/t6007-rev-list-cherry-pick-file.sh
@@ -100,42 +100,43 @@ test_expect_success '--cherry-pick bar does not come up empty (II)' '
 '
 
 test_expect_success 'name-rev multiple --refs combine inclusive' '
-	git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" \
-		< actual > actual.named &&
+		<actual >actual.named &&
	test_cmp actual.named expect
 '
 
 cat >expect <<EOF
 <tags/F
-$(git rev-list --left-right --right-only --cherry-pick F...E -- bar)
 EOF
 
 test_expect_success 'name-rev --refs excludes non-matched patterns' '
-	git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+	git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
	git name-rev --stdin --name-only --refs="*tags/F" \
-		< actual > actual.named &&
-	test_cmp actual.named expect
-'
-
-test_expect_success 'name-rev --discard excludes matched patterns' '
-	git rev-list --left-right --cherry-pick F...E -- bar > actual &&
-	git name-rev --stdin --name-only --refs="*tags/*" --discard="*E" \
-		< actual > actual.named &&
+		<actual >actual.named &&
	test_cmp actual.named expect
 '
 
 cat >expect <<EOF
-$(git rev-list --left-right --cherry-pick F...E -- bar)
+<tags/F
 EOF
 
-test_expect_success 'name-rev --no-refs clears the refs list' '
-	git rev-list --left-right --cherry-pick F...E -- bar > actual &&
-	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
-		< actual > actual.named &&
+test_expect_success 'name-rev --exclude excludes matched patterns' '
+	git rev-list --left-right --right-only --cherry-pick F...E -- bar >>expect &&
+	git rev-list --left-right --cherry-pick F...E -- bar >actual &&
+	git name-rev --stdin --name-only --refs="*tags/*" --exclude="*E" \
+		<actual >actual.named &&
	test_cmp actual.named expect
 '
 
+test_expect_success 'name-rev --no-refs clears the refs list' '
+	git rev-list --left-right --cherry-pick F...E -- bar >expect &&
+	git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
+		<actual >actual &&
+	test_cmp actual expect
+'
+
 cat >expect <<EOF
 +tags/F
 =tags/D
diff --git c/t/t6120-describe.sh w/t/t6120-describe.sh
index 4e4a9f2e5305..167491fd5b0d 100755
--- c/t/t6120-describe.sh
+++ w/t/t6120-describe.sh
@@ -218,11 +218,11 @@ test_expect_success 'describe --contains and --match' '
	test_cmp expect actual
 '
 
-test_expect_success 'describe --discard' '
+test_expect_success 'describe --exclude' '
	echo "c~1" >expect &&
	tagged_commit=$(git rev-parse "refs/tags/A^0") &&
	test_must_fail git describe --contains --match="B" $tagged_commit &&
-	git describe --contains --match="?" --discard="A" $tagged_commit >actual &&
+	git describe --contains --match="?" --exclude="A" $tagged_commit >actual &&
	test_cmp expect actual
 '
 

Jacob Keller (5):
  doc: add documentation for OPT_STRING_LIST
  name-rev: extend --refs to accept multiple patterns
  name-rev: add support to exclude refs by pattern match
  describe: teach --match to accept multiple patterns
  describe: teach describe negative pattern matches

 Documentation/git-describe.txt                | 13 ++++++-
 Documentation/git-name-rev.txt                | 11 +++++-
 Documentation/technical/api-parse-options.txt |  5 +++
 builtin/describe.c                            | 51 ++++++++++++++++++++++----
 builtin/name-rev.c                            | 53 +++++++++++++++++++++------
 t/t6007-rev-list-cherry-pick-file.sh          | 38 +++++++++++++++++++
 t/t6120-describe.sh                           | 27 ++++++++++++++
 7 files changed, 177 insertions(+), 21 deletions(-)

-- 
2.11.0.403.g196674b8396b


^ permalink raw reply related

* Re: [PATCH v6 4/6] builtin/tag: add --format argument for tag -v
From: Junio C Hamano @ 2017-01-18  0:19 UTC (permalink / raw)
  To: santiago; +Cc: git, peff, sunshine, walters, Lukas Puehringer
In-Reply-To: <20170117233723.23897-5-santiago@nyu.edu>

santiago@nyu.edu writes:

> @@ -428,9 +443,12 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
>  	if (filter.merge_commit)
>  		die(_("--merged and --no-merged option are only allowed with -l"));
>  	if (cmdmode == 'd')
> -		return for_each_tag_name(argv, delete_tag);
> -	if (cmdmode == 'v')
> -		return for_each_tag_name(argv, verify_tag);
> +		return for_each_tag_name(argv, delete_tag, NULL);
> +	if (cmdmode == 'v') {
> +		if (format)
> +			verify_ref_format(format);
> +		return for_each_tag_name(argv, verify_tag, format);
> +	}

This triggers:

    builtin/tag.c: In function 'cmd_tag':
    builtin/tag.c:451:3: error: passing argument 3 of
    'for_each_tag_name' discards 'const' qualifier from pointer target type [-Werror]
       return for_each_tag_name(argv, verify_tag, format);

Either for-each-tag-name's new parameter needs to be typed
correctly, or the type of the "format" variable needs to be updated.

^ permalink raw reply

* Re: [PATCH] transport submodules: correct error message
From: Stefan Beller @ 2017-01-18  0:21 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git@vger.kernel.org, Heiko Voigt, Dave Borowitz
In-Reply-To: <xmqqr341b4vm.fsf@gitster.mtv.corp.google.com>

On Tue, Jan 17, 2017 at 4:15 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> On Tue, Jan 17, 2017 at 3:42 PM, Junio C Hamano <gitster@pobox.com> wrote:
>>> Stefan Beller <sbeller@google.com> writes:
>>>
>>>> Trying to push with --recurse-submodules=on-demand would run into
>>>> the same problem. To fix this issue
>>>>     1) specifically mention that we looked for branches on the remote.
>>>
>>> That makes an incorrect statement ("not found on any remote"---we
>>> did not inspect all of the said remote, only heads and tags) into an
>>> irrelevant statement ("not found on any remote branch"---the end
>>> user would say "so what?  I know it exists there, it's just that not
>>> all remote refs have corresponding tracking ref locally on our side").
>>
>> eh. So to be correct we need to tell the user we did not find any match on
>> a "remote-tracking branch" as the gitglossary puts it.
>
> I think the updated text is already "correct".  I am pointing out
> that it may be correct but not very helpful to the users.
>
>>> where remote tracking information is
>>> incomplete if you only look at heads and refs, in the sense that we
>>> no longer suggest ineffective workaround.
>>
>> s/ineffective/an effective/ ?
>
> Even though I make many typoes, I meant ineffective in this case.
> "The old message suggested workaround that would not help.  You no
> longer give that workaround that does not work."

Oh, I misunderstood the original as I lumped on-demand and check
together mentally, because in the Gerrit world they behave similar.
(Both error out; in the on-demand case the server produces the failure
message, though)

>
>>> If that is the case, perhaps configuring push.recurseSubmodules to
>>> turn this off (especially because you plan to turn the defaul to
>>> "check") and not giving the command line option would give a more
>>> pleasant end-user experience, I suspect.
>>
>> I though about going another way and adding another new value
>> to the enum, such that
>>
>>     git push --recurse-submodules=sameRefSpecButNoCheck \
>>         origin HEAD:refs/for/master
>>
>> works for Gerrit users.
>
> It is unclear what that enum tells Git to do.  Care to explain?  How
> is it different from "no"?

In those submodules, that are checked positively, blindly run
git -C ${sub} push ${ref_spec} and do not double check again,
which we currently do in the on-demand case.

^ permalink raw reply

* Re: [PATCH] transport submodules: correct error message
From: Junio C Hamano @ 2017-01-18  0:15 UTC (permalink / raw)
  To: Stefan Beller; +Cc: git@vger.kernel.org, Heiko Voigt, Dave Borowitz
In-Reply-To: <CAGZ79kYu1Y2pwk9+kbSrMxwP3S0n8FMW6f4wdEE0mrACqrOPNA@mail.gmail.com>

Stefan Beller <sbeller@google.com> writes:

> On Tue, Jan 17, 2017 at 3:42 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> Stefan Beller <sbeller@google.com> writes:
>>
>>> Trying to push with --recurse-submodules=on-demand would run into
>>> the same problem. To fix this issue
>>>     1) specifically mention that we looked for branches on the remote.
>>
>> That makes an incorrect statement ("not found on any remote"---we
>> did not inspect all of the said remote, only heads and tags) into an
>> irrelevant statement ("not found on any remote branch"---the end
>> user would say "so what?  I know it exists there, it's just that not
>> all remote refs have corresponding tracking ref locally on our side").
>
> eh. So to be correct we need to tell the user we did not find any match on
> a "remote-tracking branch" as the gitglossary puts it.

I think the updated text is already "correct".  I am pointing out
that it may be correct but not very helpful to the users.

>> where remote tracking information is
>> incomplete if you only look at heads and refs, in the sense that we
>> no longer suggest ineffective workaround.
>
> s/ineffective/an effective/ ?

Even though I make many typoes, I meant ineffective in this case.
"The old message suggested workaround that would not help.  You no
longer give that workaround that does not work."

>> If that is the case, perhaps configuring push.recurseSubmodules to
>> turn this off (especially because you plan to turn the defaul to
>> "check") and not giving the command line option would give a more
>> pleasant end-user experience, I suspect.
>
> I though about going another way and adding another new value
> to the enum, such that
>
>     git push --recurse-submodules=sameRefSpecButNoCheck \
>         origin HEAD:refs/for/master
>
> works for Gerrit users.

It is unclear what that enum tells Git to do.  Care to explain?  How
is it different from "no"?

^ permalink raw reply

* [PATCH 4/4] documentation: retire unfinished documentation
From: Stefan Beller @ 2017-01-17 23:35 UTC (permalink / raw)
  To: gitster; +Cc: git, Stefan Beller
In-Reply-To: <20170117233503.27137-1-sbeller@google.com>

When looking for documentation for a specific function, you may be tempted
to run

  git -C Documentation grep index_name_pos

only to find the file technical/api-in-core-index.txt, which doesn't
help for understanding the given function. It would be better to not find
these functions in the documentation, such that people directly dive into
the code instead.

In the previous patches we have documented
* index_name_pos()
* remove_index_entry_at()
* add_[file_]to_index()
in cache.h

We already have documentation for:
* add_index_entry()
* read_index()

Which leaves us with a TODO for:
* cache -> the_index macros
* refresh_index()
* discard_index()
* ie_match_stat() and ie_modified(); how they are different and when to
  use which.
* write_index() that was renamed to write_locked_index
* cache_tree_invalidate_path()
* cache_tree_update()

Signed-off-by: Stefan Beller <sbeller@google.com>
---
 Documentation/technical/api-in-core-index.txt | 21 ---------------------
 1 file changed, 21 deletions(-)
 delete mode 100644 Documentation/technical/api-in-core-index.txt

diff --git a/Documentation/technical/api-in-core-index.txt b/Documentation/technical/api-in-core-index.txt
deleted file mode 100644
index adbdbf5d75..0000000000
--- a/Documentation/technical/api-in-core-index.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-in-core index API
-=================
-
-Talk about <read-cache.c> and <cache-tree.c>, things like:
-
-* cache -> the_index macros
-* read_index()
-* write_index()
-* ie_match_stat() and ie_modified(); how they are different and when to
-  use which.
-* index_name_pos()
-* remove_index_entry_at()
-* remove_file_from_index()
-* add_file_to_index()
-* add_index_entry()
-* refresh_index()
-* discard_index()
-* cache_tree_invalidate_path()
-* cache_tree_update()
-
-(JC, Linus)
-- 
2.11.0.299.g762782ba8a


^ permalink raw reply related

* [PATCHv3 4/4] unpack-trees: support super-prefix option
From: Stefan Beller @ 2017-01-18  1:05 UTC (permalink / raw)
  To: gitster; +Cc: git, bmwill, novalis, Stefan Beller
In-Reply-To: <xmqqh94zbwlu.fsf@gitster.mtv.corp.google.com>

In the future we want to support working tree operations within submodules,
e.g. "git checkout --recurse-submodules", which will update the submodule
to the commit as recorded in its superproject. In the submodule the
unpack-tree operation is carried out as usual, but the reporting to the
user needs to prefix any path with the superproject. The mechanism for
this is the super-prefix. (see 74866d757, git: make super-prefix option)

Add support for the super-prefix option for commands that unpack trees
by wrapping any path output in unpacking trees in the newly introduced
super_prefixed function. This new function prefixes any path with the
super-prefix if there is one.  Assuming the submodule case doesn't happen
in the majority of the cases, we'd want to have a fast behavior for no
super prefix, i.e. no reallocation/copying, but just returning path.

Another aspect of introducing the `super_prefixed` function is to consider
who owns the memory and if this is the right place where the path gets
modified. As the super prefix ought to change the output behavior only and
not the actual unpack tree part, it is fine to be that late in the line.
As we get passed in 'const char *path', we cannot change the path itself,
which means in case of a super prefix we have to copy over the path.
We need two static buffers in that function as the error messages
contain at most two paths.

For testing purposes enable it in read-tree, which has no output
of paths other than an unpack-trees.c. These are all converted in
this patch.

Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---

This replaces the last two commits (squash and unpack-trees:
support super-prefix option) of sb/unpack-trees-super-prefix.

> * sb/unpack-trees-super-prefix (2017-01-12) 5 commits
>  - SQUASH
>  - unpack-trees: support super-prefix option
>  - t1001: modernize style
>  - t1000: modernize style
>  - read-tree: use OPT_BOOL instead of OPT_SET_INT
>
>  "git read-tree" and its underlying unpack_trees() machinery learned
>  to report problematic paths prefixed with the --super-prefix option.
>
>  Expecting a reroll.
>  The first three are in good shape.  The last one needs a better
>  explanation and possibly an update to its test.
>  cf. <CAGZ79kaHDnVLQr8WLoaD5KKs7EqeW=KbkptF=iHpU5t054Xcdw@mail.gmail.com>
>

This paragraph is for the first version of the last patch?
I reviewed what you queued and both the test is in modern
style as well as the commit message is adequate now.

I agree the SQUASH commit is a good idea, so this is a reroll
with the SQUASH squashed.  No further changes applied.

Thanks,
Stefan

 git.c                       |  2 +-
 t/t1001-read-tree-m-2way.sh |  8 ++++++++
 unpack-trees.c              | 43 ++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/git.c b/git.c
index bbaa949e9c..50e559c2a8 100644
--- a/git.c
+++ b/git.c
@@ -471,7 +471,7 @@ static struct cmd_struct commands[] = {
 	{ "prune-packed", cmd_prune_packed, RUN_SETUP },
 	{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
 	{ "push", cmd_push, RUN_SETUP },
-	{ "read-tree", cmd_read_tree, RUN_SETUP },
+	{ "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
 	{ "receive-pack", cmd_receive_pack },
 	{ "reflog", cmd_reflog, RUN_SETUP },
 	{ "remote", cmd_remote, RUN_SETUP },
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 7b70089705..5ededd8e40 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -363,6 +363,14 @@ test_expect_success 'a/b (untracked) vs a, plus c/d case test.' '
 	test -f a/b
 '
 
+test_expect_success 'read-tree supports the super-prefix' '
+	cat <<-EOF >expect &&
+		error: Updating '\''fictional/a'\'' would lose untracked files in it
+	EOF
+	test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'a/b vs a, plus c/d case setup.' '
 	rm -f .git/index &&
 	rm -fr a &&
diff --git a/unpack-trees.c b/unpack-trees.c
index 7a6df99d10..eee4865804 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -52,6 +52,41 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
 	  ? ((o)->msgs[(type)])      \
 	  : (unpack_plumbing_errors[(type)]) )
 
+static const char *super_prefixed(const char *path)
+{
+	/*
+	 * It is necessary and sufficient to have two static buffers
+	 * here, as the return value of this function is fed to
+	 * error() using the unpack_*_errors[] templates we see above.
+	 */
+	static struct strbuf buf[2] = {STRBUF_INIT, STRBUF_INIT};
+	static int super_prefix_len = -1;
+	static unsigned idx = ARRAY_SIZE(buf) - 1;
+
+	if (super_prefix_len < 0) {
+		const char *super_prefix = get_super_prefix();
+		if (!super_prefix) {
+			super_prefix_len = 0;
+		} else {
+			int i;
+			for (i = 0; i < ARRAY_SIZE(buf); i++)
+				strbuf_addstr(&buf[i], super_prefix);
+			super_prefix_len = buf[0].len;
+		}
+	}
+
+	if (!super_prefix_len)
+		return path;
+
+	if (++idx >= ARRAY_SIZE(buf))
+		idx = 0;
+
+	strbuf_setlen(&buf[idx], super_prefix_len);
+	strbuf_addstr(&buf[idx], path);
+
+	return buf[idx].buf;
+}
+
 void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
 				  const char *cmd)
 {
@@ -172,7 +207,7 @@ static int add_rejected_path(struct unpack_trees_options *o,
 			     const char *path)
 {
 	if (!o->show_all_errors)
-		return error(ERRORMSG(o, e), path);
+		return error(ERRORMSG(o, e), super_prefixed(path));
 
 	/*
 	 * Otherwise, insert in a list for future display by
@@ -196,7 +231,7 @@ static void display_error_msgs(struct unpack_trees_options *o)
 			something_displayed = 1;
 			for (i = 0; i < rejects->nr; i++)
 				strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
-			error(ERRORMSG(o, e), path.buf);
+			error(ERRORMSG(o, e), super_prefixed(path.buf));
 			strbuf_release(&path);
 		}
 		string_list_clear(rejects, 0);
@@ -1918,7 +1953,9 @@ int bind_merge(const struct cache_entry * const *src,
 			     o->merge_size);
 	if (a && old)
 		return o->gently ? -1 :
-			error(ERRORMSG(o, ERROR_BIND_OVERLAP), a->name, old->name);
+			error(ERRORMSG(o, ERROR_BIND_OVERLAP),
+			      super_prefixed(a->name),
+			      super_prefixed(old->name));
 	if (!a)
 		return keep_entry(old, o);
 	else
-- 
2.11.0.299.g762782ba8a


^ permalink raw reply related

* "git diff --ignore-space-change --stat" lists files with only whitespace differences as "changed"
From: Matt McCutchen @ 2017-01-18  2:01 UTC (permalink / raw)
  To: git

A bug report: I noticed that "git diff --ignore-space-change --stat"
lists files with only whitespace differences as having changed with 0
differing lines.  This is inconsistent with the behavior without --
stat, which doesn't list such files at all.  (Same behavior with all
the --ignore*space* flags.)  I can reproduce this with the current
"next", af746e4.  Quick test case:

echo ' ' >test1 && echo '  ' >test2 &&
git diff --stat --no-index --ignore-space-change test1 test2

This caused me some inconvenience in the following scenario: I was
reading a commit diff that had a bulk license change in all files
combined with code changes.  I attempted to revert the bulk license
change locally using "sed" to more easily read the code diff, but my
reversion left some whitespace diffs where the original files had
inconsistent whitespace.  So the diffstat after my reversion was
cluttered with these "0" entries.

Regards,
Matt

^ permalink raw reply

* [PATCH] gitk: remove translated message from comments
From: David Aguilar @ 2017-01-18  3:52 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Junio C Hamano, git
In-Reply-To: <xmqq4m0xpmbz.fsf@gitster.mtv.corp.google.com>

"make update-po" fails because a previously untranslated string
has now been translated:

	Updating po/sv.po
	po/sv.po:1388: duplicate message definition...
	po/sv.po:380: ...this is the location of the first definition

Remove the duplicate message definition.

Reported-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: David Aguilar <davvid@gmail.com>
---
 po/sv.po | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/po/sv.po b/po/sv.po
index 32fc752..2a06fe5 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -1385,21 +1385,6 @@ msgstr "Felaktiga argument till gitk:"
 #~ msgid "mc"
 #~ msgstr "mc"
 
-#~ msgid ""
-#~ "\n"
-#~ "Gitk - a commit viewer for git\n"
-#~ "\n"
-#~ "Copyright © 2005-2016 Paul Mackerras\n"
-#~ "\n"
-#~ "Use and redistribute under the terms of the GNU General Public License"
-#~ msgstr ""
-#~ "\n"
-#~ "Gitk - en incheckningsvisare för git\n"
-#~ "\n"
-#~ "Copyright © 2005-2016 Paul Mackerras\n"
-#~ "\n"
-#~ "Använd och vidareförmedla enligt villkoren i GNU General Public License"
-
 #~ msgid "next"
 #~ msgstr "nästa"
 
-- 
2.11.0.536.gaf746e49c2


^ permalink raw reply related

* difflame
From: Edmundo Carmona Antoranz @ 2017-01-18  5:24 UTC (permalink / raw)
  To: Git List

Hi!

For a very long time I had wanted to get the output of diff to include
blame information as well (to see when something was added/removed).

I just created a very small (and rough) tool for that purpose. It's
written in python and if it gets to something better than a small
tool, I think it could be worth to be added into git main (perhaps
into contrib?).

If you want to give ir a try:
https://github.com/eantoranz/difflame

Just provide the two treeishs you would like to diff (no more
parameters are accepted at the time) and you will get the diff along
with blame. Running it right now on the project itself:

✔ ~/difflame [master L|⚑ 1]
23:21 $ ./difflame.py HEAD~3 HEAD~
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..a82aa27
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,11 @@
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600  1) difflame
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600  2)
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600  3)
Copyright 2017 Edmundo Carmona Antoranz
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600  4)
Released under the terms of GPLv2
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600  5)
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600  6) Show
the output of diff with the additional information of blame.
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600  7)
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600  8)
Lines that remain the same or that were added will indicate when those
lines were 'added' to the file
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600  9)
Lines that were removed will display the last revision where those
lines were _present_ on the file (as provided by blame --re
verse)
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600 10)
+3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600 11) At
the moment, only two parameters need to be provided: two treeishs to
get the diff from
diff --git a/difflame.py b/difflame.py
index f6e879b..06bfc03 100755
--- a/difflame.py
+++ b/difflame.py
@@ -112,16 +112,20 @@ def process_file_from_diff_output(output_lines,
starting_line):
c661286f (Edmundo Carmona Antoranz 2017-01-17 20:10:07 -0600 112)
diff_line = output_lines[i].split()
c661286f (Edmundo Carmona Antoranz 2017-01-17 20:10:07 -0600 113)
if diff_line[0] != "diff":
c661286f (Edmundo Carmona Antoranz 2017-01-17 20:10:07 -0600 114)
   raise Exception("Doesn't seem to exist a 'diff' line at line " +
str(i + 1) + ": " + output_lines[i])
-3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600 115)
original_name = diff_line[1]
-3d426842 (Edmundo Carmona Antoranz 2017-01-17 22:26:18 -0600 116)
final_name = diff_line[2]
+f135bf04 (Edmundo Carmona Antoranz 2017-01-17 22:50:50 -0600 115)
original_name = diff_line[2]
+f135bf04 (Edmundo Carmona Antoranz 2017-01-17 22:50:50 -0600 116)
final_name = diff_line[3]
c661286f (Edmundo Carmona Antoranz 2017-01-17 20:10:07 -0600 117)
print output_lines[i]; i+=1
.
.
.


Hope you find it useful

Best regards!

^ permalink raw reply related

* Re: What's cooking in git.git (Jan 2017, #02; Sun, 15)
From: Johannes Sixt @ 2017-01-18  6:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Johannes Schindelin, git
In-Reply-To: <xmqqo9z5fqdj.fsf@gitster.mtv.corp.google.com>

Am 17.01.2017 um 20:17 schrieb Junio C Hamano:
> So... can we move this forward?

I have no objects anymore.

-- Hannes


^ permalink raw reply

* Re: [RFH - Tcl/Tk] use of procedure before declaration?
From: Konstantin Khomoutov @ 2017-01-18  6:43 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Philip Oakley, Git List, Pat Thoyts
In-Reply-To: <alpine.DEB.2.20.1701171218260.3469@virtualbox>

On Tue, 17 Jan 2017 12:29:23 +0100 (CET)
Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:

> > In
> > https://github.com/git/git/blob/master/git-gui/lib/choose_repository.tcl#L242
> > the procedure `_unset_recentrepo` is called, however the procedure
> > isn't declared until line 248. My reading of the various Tcl
> > tutorials suggest (but not explictly) that this isn't the right way.
> 
> Indeed, calling a procedure before it is declared sounds incorrect.
[...]
> And it is perfectly legitimate to use not-yet-declared procedures in
> other procedures, otherwise recursion would not work.
[...]

Sorry for chiming in too late, but I'd throw a bit of theory in.

Since Tcl is an interpreter (though it automatically compiles certain
stuff to bytecode as it goes through the script, and caches this
representation), everything is interpreted in the normal script order --
top to bottom as we usually see it in a text editor.

That is, there are simply no declaration vs definition: the main script
passed to tclsh / wish is read and interpreted from top to bottom;
as soon as it calls the [source] command, the specified script is read
and interpreted from top to bottom etc; after that the control is back
to the original script and its interpretation continues.

Hence when Tcl sees a command (everything it executes is a command; this
includes stuff like [proc], [foreach] and others, which are syntax in
other languages) it looks up this command in the current list of
commands it knows and this either succeeds or fails.  The built-in
command [proc] defines a new Tcl procedure with the given name, and
registers it in that list of known commands.

So the general rule for user-defined procedures is relatively
straightforward: to call a procedure, the interpreter should have read
and executed its definition before the attempted call.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox