From 679b5916cdafdcfa9fb36c31dbf53d7e4aa0af0b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 27 Jan 2021 16:37:22 +0000 Subject: range-diff/format-patch: refactor check for commit range Currently, when called with exactly two arguments, `git range-diff` tests for a literal `..` in each of the two. Likewise, the argument provided via `--range-diff` to `git format-patch` is checked in the same manner. However, `^!` is a perfectly valid commit range, equivalent to `^..` according to the `SPECIFYING RANGES` section of gitrevisions[7]. In preparation for allowing more sophisticated ways to specify commit ranges, let's refactor the check into its own function. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano diff --git a/builtin/log.c b/builtin/log.c index f23ccdb..91466c0 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1680,7 +1680,7 @@ static void infer_range_diff_ranges(struct strbuf *r1, struct commit *head) { const char *head_oid = oid_to_hex(&head->object.oid); - int prev_is_range = !!strstr(prev, ".."); + int prev_is_range = is_range_diff_range(prev); if (prev_is_range) strbuf_addstr(r1, prev); diff --git a/builtin/range-diff.c b/builtin/range-diff.c index 24c4162..5b1f632 100644 --- a/builtin/range-diff.c +++ b/builtin/range-diff.c @@ -3,6 +3,7 @@ #include "parse-options.h" #include "range-diff.h" #include "config.h" +#include "revision.h" static const char * const builtin_range_diff_usage[] = { N_("git range-diff [] .. .."), @@ -46,12 +47,12 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix) diffopt.use_color = 1; if (argc == 2) { - if (!strstr(argv[0], "..")) - die(_("no .. in range: '%s'"), argv[0]); + if (!is_range_diff_range(argv[0])) + die(_("not a commit range: '%s'"), argv[0]); strbuf_addstr(&range1, argv[0]); - if (!strstr(argv[1], "..")) - die(_("no .. in range: '%s'"), argv[1]); + if (!is_range_diff_range(argv[1])) + die(_("not a commit range: '%s'"), argv[1]); strbuf_addstr(&range2, argv[1]); } else if (argc == 3) { strbuf_addf(&range1, "%s..%s", argv[0], argv[1]); diff --git a/range-diff.c b/range-diff.c index b9950f1..9b93e08 100644 --- a/range-diff.c +++ b/range-diff.c @@ -564,3 +564,8 @@ int show_range_diff(const char *range1, const char *range2, return res; } + +int is_range_diff_range(const char *arg) +{ + return !!strstr(arg, ".."); +} diff --git a/range-diff.h b/range-diff.h index 583ced2..c17dbc2 100644 --- a/range-diff.h +++ b/range-diff.h @@ -16,4 +16,12 @@ int show_range_diff(const char *range1, const char *range2, const struct diff_options *diffopt, const struct strvec *other_arg); +/* + * Determine whether the given argument is usable as a range argument of `git + * range-diff`, e.g. A..B. Note that this only validates the format but does + * _not_ parse it, i.e. it does _not_ look up the specified commits in the + * local repository. + */ +int is_range_diff_range(const char *arg); + #endif -- cgit v0.10.2-6-g49f6 From 359f0d754ab709c5a1ff3267bc117fb8559c62c2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 5 Feb 2021 14:44:48 +0000 Subject: range-diff/format-patch: handle commit ranges other than A..B In the `SPECIFYING RANGES` section of gitrevisions[7], two ways are described to specify commit ranges that `range-diff` does not yet accept: "^!" and "^-". Let's accept them, by parsing them via the revision machinery and looking for at least one interesting and one uninteresting revision in the resulting `pending` array. This also finally lets us reject arguments that _do_ contain `..` but are not actually ranges, e.g. `HEAD^{/do.. match this}`. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano diff --git a/range-diff.c b/range-diff.c index 9b93e08..a88612c 100644 --- a/range-diff.c +++ b/range-diff.c @@ -11,6 +11,7 @@ #include "pretty.h" #include "userdiff.h" #include "apply.h" +#include "revision.h" struct patch_util { /* For the search for an exact match */ @@ -567,5 +568,28 @@ int show_range_diff(const char *range1, const char *range2, int is_range_diff_range(const char *arg) { - return !!strstr(arg, ".."); + char *copy = xstrdup(arg); /* setup_revisions() modifies it */ + const char *argv[] = { "", copy, "--", NULL }; + int i, positive = 0, negative = 0; + struct rev_info revs; + + init_revisions(&revs, NULL); + if (setup_revisions(3, argv, &revs, NULL) == 1) { + for (i = 0; i < revs.pending.nr; i++) + if (revs.pending.objects[i].item->flags & UNINTERESTING) + negative++; + else + positive++; + for (i = 0; i < revs.pending.nr; i++) { + struct object *obj = revs.pending.objects[i].item; + + if (obj->type == OBJ_COMMIT) + clear_commit_marks((struct commit *)obj, + ALL_REV_FLAGS); + } + } + + free(copy); + object_array_clear(&revs.pending); + return negative > 0 && positive > 0; } diff --git a/range-diff.h b/range-diff.h index c17dbc2..4abd70c 100644 --- a/range-diff.h +++ b/range-diff.h @@ -18,9 +18,7 @@ int show_range_diff(const char *range1, const char *range2, /* * Determine whether the given argument is usable as a range argument of `git - * range-diff`, e.g. A..B. Note that this only validates the format but does - * _not_ parse it, i.e. it does _not_ look up the specified commits in the - * local repository. + * range-diff`, e.g. A..B. */ int is_range_diff_range(const char *arg); diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh index 6eb344b..2b51837 100755 --- a/t/t3206-range-diff.sh +++ b/t/t3206-range-diff.sh @@ -150,6 +150,19 @@ test_expect_success 'simple A B C (unmodified)' ' test_cmp expect actual ' +test_expect_success 'A^! and A^- (unmodified)' ' + git range-diff --no-color topic^! unmodified^-1 >actual && + cat >expect <<-EOF && + 1: $(test_oid t4) = 1: $(test_oid u4) s/12/B/ + EOF + test_cmp expect actual +' + +test_expect_success 'A^{/..} is not mistaken for a range' ' + test_must_fail git range-diff topic^.. topic^{/..} 2>error && + test_i18ngrep "not a commit range" error +' + test_expect_success 'trivial reordering' ' git range-diff --no-color master topic reordered >actual && cat >expect <<-EOF && -- cgit v0.10.2-6-g49f6 From 2cc543deab38c188906c41e537dc5c7de98b93d7 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 5 Feb 2021 14:44:49 +0000 Subject: range-diff(docs): explain how to specify commit ranges There are three forms, depending whether the user specifies one, two or three non-option arguments. We've never actually explained how this works in the manual, so let's explain it. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt index 9701c1e..a968d52 100644 --- a/Documentation/git-range-diff.txt +++ b/Documentation/git-range-diff.txt @@ -28,6 +28,17 @@ Finally, the list of matching commits is shown in the order of the second commit range, with unmatched commits being inserted just after all of their ancestors have been shown. +There are three ways to specify the commit ranges: + +- ` `: Either commit range can be of the form + `..`, `^!` or `^-`. See `SPECIFYING RANGES` + in linkgit:gitrevisions[7] for more details. + +- `...`. This is equivalent to + `.. ..`. + +- ` `: This is equivalent to `.. + ..`. OPTIONS ------- -- cgit v0.10.2-6-g49f6