]> source.dussan.org Git - redmine.git/commitdiff
Do not parse the entire git log to fetch new commits (takes several minutes for a...
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 7 Feb 2010 15:17:21 +0000 (15:17 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 7 Feb 2010 15:17:21 +0000 (15:17 +0000)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3394 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/models/repository/git.rb
lib/redmine/scm/adapters/git_adapter.rb

index dd5e9e3166f48730b4e080c91e6f3cfd2f1a43a0..473eb07e290d864efb530683b3e329915bbc9728 100644 (file)
@@ -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?
index 14e1674b1286caf46688352299cf213648205bd0..604407f5bce9efca0169518efdfe186d52eb6ae1 100644 (file)
@@ -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|