]> git.ipfire.org Git - thirdparty/git.git/commitdiff
log: "--since-as-filter" option is a non-terminating "--since" variant
authorMiklos Vajna <vmiklos@vmiklos.hu>
Sat, 23 Apr 2022 12:59:57 +0000 (14:59 +0200)
committerJunio C Hamano <gitster@pobox.com>
Sat, 23 Apr 2022 16:36:07 +0000 (09:36 -0700)
The "--since=<time>" option of "git log" limits the commits displayed by
the command by stopping the traversal once it sees a commit whose
timestamp is older than the given time and not digging further into its
parents.

This is OK in a history where a commit always has a newer timestamp than
any of its parents'.  Once you see a commit older than the given <time>,
all ancestor commits of it are even older than the time anyway.  It
poses, however, a problem when there is a commit with a wrong timestamp
that makes it appear older than its parents.  Stopping traversal at the
"incorrectly old" commit will hide its ancestors that are newer than
that wrong commit and are newer than the cut-off time given with the
--since option.  --max-age and --after being the synonyms to --since,
they share the same issue.

Add a new "--since-as-filter" option that is a variant of
"--since=<time>".  Instead of stopping the traversal to hide an old
enough commit and its all ancestors, exclude commits with an old
timestamp from the output but still keep digging the history.

Without other traversal stopping options, this will force the command in
"git log" family to dig down the history to the root.  It may be an
acceptable cost for a small project with short history and many commits
with screwy timestamps.

It is quite unlikely for us to add traversal stopper other than since,
so have this as a --since-as-filter option, rather than a separate
--as-filter, that would be probably more confusing.

Signed-off-by: Miklos Vajna <vmiklos@vmiklos.hu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/rev-list-options.txt
revision.c
revision.h
t/t4217-log-limit.sh [new file with mode: 0755]

index fd4f4e26c90face314632ac6c2b81bed648abd17..195e74eec633ea913c0934d2b690b674360376d7 100644 (file)
@@ -25,6 +25,11 @@ ordering and formatting options, such as `--reverse`.
 --after=<date>::
        Show commits more recent than a specific date.
 
+--since-as-filter=<date>::
+       Show all commits more recent than a specific date. This visits
+       all commits in the range, rather than stopping at the first commit which
+       is older than a specific date.
+
 --until=<date>::
 --before=<date>::
        Show commits older than a specific date.
index 7d435f80480ef1b7684fdc43b51057d20e79966f..c367273c0061142bd98ca72ed509e142d7fe837c 100644 (file)
@@ -1440,6 +1440,9 @@ static int limit_list(struct rev_info *revs)
                if (revs->min_age != -1 && (commit->date > revs->min_age) &&
                    !revs->line_level_traverse)
                        continue;
+               if (revs->max_age_as_filter != -1 &&
+                       (commit->date < revs->max_age_as_filter) && !revs->line_level_traverse)
+                       continue;
                date = commit->date;
                p = &commit_list_insert(commit, p)->next;
 
@@ -1838,6 +1841,7 @@ void repo_init_revisions(struct repository *r,
        revs->dense = 1;
        revs->prefix = prefix;
        revs->max_age = -1;
+       revs->max_age_as_filter = -1;
        revs->min_age = -1;
        revs->skip_count = -1;
        revs->max_count = -1;
@@ -2218,6 +2222,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
        } else if ((argcount = parse_long_opt("since", argv, &optarg))) {
                revs->max_age = approxidate(optarg);
                return argcount;
+       } else if ((argcount = parse_long_opt("since-as-filter", argv, &optarg))) {
+               revs->max_age_as_filter = approxidate(optarg);
+               return argcount;
        } else if ((argcount = parse_long_opt("after", argv, &optarg))) {
                revs->max_age = approxidate(optarg);
                return argcount;
@@ -3862,6 +3869,9 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
        if (revs->min_age != -1 &&
            comparison_date(revs, commit) > revs->min_age)
                        return commit_ignore;
+       if (revs->max_age_as_filter != -1 &&
+           comparison_date(revs, commit) < revs->max_age_as_filter)
+                       return commit_ignore;
        if (revs->min_parents || (revs->max_parents >= 0)) {
                int n = commit_list_count(commit->parents);
                if ((n < revs->min_parents) ||
index 5bc59c7bfe1e35efe7fb24e93f9a093baa28b658..e80c148b1943e7cbedf9b4bd6bd0f0a698e78437 100644 (file)
@@ -263,6 +263,7 @@ struct rev_info {
        int skip_count;
        int max_count;
        timestamp_t max_age;
+       timestamp_t max_age_as_filter;
        timestamp_t min_age;
        int min_parents;
        int max_parents;
diff --git a/t/t4217-log-limit.sh b/t/t4217-log-limit.sh
new file mode 100755 (executable)
index 0000000..6e01e26
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+test_description='git log with filter options limiting the output'
+
+. ./test-lib.sh
+
+test_expect_success 'setup test' '
+       git init &&
+       echo a >file &&
+       git add file &&
+       GIT_COMMITTER_DATE="2021-02-01 00:00" git commit -m init &&
+       echo a >>file &&
+       git add file &&
+       GIT_COMMITTER_DATE="2022-02-01 00:00" git commit -m first &&
+       echo a >>file &&
+       git add file &&
+       GIT_COMMITTER_DATE="2021-03-01 00:00" git commit -m second &&
+       echo a >>file &&
+       git add file &&
+       GIT_COMMITTER_DATE="2022-03-01 00:00" git commit -m third
+'
+
+test_expect_success 'git log --since-as-filter=...' '
+       git log --since-as-filter="2022-01-01" --format=%s >actual &&
+       cat >expect <<-\EOF &&
+       third
+       first
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'git log --children --since-as-filter=...' '
+       git log --children --since-as-filter="2022-01-01" --format=%s >actual &&
+       cat >expect <<-\EOF &&
+       third
+       first
+       EOF
+       test_cmp expect actual
+'
+
+test_done