From 3c20a9b0acd5f43bb9134c711a8fe80fc0497e1c Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 7 Feb 2010 15:17:21 +0000 Subject: [PATCH] Do not parse the entire git log to fetch new commits (takes several minutes for a few thousands commits), but only 1 week before the last known commit (#4547, #4716). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3394 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/repository/git.rb | 21 ++++++++++++--------- lib/redmine/scm/adapters/git_adapter.rb | 6 +----- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/app/models/repository/git.rb b/app/models/repository/git.rb index dd5e9e3166..473eb07e29 100644 --- a/app/models/repository/git.rb +++ b/app/models/repository/git.rb @@ -40,23 +40,26 @@ class Repository::Git < Repository # With SCM's that have a sequential commit numbering, redmine is able to be # clever and only fetch changesets going forward from the most recent one # it knows about. However, with git, you never know if people have merged - # commits into the middle of the repository history, so we always have to - # parse the entire log. + # commits into the middle of the repository history, so we should parse + # the entire log. Since it's way too slow for large repositories, we only + # parse 1 week before the last known commit. + # The repository can still be fully reloaded by calling #clear_changesets + # before fetching changesets (eg. for offline resync) def fetch_changesets - # Save ourselves an expensive operation if we're already up to date - return if scm.num_revisions == changesets.count + c = changesets.find(:first, :order => 'committed_on DESC') + since = (c ? c.committed_on - 7.days : nil) - revisions = scm.revisions('', nil, nil, :all => true) + revisions = scm.revisions('', nil, nil, :all => true, :since => since) return if revisions.nil? || revisions.empty? - # Find revisions that redmine knows about already - existing_revisions = changesets.find(:all).map!{|c| c.scmid} + recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since]) # Clean out revisions that are no longer in git - Changeset.delete_all(["scmid NOT IN (?) AND repository_id = (?)", revisions.map{|r| r.scmid}, self.id]) + recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }} # Subtract revisions that redmine already knows about - revisions.reject!{|r| existing_revisions.include?(r.scmid)} + recent_revisions = recent_changesets.map{|c| c.scmid} + revisions.reject!{|r| recent_revisions.include?(r.scmid)} # Save the remaining ones to the database revisions.each{|r| r.save(self)} unless revisions.nil? diff --git a/lib/redmine/scm/adapters/git_adapter.rb b/lib/redmine/scm/adapters/git_adapter.rb index 14e1674b12..604407f5bc 100644 --- a/lib/redmine/scm/adapters/git_adapter.rb +++ b/lib/redmine/scm/adapters/git_adapter.rb @@ -110,11 +110,6 @@ module Redmine end end - def num_revisions - cmd = "#{GIT_BIN} --git-dir #{target('')} log --all --pretty=format:'' | wc -l" - shellout(cmd) {|io| io.gets.chomp.to_i + 1} - end - def revisions(path, identifier_from, identifier_to, options={}) revisions = Revisions.new @@ -124,6 +119,7 @@ module Redmine cmd << " -n #{options[:limit]} " if options[:limit] cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from cmd << " #{shell_quote identifier_to} " if identifier_to + cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since] cmd << " -- #{path}" if path && !path.empty? shellout(cmd) do |io|