comparison app/models/repository/git.rb @ 514:7eba09d624db live

Merge
author Chris Cannam
date Thu, 14 Jul 2011 10:50:53 +0100
parents 851510f1b535
children 5e80956cc792
comparison
equal deleted inserted replaced
512:b9aebdd7dd40 514:7eba09d624db
1 # redMine - project management software 1 # Redmine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 # Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com 3 # Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com
4 #
4 # This program is free software; you can redistribute it and/or 5 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License 6 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2 7 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version. 8 # of the License, or (at your option) any later version.
8 # 9 #
9 # This program is distributed in the hope that it will be useful, 10 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details. 13 # GNU General Public License for more details.
13 # 14 #
14 # You should have received a copy of the GNU General Public License 15 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software 16 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 18
18 require 'redmine/scm/adapters/git_adapter' 19 require 'redmine/scm/adapters/git_adapter'
19 20
20 class Repository::Git < Repository 21 class Repository::Git < Repository
21 attr_protected :root_url 22 attr_protected :root_url
22 validates_presence_of :url 23 validates_presence_of :url
23 24
24 def scm_adapter 25 def self.human_attribute_name(attribute_key_name)
26 attr_name = attribute_key_name
27 if attr_name == "url"
28 attr_name = "path_to_repository"
29 end
30 super(attr_name)
31 end
32
33 def self.scm_adapter_class
25 Redmine::Scm::Adapters::GitAdapter 34 Redmine::Scm::Adapters::GitAdapter
26 end 35 end
27 36
28 def self.scm_name 37 def self.scm_name
29 'Git' 38 'Git'
39 end
40
41 def report_last_commit
42 extra_report_last_commit
43 end
44
45 def extra_report_last_commit
46 return false if extra_info.nil?
47 v = extra_info["extra_report_last_commit"]
48 return false if v.nil?
49 v.to_s != '0'
50 end
51
52 def supports_directory_revisions?
53 true
54 end
55
56 def repo_log_encoding
57 'UTF-8'
58 end
59
60 # Returns the identifier for the given git changeset
61 def self.changeset_identifier(changeset)
62 changeset.scmid
63 end
64
65 # Returns the readable identifier for the given git changeset
66 def self.format_changeset_identifier(changeset)
67 changeset.revision[0, 8]
30 end 68 end
31 69
32 def branches 70 def branches
33 scm.branches 71 scm.branches
34 end 72 end
35 73
36 def tags 74 def tags
37 scm.tags 75 scm.tags
38 end 76 end
39 77
40 # With SCM's that have a sequential commit numbering, redmine is able to be 78 def default_branch
41 # clever and only fetch changesets going forward from the most recent one 79 scm.default_branch
42 # it knows about. However, with git, you never know if people have merged 80 end
43 # commits into the middle of the repository history, so we should parse 81
44 # the entire log. Since it's way too slow for large repositories, we only 82 def find_changeset_by_name(name)
45 # parse 1 week before the last known commit. 83 return nil if name.nil? || name.empty?
84 e = changesets.find(:first, :conditions => ['revision = ?', name.to_s])
85 return e if e
86 changesets.find(:first, :conditions => ['scmid LIKE ?', "#{name}%"])
87 end
88
89 def entries(path=nil, identifier=nil)
90 scm.entries(path,
91 identifier,
92 options = {:report_last_commit => extra_report_last_commit})
93 end
94
95 # In Git and Mercurial, revisions are not in date order.
96 # Redmine Mercurial fixed issues.
97 # * Redmine Takes Too Long On Large Mercurial Repository
98 # http://www.redmine.org/issues/3449
99 # * Sorting for changesets might go wrong on Mercurial repos
100 # http://www.redmine.org/issues/3567
101 #
102 # Database revision column is text, so Redmine can not sort by revision.
103 # Mercurial has revision number, and revision number guarantees revision order.
104 # Redmine Mercurial model stored revisions ordered by database id to database.
105 # So, Redmine Mercurial model can use correct ordering revisions.
106 #
107 # Redmine Mercurial adapter uses "hg log -r 0:tip --limit 10"
108 # to get limited revisions from old to new.
109 # But, Git 1.7.3.4 does not support --reverse with -n or --skip.
110 #
46 # The repository can still be fully reloaded by calling #clear_changesets 111 # The repository can still be fully reloaded by calling #clear_changesets
47 # before fetching changesets (eg. for offline resync) 112 # before fetching changesets (eg. for offline resync)
48 def fetch_changesets 113 def fetch_changesets
49 c = changesets.find(:first, :order => 'committed_on DESC') 114 scm_brs = branches
50 since = (c ? c.committed_on - 7.days : nil) 115 return if scm_brs.nil? || scm_brs.empty?
116 h1 = extra_info || {}
117 h = h1.dup
118 h["branches"] ||= {}
119 h["db_consistent"] ||= {}
120 if changesets.count == 0
121 h["db_consistent"]["ordering"] = 1
122 merge_extra_info(h)
123 self.save
124 elsif ! h["db_consistent"].has_key?("ordering")
125 h["db_consistent"]["ordering"] = 0
126 merge_extra_info(h)
127 self.save
128 end
129 scm_brs.each do |br|
130 from_scmid = nil
131 from_scmid = h["branches"][br]["last_scmid"] if h["branches"][br]
132 h["branches"][br] ||= {}
133 scm.revisions('', from_scmid, br, {:reverse => true}) do |rev|
134 db_rev = find_changeset_by_name(rev.revision)
135 transaction do
136 if db_rev.nil?
137 save_revision(rev)
138 end
139 h["branches"][br]["last_scmid"] = rev.scmid
140 merge_extra_info(h)
141 self.save
142 end
143 end
144 end
145 end
51 146
52 revisions = scm.revisions('', nil, nil, :all => true, :since => since, :reverse => true) 147 def save_revision(rev)
53 return if revisions.nil? || revisions.empty? 148 changeset = Changeset.new(
54 149 :repository => self,
55 recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since]) 150 :revision => rev.identifier,
56 151 :scmid => rev.scmid,
57 # Clean out revisions that are no longer in git 152 :committer => rev.author,
58 recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }} 153 :committed_on => rev.time,
59 154 :comments => rev.message
60 # Subtract revisions that redmine already knows about 155 )
61 recent_revisions = recent_changesets.map{|c| c.scmid} 156 if changeset.save
62 revisions.reject!{|r| recent_revisions.include?(r.scmid)} 157 rev.paths.each do |file|
63 158 Change.create(
64 # Save the remaining ones to the database 159 :changeset => changeset,
65 revisions.each{|r| r.save(self)} unless revisions.nil? 160 :action => file[:action],
161 :path => file[:path])
162 end
163 end
66 end 164 end
165 private :save_revision
67 166
68 def latest_changesets(path,rev,limit=10) 167 def latest_changesets(path,rev,limit=10)
69 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false) 168 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
70 return [] if revisions.nil? || revisions.empty? 169 return [] if revisions.nil? || revisions.empty?
71 170
72 changesets.find( 171 changesets.find(
73 :all, 172 :all,
74 :conditions => [ 173 :conditions => [
75 "scmid IN (?)", 174 "scmid IN (?)",
76 revisions.map!{|c| c.scmid} 175 revisions.map!{|c| c.scmid}
77 ], 176 ],
78 :order => 'id DESC' 177 :order => 'committed_on DESC'
79 ) 178 )
80 end 179 end
81 end 180 end