132

Or just all the commits that occurred between two dates? In SVN, you could do something like

svn diff -r{date}:{date}

to do it! I can't seem to find a Git equivalent to this.

Specifically I'm looking at writing a script to send out daily emails with all the code committed that day and by who.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Chris
  • 3,184
  • 4
  • 26
  • 24

11 Answers11

184

You could use git whatchanged --since="1 day ago" -p

It also takes a --until argument.

Docs

SterlingVix
  • 321
  • 6
  • 12
seth
  • 36,759
  • 7
  • 60
  • 57
  • thanks! This was right what I wanted, it even takes the --committer parameter, though thats not listed in its documentation! also, 'git whatchanged' didn't appear in 'git help'! No idea why... thanks again. – Chris Jul 22 '09 at 10:34
  • 6
    You should make this your chosen answer so seth gets some karma. – Scott Jul 22 '09 at 14:02
  • Man what a kick in the nuts for seth – gtd Aug 14 '09 at 20:43
  • Use this answer if you prefer multiple diffs per file. – Greg M. Krsak Apr 21 '14 at 20:59
  • 21
    @brbob I know this was answered a long time ago, but just for someone who stumbles upon this (as I did) Git help says: `The command is kept primarily for historical reasons; fingers of many people who learned Git long before git log was invented by reading Linux kernel mailing list are trained to type it.` So, the docs encourages using `git log` instead of `git whatchanged`; this last command also uses the --no-merge option of git log, so they output the same results. – Ramses Jul 29 '14 at 15:07
  • 2
    git whatchanged is kind of alias of git log command according to [git log's doc](http://git-scm.com/docs/git-whatchanged) – Vincent Mar 15 '15 at 03:18
  • 4
    `git whatchanged` is deprecated as of the current latest version 2.21.0. All `git whatchanged` achieved can be achieved by `git log` and it's only preserved for historical reasons. See details https://git-scm.com/docs/git-whatchanged/2.21.0 – Devy May 21 '19 at 15:56
69

The previous suggestions have some drawbacks. Basically, I was looking for something equivalent to cvs diff -D"1 day ago" -D"2010-02-29 11:11". While collecting more and more information, I found a solution.

Things I have tried:

  • git whatchanged --since="1 day ago" -p from here

    But this gives a diff for each commit, even if there are multiple commits in one file. I know that "date" is a bit of a loose concept in git, I thought there must be some way to do this.

  • git diff 'master@{1 day ago}..master gives some warning warning: Log for 'master' only goes back to Tue, 16 Mar 2010 14:17:32 +0100. and does not show all diffs.

  • git format-patch --since=yesterday --stdout does not give anything for me.

  • revs=$(git log --pretty="format:%H" --since="1 day ago");git diff $(echo "$revs"|tail -n1) $(echo "$revs"|head -n1) works somehow, but seems complicated and does not restrict to the current branch.

Finally:

Funnily, git-cvsserver does not support "cvs diff -D" (without that it is documented somewhere).

Community
  • 1
  • 1
Weidenrinde
  • 2,152
  • 1
  • 20
  • 21
  • 4
    +1 for `git rev-list`, which went a long way towards solving the very similar problem I was seeing. – me_and Sep 15 '11 at 13:27
  • This shouldn't be the accepted answer, seth's is more concise and correct. – ctford Jan 30 '14 at 06:37
  • 6
    @ctford, in my view, it is not correct. It may report multiple diffs for one file, not one diff per file as svn/cvs diff. – Weidenrinde Feb 18 '14 at 21:46
  • 1
    @Weidenrinde +1, this is much more clever – rostamn739 Jun 16 '16 at 12:46
  • 2
    The `git diff 'master@{1 day ago}..master` syntax means "check **the reflog** and figure out where branch `master` used to point **in your local repository** `1 day ago`". Specifically, will not use the actual commit history of current branch `master`. This is very seldom the thing you really want. – Mikko Rantalainen Jun 27 '18 at 07:33
  • To get changes on the current day so far, use `--before="midnight"` – Tomáš Hübelbauer Mar 16 '21 at 08:43
26

"date" is a bit of a loose concept in git. A commit will have an author date that may be some time well in the past before someone actually pulls/commits the commit into their repository, also the commit may be rebased and updated to be on top of an apparently newer commit.

A commit also has an commit date which is updated if a commit is rebased or amended in any way. These commits are more likely to be in some sort of chronological order but you are still at the mercy of the committer having the correct time set on his computer and even so, an unmodified commit can sit on a feature branch on a remote repository indefinitely before being merged into the master branch of a central repository.

What is probably most useful for your purposes is the reflog date on the particular repository in question. If you have per-branch reflogs enabled (see git config core.logAllRefUpdates) then you can use the ref@{date} syntax to refer to where a branch was at a particular time.

E.g.

git log -p master@{2009-07-01}..master@{now}

You can also use 'fuzzy' descriptions like:

git log -p "master@{1 month ago}..master@{yesterday}"

These commands will show all commits that have 'appeared' in the given branch of the repository regardless of how 'old' they actually are according to their author and commit dates.

Note that the per-branch reflog is specific to a repository, so if you're running the log command on a clone, and you don't pull for (say) a month then pull all the changes for the last month at once, then all of the last month's changes will appear in a @{1 hour ago}..@{now} range. If you are able to run the log command on the 'central' repostory that people push to, then it may do what you want.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • Very good writeup and good answer to stated question... but I think it wouldn't help much with doing what brbob intended. – Jakub Narębski Jul 21 '09 at 21:10
  • It depends, it might help if he actually wants to parse what was pushed to a certain branch on a certain central repository and the log command was run on that repository. I think that an edit is in order... – CB Bailey Jul 21 '09 at 21:15
  • "commit date which is updated if a commit is rebased or amended in any way", actually the date is never changed; the whole commit gets replaced with another commit (although the tree could supposedly be the same). – hasen Mar 16 '10 at 15:04
  • 2
    @hasen j: Technically, you're correct. Commits are immutable. When you rebase or amend a commit and create a new commit, the existing commit message, author details and author date are often copied from the old commit so it's _like_ you're updating the commit with a new commit id and commit date. – CB Bailey Mar 16 '10 at 15:34
  • Note that the `@{time spec}` syntax always refers **your** local **reflog**. It does not refer to actual commit history (DAG). If you do not understad the difference, do not use this syntax! – Mikko Rantalainen Jun 27 '18 at 07:37
22
git diff --stat @{2013-11-01}..@{2013-11-30}

or

git diff --stat @{2.weeks.ago}..@{last.week}
AA.
  • 4,496
  • 31
  • 35
  • Does this depend on the reflog? Because if it does, then you can't actually use this if the repo you're running this command in is newer (i.e. freshly cloned) than the commit history that it contains. –  Jul 22 '14 at 03:53
  • 2
    Yes, this totally depend of the reflog. And yes, this only works in local copy history, but is a little an convenient command. – AA. Jul 22 '14 at 17:13
  • 1
    Yes, I definitely agree that it's convenient, as long as you have reflog entries old enough to support it. –  Jul 22 '14 at 17:15
  • Thank you AA. Using your answer, I was able to do: git annotate --stat ..@{2017-08-8} filename | less;git annotate --stat ..@{5.days.ago} filename; so I can see the changes in context. – Chris Sep 14 '17 at 11:25
  • Note that the `@{time spec}` syntax always refers **your** local **reflog**. It does not refer to actual commit history (DAG). If you do not understad the difference, do not use this syntax! – Mikko Rantalainen Jun 27 '18 at 07:38
  • IMO, This is more appropriate answer to the question. – mask Sep 12 '18 at 18:26
5

Perhaps

$ git format-patch --committer=<who> --since=yesterday --stdout

is what you want (with or without '--stdout')?

Jakub Narębski
  • 309,089
  • 65
  • 217
  • 230
4

In order to watch Git files changes from date to date on your branch ,use the following formula:

  1. checkout your branch.
  2. pull and update changes from remote repository
  3. watch diff files from date to date range

Formula:

git checkout <branch>
git pull
git diff --stat @{fromDate}..@{toDate}

Pay attention that the dates are on YYYY-MM-DD format:

git diff --stat @{2019-08-20}..@{2019-08-21}

If you'd like to observe changes on specific file in specific time range (watch diff in code), just navigate the current file:

Example:

git diff @{2019-01-01}..@{2019-01-02} ~/dev/myApp/package.json
avivamg
  • 12,197
  • 3
  • 67
  • 61
3

I believe the general solution is to use:

git rev-list -n1 --first-parent --until=<a date string> <a ref>

Without --first-parent, you might get a commit from a branch that was later merged into a ref but hadn't been merged as of a date string.

Here's an alternative using --children and grep instead of -n1:

mlm_git_ref_as_of() {
    # # Examples #
    #
    # Show all commits between two dates:
    #
    #     git log $(mlm_git_ref_as_of '2012-05-21 09:00:00-0400')..$(mlm_git_ref_as_of '2012-05-21 17:00:00-0400')
    #
    # Show diffs of all commits between two dates:
    #
    #     git diff $(mlm_git_ref_as_of '2012-05-21 09:00:00-0400')..$(mlm_git_ref_as_of '2012-05-21 17:00:00-0400')
    local as_of="$1"
    local ref="${2:-HEAD}"
    # Get the most recent commit (--children, grep -v ' ') that was on
    # the given branch ($ref, --first-parent) as of a given date
    # ($as_of)
    git rev-list --children --first-parent --until="$as_of" "$ref" | grep -v ' '
}

I wasn't familiar with git whatchanged before reading this Q&A, but it gives very different results for me, so I'm not sure what it's doing.

Matt McClure
  • 16,009
  • 2
  • 28
  • 30
3

Another simple way that you can get a diff of all changes since a certain date is to simply find the first commit X that occured on or after that date, then use

git diff X

This has the advantage that it doesn't depend on reflog entries in a fresh clone, unlike the

git diff <reference>@{n}..
git log <reference>@{n}..

solutions in

Community
  • 1
  • 1
2

This is more of a funny answer, because there is likely a better way. This will show all commit hashes for today.

git log --pretty="format:%H %ai" | grep `date +"%Y-%m-%d"` | awk {'print $1'}`

;·)

gahooa
  • 131,293
  • 12
  • 98
  • 101
2

You can also use git-format-patch to prepare patches (diffs) and send them through email.

Use options [since] or [revision range] to specify commits range.

Nick Dandoulakis
  • 42,588
  • 16
  • 104
  • 136
0

I'll throw in the way I do it: git log for a date gives you commit hashes for the current branch. Then I just use something like git diff 8fgdfg8..565k4l5 which gives me proper difference aggregated by files. Hope this helps, not tested much though

rostamn739
  • 323
  • 3
  • 8