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