这个坑,多少让人觉得有点无语。其实很早就注意到,Git中一次Commit对应两个时间的,但是也没仔细看JGit中的时间对应的是哪个时间。这里我们以这个Repo为例:https://git-wip-us.apache.org/repos/asf/wicket.git
对于这个Repo而言,如果我在命令行中输入:
git show ca03c252b5745bdccfb7c8cdffcc705846593ec1
那么将得到下面的一些输出:
commit ca03c252b5745bdccfb7c8cdffcc705846593ec1
Author: Sven Meier
Date: Mon Jun 25 17:19:41 2018 +0200
那这个时间到底是哪一个时间呢,从这里实际上看不太出来。如果我们在命令行中输入:
git log ca03c252b5745bdccfb7c8cdffcc705846593ec1
那么得到的输出和上面相同,只不过后面还有更多的commit信息。只有当我们输入:
git show --pretty=fuller ca03c252b5745bdccfb7c8cdffcc705846593ec1
那么这时候的输出变成了:
commit ca03c252b5745bdccfb7c8cdffcc705846593ec1
Author: Sven Meier
AuthorDate: Mon Jun 25 17:19:41 2018 +0200
Commit: Sven Meier
CommitDate: Tue Mar 19 11:53:23 2019 +0100
所以说原来之前输出的Date一直是AuthorDate!
这个确实有点坑啊,而且这个commit也挺奇葩,这两个日期差了这么多!
这种区别就导致了有时候我们拿不到想要的时间信息,从而导致时间匹配和过滤上出错,例如下面这段Java代码用了JGit来获取这个commit对应的时间:
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
public class Test {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String repo_path="%wicket这个Repo的本地目录%";
FileRepositoryBuilder builder = new FileRepositoryBuilder();
builder.setMustExist(true);
builder.addCeilingDirectory(new File(repo_path));
builder.findGitDir(new File(repo_path));
String versionCommit="ca03c252b5745bdccfb7c8cdffcc705846593ec1";
Repository repo;
repo = builder.build();
RevWalk walk = new RevWalk(repo);
ObjectId versionId=repo.resolve(versionCommit);
RevCommit verCommit=walk.parseCommit(versionId);
System.out.println(verCommit.getCommitTime());
Date revTime =new Date((long)verCommit.getCommitTime()*1000);
SimpleDateFormat time = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
String TimeString = time.format(revTime);
System.out.println();
System.out.println("This commit time:");
System.out.println(TimeString);
PersonIdent authorIdent = verCommit.getAuthorIdent();
Date authorDate = authorIdent.getWhen();
String authorDateTimeString = time.format(authorDate);
System.out.println();
System.out.println("This commit time:");
System.out.println(authorDateTimeString);
}
}
另外吐槽一下,getCommitTime返回的是个int的数值,表示从基准时间到现在的秒数。但下面的getWhen返回的是一个Date,这个统一起来很难么??如果我们运行上面的Java的代码,得到的就是:
1552992803
This commit time:
2019-03-19 03:53:23
This commit time:
2018-06-25 08:19:41
也就是说我们用getWhen才能得到和git show,git log中显示的同样的时间。这也太坑了吧!!我估计不止我一个人会遇到这种莫名其妙的问题:上面这段代码也是参考了这里:https://stackoverflow.com/questions/12608610/how-do-you-get-the-author-date-and-commit-date-from-a-jgit-revcommit
至于AuthorDate和CommitDate的区别,请大家参考这里:https://stackoverflow.com/questions/11856983/why-git-authordate-is-different-from-commitdate
另外,如果我用pydriller这个Python库:https://github.com/ishepard/pydriller,那么需要写的代码会少很多(这里也看出来对一些任务来讲,Python取代Java是明显的趋势啊,但这仅仅是对诸如数据分析、深度学习这样的领域):
from pydriller import RepositoryMining
import datetime
repo_dir='%wicket这个Repo的本地目录%'
the_version="ca03c252b5745bdccfb7c8cdffcc705846593ec1"
this_version_time=datetime.datetime.now()
for commit in RepositoryMining(repo_dir, single=the_version).traverse_commits():
this_version_time=commit.committer_date
print(this_version_time.strftime('%b-%d-%Y %H:%M:%S'))
那么得到的结果依然是CommitDate,如果不仔细看,想和Git Log中的Date做匹配的话,就会有bug。
Python的输出如下:
Mar-19-2019 11:53:23
综上所述,这个Bug(其实不能算bug,是大家直觉和默认Git Show、Log中信息不符的问题)肯定会让很多朋友困惑,所以我简单总结一下。