3

I need to run git log to show all commits after a specific date and time, and not leave out any commits, and without running git log to show all commits, as the latter is too slow (because this should work within git IMO).

However, before you mark this as a duplicate, consider I've read, as carefully as I can, through all of the following:

  1. What is the format for --date parameter of git commit
  2. git log --since=<date> options
  3. Strange behavior from git log --since
  4. How does git log --since count?

This is what I tried:

$ git --version
git version 2.31.1
$ date
Tue May 18 08:55:45 PDT 2021
$ git log --date=iso-local --format='%ad %<(20)%ar %H' --since='2021-04-01' | grep 2021-04- | tail -1
$ git log --date=iso-local --format='%ad %<(20)%ar %H' --since='2021-04-01 00:00' | grep 2021-04- | tail -1
$ git log --date=iso-local --format='%ad %<(20)%ar %H' --since='2021-04-01 00:00:00' | grep 2021-04- | tail -1
$ git log --date=iso-local --format='%ad %<(20)%ar %H' --since='2021-04-01T00:00:00' | grep 2021-04- | tail -1
$ git log --date=iso-local --format='%ad %<(20)%ar %H' --since='1 week ago' | grep 2021-04- | tail -1
$ git log --date=iso-local --format='%ad %<(20)%ar %H' --since='2 weeks ago' | grep 2021-04- | tail -1
$ git log --date=iso-local --format='%ad %<(20)%ar %H' --since='3 weeks ago' | grep 2021-04- | tail -1
$ git log --date=iso-local --format='%ad %<(20)%ar %H' --since='4 weeks ago' | grep 2021-04- | tail -1
$ git log --date=iso-local --format='%ad %<(20)%ar %H' --since='666 weeks ago' | grep 2021-04- | tail -1
2021-04-23 11:51:30 -0700 4 weeks ago          76044d3f08087add08ad1012ae1ee9a569679268
$ git log --date=local --format='%ad %<(20)%ar %H' --since='2021-04-01' | grep 2021-04- | tail -1
$ git log --date=local --format='%ad %<(20)%ar %H' --since='2021-04-01 00:00' | grep 2021-04- | tail -1
$ git log --date=local --format='%ad %<(20)%ar %H' --since='2021-04-01 00:00:00' | grep 2021-04- | tail -1
$ git log --date=local --format='%ad %<(20)%ar %H' --since='2021-04-01T00:00:00' | grep 2021-04- | tail -1
$ git log --date=local --format='%ad %<(20)%ar %H' --since='1 week ago' | grep 2021-04- | tail -1
$ git log --date=local --format='%ad %<(20)%ar %H' --since='2 weeks ago' | grep 2021-04- | tail -1
$ git log --date=local --format='%ad %<(20)%ar %H' --since='3 weeks ago' | grep 2021-04- | tail -1
$ git log --date=local --format='%ad %<(20)%ar %H' --since='4 weeks ago' | grep 2021-04- | tail -1
$ git log --date=local --format='%ad %<(20)%ar %H' --since='666 weeks ago' | grep 2021-04- | tail -1
$ git log --date=local --format='%ad %<(20)%ar %H' --since='666 weeks ago' | grep 2021-04- | tail -1
$ git log --date=default --format='%ad %<(20)%ar %H' --since='2021-04-01' | grep 2021-04- | tail -1
$ git log --date=default --format='%ad %<(20)%ar %H' --since='2021-04-01 00:00' | grep 2021-04- | tail -1
$ git log --date=default --format='%ad %<(20)%ar %H' --since='2021-04-01 00:00:00' | grep 2021-04- | tail -1
$ git log --date=default --format='%ad %<(20)%ar %H' --since='2021-04-01T00:00:00' | grep 2021-04- | tail -1
$ git log --date=default --format='%ad %<(20)%ar %H' --since='1 week ago' | grep 2021-04- | tail -1
$ git log --date=default --format='%ad %<(20)%ar %H' --since='2 weeks ago' | grep 2021-04- | tail -1
$ git log --date=default --format='%ad %<(20)%ar %H' --since='3 weeks ago' | grep 2021-04- | tail -1
$ git log --date=default --format='%ad %<(20)%ar %H' --since='4 weeks ago' | grep 2021-04- | tail -1
$ git log --date=default --format='%ad %<(20)%ar %H' --since='666 weeks ago' | grep 2021-04- | tail -1
$ git log --date=iso-local --format='%ad %<(20)%ar %H' | grep 2021-04- | tail -1
2021-04-01 00:00:13 -0700 7 weeks ago          657fa6a40cfd93c6d48a8aee4cc8190df753f6d7
$ git log --date=default --format='%ci %<(20)%ar %H' --since='2021-04-01' | grep 2021-04- | tail -1
$ git log --date=default --format='%ci %<(20)%ar %H' --since='2021-04-01 00:00' | grep 2021-04- | tail -1
$ git log --date=default --format='%ci %<(20)%ar %H' --since='2021-04-01 00:00:00' | grep 2021-04- | tail -1
$ git log --date=default --format='%ci %<(20)%ar %H' --since='2021-04-01T00:00:00' | grep 2021-04- | tail -1
$ git log --date=default --format='%ci %<(20)%ar %H' --since='1 week ago' | grep 2021-04- | tail -1
$ git log --date=default --format='%ci %<(20)%ar %H' --since='2 weeks ago' | grep 2021-04- | tail -1
$ git log --date=default --format='%ci %<(20)%ar %H' --since='3 weeks ago' | grep 2021-04- | tail -1
$ git log --date=default --format='%ci %<(20)%ar %H' --since='4 weeks ago' | grep 2021-04- | tail -1
$ git log --date=default --format='%ci %<(20)%ar %H' --since='666 weeks ago' | grep 2021-04- | tail -1
2021-04-23 18:51:30 +0000 4 weeks ago          76044d3f08087add08ad1012ae1ee9a569679268
$ git log --date=iso-local --format='%ci %<(20)%ar %H' | grep 2021-04- | tail -1
2021-04-01 00:00:13 -0700 7 weeks ago          657fa6a40cfd93c6d48a8aee4cc8190df753f6d7
$ 

I'm baffled as to why I get output about commit 76044d3f08087add08ad1012ae1ee9a569679268 at all, and the other --date=something variations do not show any output. And of course it is wrong output anyhow.

Puzzling.

Here is my slow workaround that I do not want to have to constantly resort to:

$ git log --date=iso-local --format='%ad %<(20)%ar %H' | grep 2021-04- | tail -1
2021-04-01 00:00:13 -0700 7 weeks ago          657fa6a40cfd93c6d48a8aee4cc8190df753f6d7
$

In the latter command, Git is dumping out the entire commit history, only for me to have to filter out the results I am looking for. In this case, git log is slow because my git repository is huge:

$ git log --date=iso-local --format='%ad %<(20)%ar %H' | wc -l
344841

What am I doing incorrectly here? Or is the --since option defective?

bgoodr
  • 2,744
  • 1
  • 30
  • 51
  • 1
    I tried the very first entry on my own repository with Git 2.28.0 and it definitely works. Are you sure you were always on top of your branch when you started each of them ? What kind of output do you get when you remove « tail » (even though I well understood that you eventually get the last row of the list, I'm interrested in what Git says here). – Obsidian May 18 '21 at 16:53
  • 1
    Also, be aware that "%ad" is *author date* while `--since` cares about *commit date*. But since this latter one should always occur after the other one in normal conditions, it shouldn't affect your command. I would try `git log --graph HEAD 76044d3f08087add08ad1012ae1ee9a569679268` to see if we can reach a incorrectly date node that then would lead you to another eligible commits. – Obsidian May 18 '21 at 17:18
  • 1
    Besides the author-date vs committer-date issue, Git has (or had) some shortcut code in it that I consider suspect: it assumes ascending committer-date order on successor-commits, within some degree of flexibility (I think it was 6 months when I noticed it). Since committer dates can be spoofed or incorrect, this can cut off a traversal incorrectly. The new slab data code contains "corrected committer date" values to compensate for this problem, so graph traversal that uses that data would not suffer from it. – torek May 19 '21 at 00:55
  • I've dug and dug and I cannot make sense of it. `git log --graph ...` only helps me understand that Git is trying to avoid traversing legs of the graph and ending up stuck. The graph in my case the graph is bewilderingly complex. I'd have to resort to writing a crafty graph theoretical algorithm to sort it out. I give up for now and will just live with the annoyance of the **workround** until which time someone can confirm a fix to the "cut off a traversal incorrectly" problem mentioned by @torek. – bgoodr May 28 '21 at 20:28
  • With Git 2.37 (Q3 2022), a `git log --since-as-filter=...` will give you a more reliable and complete result. – VonC May 22 '22 at 16:05

1 Answers1

1

torek commented:

Since committer dates can be spoofed or incorrect, this can cut off a traversal incorrectly.

Not anymore, since Git 2.37 (Q3 2022):

Before 2.37, "git log --since=X"(man) was stopping traversal upon seeing a commit that is older than X.
But there may be commits behind it that is younger than X when the commit was created with a faulty clock.

A new option --since-as-filter is added to keep digging without stopping, and instead filter out commits with timestamp older than X.

See commit 9669778 (23 Apr 2022) by Miklos Vajna (vmiklos).
(Merged by Junio C Hamano -- gitster -- in commit 6f24da6, 20 May 2022)

log: "--since-as-filter" option is a non-terminating "--since" variant

Signed-off-by: Miklos Vajna

The "--since=<time>" option of "git log"(man) 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.

rev-list-options now includes in its man page:

--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.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250