【问题标题】:git diff between current date and some times ago in GitPythonGitPython 中当前日期和前一段时间之间的 git diff
【发布时间】:2019-12-18 04:39:51
【问题描述】:

我正在使用 GitPython 查找一段时间内(例如现在和 1 周前)更改的文件:

 repo = Repo(self.repo_directory)
 for item in repo.head.commit.diff('develop@{1 weeks ago}'):
     print ("smth") 

但即使将周数更改为不同的数字也没有任何反应,这意味着在该时间段内没有检测到差异。如果我将'develop@{1 weeks ago}' 更改为'HEAD@{1 weeks ago}',那么更改的数量会很大,这在一周内是不正确的。任何帮助表示赞赏。

【问题讨论】:

  • 请记住,ref@{reflog-selector} 只是一种指定特定提交哈希的方法。 reflog 选择器选择 Git 如何查看给定 ref 的 reflog(@ 之前的那个),并选择其中一个值。使用git reflog <ref> 显示该引用的引用日志:您的引用日志表达式选择的哈希 ID 将是这些哈希 ID 之一。
  • 真的,看看 你的 reflogs。您的 reflog 是 yours 的——它们反映了 youyour 存储库中所做的活动。它们不反映任何其他存储库中的活动!如果有人在十年前更改了 他们的 master 中的某个文件,而你昨天将 Git 连接到他们的 Git 并在昨天收到了他们的新提交,your reflogs 会说“这发生在昨天"。
  • 感谢 Torek,那么您建议如何在 repo 中查找已更改文件的列表(添加、删除、...)?如果您知道,使用 GitPython 或其他一些 Python 包?
  • 也许足够接近,是的。但是您可能希望使用原始哈希 ID:它们标识一个确切的提交,并且不依赖于图的相对遍历。 (使用git log --pretty=format:%Hgit rev-list 来获取正确的哈希ID。)也不是那个相对是错误,只是如果你进行新的提交,突然间~10 现在是@987654331 @。或者,如果您的提交 DAG 非常复杂,您可能需要 HEAD~3^2~2^2~4^2 或类似的疯狂的东西才能使用相对运动到达那里。如果您正在编写代码,这很荒谬:编译器可以记住哈希 ID!
  • “十次首次提交从我自己的分支名称develop 现在指向的位置后退”的语法是develop~10,而不是develop@{HEAD~10}。见the gitrevisions documentation。请记住,对于任何涉及 any 历史提交的内容,any 名称只是我们让 Git 找到提交的哈希 ID 的一种方法。

标签: python git git-diff gitpython


【解决方案1】:

develop@{1 weeks ago} 将使用 reflog

引用日志,或“reflogs”,记录分支的提示和其他引用在本地存储库中的更新时间。

这意味着您的本地 Git 存储库可能没有在本地记录一周前对 develop 的任何操作,但它记录了“HEAD”发生的任何事情。

如果 develop 被远程更改,然后在本地导入其历史记录,develop@{1 weeks ago} 可能不会产生任何结果(因为您的本地 reflog 不会引用它)。

只有git log --since/--until 会在任何日期运行(不仅仅是 reflog 中记录的那些,仅限于本地运行,默认情况下为 90 天)

但我不知道 GitPython 是否实现了这一点。
它的git.refs.log 模块更多地基于 reflogs 条目,这对您的情况没有帮助。

【讨论】:

  • 如果我将 @{1 周前} 更改为 @{10 周前} 仍然给出相同的结果(什么都没有)。那么,例如 1 周前,您建议在开发中获取所有更改(更改的文件、删除的......)?使用 GitPython?使用 HEAD@{1 周前} 似乎也不正确,因为在我的示例中,上周的更改数量很大,这是不合理的。
  • @Alan 我的建议是“一周前”表示法仅适用于您在本地完成的工作,不适用于从远程存储库导入的历史记录。
  • 我明白了,那么如何跟踪远程存储库?
  • @Alan POssibly 提供一个确切的日期,而不是依赖于“一周前”表示法,它本身并不总是可用的。
  • 我使用了repo.head.commit.diff('develop@{1 Dec 2019}}'):,并将日期从 12 月 16 日一直更改为 12 月 1 日,但仍然没有输出。
【解决方案2】:

根据 cmets 中的讨论,我提出了以下使用 GitPython 的解决方案(仅需要的代码放在这里,其余部分忽略以避免混淆)

   import git
   from git import Repo
   from git import RemoteProgress

   class MyProgressPrinter(RemoteProgress):
       def update(op_code, cur_count, max_count=None, message=''):
          print(op_code, cur_count, max_count, cur_count / (max_count or 100.0), message or "NO MESSAGE")


   def _get_commits_info(self):
        for fetch_info in self.repo.remotes.origin.fetch(progress=MyProgressPrinter()):
        self.commits_info.append(
            (fetch_info.commit.committed_date, fetch_info.commit))  
        self.commits_info = sorted(self.commits_info, key=lambda x: x[0]) #sort based on committed date


   def _get_the_changed_components(self):
       self._get_commits_info()
       last_date = self.commits_info[-1][0]
       last_commit = self.commits_info[-1][1]
       since_date = last_date - self.time_period * 86400 # for example time_period is 7 (days)
       since_commit = self._get_since_commit(since_date) # finds the since_commit from the sorted list of commits_info 

       for item in last_commit.diff(since_commit):
           if item.a_path.find('certain_path') != -1:
               self.paths.add(item.a_path) #self.path is a set()

但是,self.path 的长度对我来说是不合理的,因为它捕获了太多的变化,我不知道为什么。所以基本上,我所做的是:找到所有提交,根据committed_date 对它们进行排序,然后找到一个提交(代码中的since_commit),其中committed_date7 days ago。之后得到排序后的commits_info 列表中的last commitsince_commit 之间的差异,然后将a_pathes 保存到一个集合中。

我还尝试了另一种方法,并从since_commit 到排序的commits_info 一直到最后一次提交,得到了每两次连续提交之间的差异。这样,更改的数量甚至更高。

有什么 cmets 或帮助吗?还是您认为这是在一段时间内获取差异的正确方法?而变化次数多的原因只是偶然?

更新和最终解决方案

因此,似乎比较(差异)两个提交并没有给出从现在到有时之前发生的更改,因为合并之前的提交可能包括感兴趣的时间段之前的更改。为此,我找到了两个解决方案,首先计算从那时到当前日期的HEAD 更改次数,这不是很准确。为此,我们可以使用:

 g = Git(self.repo_directory)
 loginfo = g.log('--since={}'.format(since), '--pretty=tformat:') 

然后计算Merge pull request字符串的数量,它基本上计算了repo发生合并的次数,这通常会改变HEAD。但是,它不准确,但我们假设这个计数将是 31。那么:

  for item in self.repo.head.commit.diff('develop~31'):
     if item.a_path.find('certain_path') != -1:
         self.paths.add(item.a_path) #self.path is a set()

有效且直接的解决方案

  def _get_the_changed_components(self):
      g = Git(self.repo_directory)
      today = date.today()
      since = today - DT.timedelta(self.time_period) #some times ago
      loginfo = g.log('--since={}'.format(since), '--pretty=tformat:', '--name-only')
      files = loginfo.split('\n')
      for file in files:
          self.paths.add(file)

【讨论】:

  • 很好地使用 git log --since,正如我在回答中提到的那样。赞成。
  • 谢谢,GitPython 支持 Git 日志,这让它变得非常简单。
猜你喜欢
  • 2011-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-07
  • 1970-01-01
相关资源
最近更新 更多