如何在Git中获取两个日期之间发生的所有提交之间的差异?

133

或者只获取在两个日期之间发生的所有提交记录?在SVN中,你可以这样做:

svn diff -r{date}:{date}

做这件事情!我找不到Git的同等方法。

具体而言,我正在考虑编写一个脚本,每天发送包含当天提交的所有代码以及提交者的电子邮件。

11个回答

187

您可以使用 git whatchanged --since="1 day ago" -p 命令。

该命令还可以使用 --until 参数。

文档


谢谢!这正是我想要的,它甚至可以使用“--committer”参数,尽管在文档中没有列出!另外,“git whatchanged”在“git help”中没有出现!不知道为什么...再次感谢。 - Chris
6
你应该选择这个答案,这样Seth就能得到一些“声望值”(karma)。 - Scott
21
我知道这个问题很久以前就被回答了,但是对于像我一样偶然发现这个问题的人,Git帮助文档说:该命令主要是出于历史原因而保留的;许多在git log诞生之前通过阅读Linux内核邮件列表学习Git的人都已经习惯了输入它。因此,文档鼓励使用git log而不是git whatchanged;后者也使用了git log的--no-merge选项,所以它们输出相同的结果。 - Ramses
2
git whatchanged是根据git log文档的说法,git log命令的一种别名。 - Vincent
4
自当前最新版本2.21.0起,git whatchanged已弃用。所有git whatchanged所实现的功能都可以使用git log来实现,而且为了历史原因,仅保留git whatchanged。详情请参见https://git-scm.com/docs/git-whatchanged/2.21.0。 - Devy
显示剩余2条评论

69

之前的建议有一些缺点。基本上,我在寻找与cvs diff -D“1 day ago” -D“2010-02-29 11:11”等价的东西。在收集越来越多的信息时,我找到了一个解决方案。

我尝试过的方法:

  • git whatchanged --since="1 day ago" -p,但是对于每个提交都会给出差异,即使一个文件中有多个提交。我知道"日期"在 git 中是一个比较宽泛的概念,我想一定有办法做到这一点。

  • git diff 'master@{1 day ago}..master会给出一些警告 warning: Log for 'master' only goes back to Tue, 16 Mar 2010 14:17:32 +0100. 并且没有显示所有的差异。

  • git format-patch --since=yesterday --stdout 对我来说没有任何输出。

  • revs=$(git log --pretty="format:%H" --since="1 day ago");git diff $(echo "$revs"|tail -n1) $(echo "$revs"|head -n1) 工作起来有些麻烦,而且不限于当前分支。

最后:

  • git diff $(git rev-list -n1 --before="1 day ago" master) 看起来是可行的,并且是一种默认的类似操作的方式,虽然比我想象的要复杂。

有趣的是,git-cvsserver并不支持“cvs diff -D”(没有文档说明)。


4
git rev-list 得到了 "+1" 的评价,它在解决我遇到的非常相似的问题时发挥了很大作用。 - me_and
这不应该成为被采纳的答案,seth的回答更加简明和正确。 - ctford
6
@ctford,我认为这不正确。它可能会为一个文件报告多个差异,而不是像svn/cvs diff一样每个文件一个差异。 - Weidenrinde
1
@Weidenrinde +1,这个更聪明了。 - rostamn739
2
git diff 'master@{1 day ago}..master 语法的意思是“检查 引用日志 并找出分支 master1 天前 指向 本地仓库 中的位置”。具体来说,它不会使用当前分支 master 的实际提交历史记录。这很少是你真正想要的东西。 - Mikko Rantalainen
要获取当前日期的变更情况,可以使用 --before="midnight" - Tomáš Hübelbauer

26

"date"在Git中是一个比较宽泛的概念。一个提交会有一个作者日期,可能在很久以前就被提交到了某个仓库中,然后才被拉取或者提交到另一个仓库中;同时,这个提交可能会被rebase并更新到一个表面上较新的提交之上。

一个提交还有一个提交日期,如果提交被rebase或修改,那么该日期也会随之更新。这些提交更可能处于某种时间顺序,但你仍然要看提交者在他的计算机上设置的时间是否准确;此外,即使提交没有修改,它也可能在远程仓库的一个分支上无限期地坐等,直到被合并到中央仓库的主分支中。

对于你的目的而言,最有用的可能是特定仓库的reflog日期。如果你启用了按分支记录所有引用更新(请参见git config core.logAllRefUpdates),那么你可以使用ref@{date}语法来指向分支在特定时间的位置。

例如:

git log -p master@{2009-07-01}..master@{now}
您还可以使用“模糊”描述,例如:
git log -p "master@{1 month ago}..master@{yesterday}"
这些命令将显示给定代码库分支中出现的所有提交,而不管它们根据作者和提交日期实际上有多“旧”。
请注意,每个分支的reflog是特定于代码库的,因此如果您在克隆上运行日志命令,并且您一个月内没有拉取任何更改,然后一次性拉取了所有上个月的更改,则上个月的所有更改都将出现在@{1 hour ago}..@{now}范围内。如果能够在人们推送到的“中央”代码库上运行日志命令,则可能会达到您想要的效果。

非常好的写作和对所提出问题的良好回答...但我认为这并不能帮助brbob实现他想要做的事情。 - Jakub Narębski
这要看情况,如果他真的想解析推送到某个中央仓库的特定分支上的内容,并且日志命令是在该仓库上运行的,那么这可能会有所帮助。我认为需要进行编辑... - CB Bailey
“commit date which is updated if a commit is rebased or amended in any way”, 实际上日期从未更改;整个提交将被替换为另一个提交(尽管树可能是相同的)。 - hasen
2
@hasen j:从技术上讲,你是正确的。提交是不可变的。当您重新定义基础或修改提交并创建新提交时,通常会从旧提交中复制现有提交消息、作者详细信息和作者日期,因此就像您使用新的提交ID和提交日期更新提交一样。 - CB Bailey
请注意,@ {time spec}语法始终是指您本地的reflog,而不是实际的提交历史记录(DAG)。如果你不理解这个区别,请不要使用这个语法! - Mikko Rantalainen

23
git diff --stat @{2013-11-01}..@{2013-11-30}
git diff --stat @{2.weeks.ago}..@{last.week}

这是否取决于 reflog?因为如果是的话,那么如果您运行此命令的存储库比其包含的提交历史更新(即新克隆的),则实际上无法使用此命令。 - user456814
2
是的,这完全取决于reflog。而且是的,这仅适用于本地副本历史记录,但是这是一个方便的命令。 - AA.
1
是的,我完全同意这一点,只要您有足够旧的reflog条目来支持它,那么它就非常方便。 - user456814
谢谢AA。使用您的答案,我能够执行以下操作:git annotate --stat ..@{2017-08-8} filename | less; git annotate --stat ..@{5.days.ago} filename; 这样我就可以在上下文中查看更改。 - Chris
请注意,@{time spec}语法始终指的是您本地的reflog。它不是指实际的提交历史记录(DAG)。如果您不了解差异,请不要使用此语法! - Mikko Rantalainen
在我看来,这是更合适的答案。 - mask

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

你想要的是这个吗(带或不带'--stdout')?


1
快速问题,--since选项是否使用提交日期? - CB Bailey

4
为了查看您的分支上从某日期到另一日期的Git文件更改,请使用以下公式:
  1. 检出您的分支。
  2. 拉取并更新来自远程仓库的更改
  3. 查看日期范围内的差异文件
公式:
git checkout <branch>
git pull
git diff --stat @{fromDate}..@{toDate}

请注意,日期格式为YYYY-MM-DD

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

如果你想观察特定时间范围内某个文件的变化(观察代码差异),只需导航到当前文件即可。
示例:
git diff @{2019-01-01}..@{2019-01-02} ~/dev/myApp/package.json

3

我认为一般的解决方法是使用:

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

如果不使用 --first-parent 选项,你可能会得到一个来自某个分支的提交,这个分支后来被合并到了 a ref,但在 a date string 之前没有被合并。

以下是另一种选择,使用 --childrengrep 代替 -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 ' '
}

在阅读这个问答之前,我对于git whatchanged并不熟悉。但是它给出的结果与我的预期有很大不同,因此我不确定它具体执行了何种操作。


3

2

这只是一个有趣的答案,因为可能有更好的方法。这将显示今天的所有提交哈希值。

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

;·)


2
你也可以使用 git-format-patch 来准备补丁(差异文件)并通过电子邮件发送。
使用选项 [since] 或 [revision range] 来指定提交范围。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接