Patch #250 » git_patch_against_svn_revision_1069.diff
app/helpers/repositories_helper.rb (working copy) | ||
---|---|---|
76 | 76 |
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) |
77 | 77 |
end |
78 | 78 | |
79 |
def git_field_tags(form, repository) |
|
80 |
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) |
|
81 |
end |
|
82 | ||
79 | 83 |
def cvs_field_tags(form, repository) |
80 | 84 |
content_tag('p', form.text_field(:root_url, :label => 'CVSROOT', :size => 60, :required => true, :disabled => !repository.new_record?)) + |
81 | 85 |
content_tag('p', form.text_field(:url, :label => 'Module', :size => 30, :required => true, :disabled => !repository.new_record?)) |
app/models/repository/subversion.rb (working copy) | ||
---|---|---|
42 | 42 |
db_revision = latest_changeset ? latest_changeset.revision : 0 |
43 | 43 |
# latest revision in the repository |
44 | 44 |
scm_revision = scm_info.lastrev.identifier.to_i |
45 |
if db_revision < scm_revision |
|
45 |
if db_revision.to_i < scm_revision
|
|
46 | 46 |
logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug? |
47 | 47 |
identifier_from = db_revision + 1 |
48 | 48 |
while (identifier_from <= scm_revision) |
app/models/repository/git.rb (revision 0) | ||
---|---|---|
1 |
# redMine - project management software |
|
2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 |
# Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com |
|
4 |
# This program is free software; you can redistribute it and/or |
|
5 |
# modify it under the terms of the GNU General Public License |
|
6 |
# as published by the Free Software Foundation; either version 2 |
|
7 |
# of the License, or (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# 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 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | ||
18 |
require 'redmine/scm/adapters/git_adapter' |
|
19 | ||
20 |
class Repository::Git < Repository |
|
21 |
attr_protected :root_url |
|
22 |
validates_presence_of :url |
|
23 | ||
24 |
def scm_adapter |
|
25 |
Redmine::Scm::Adapters::GitAdapter |
|
26 |
end |
|
27 |
|
|
28 |
def self.scm_name |
|
29 |
'Git' |
|
30 |
end |
|
31 |
|
|
32 |
def entries(path=nil, identifier=nil) |
|
33 |
entries=scm.entries(path, identifier) |
|
34 |
if entries |
|
35 |
entries.each do |entry| |
|
36 |
next unless entry.is_file? |
|
37 |
# Search the DB for the entry's last change |
|
38 |
change = changes.find(:first, :conditions => ["path = ?", scm.with_leading_slash(entry.path)], :order => "#{Changeset.table_name}.committed_on DESC") |
|
39 |
if change |
|
40 |
entry.lastrev.identifier = change.changeset.revision |
|
41 |
entry.lastrev.name = change.changeset.revision |
|
42 |
entry.lastrev.author = change.changeset.committer |
|
43 |
entry.lastrev.revision = change.revision |
|
44 |
end |
|
45 |
end |
|
46 |
end |
|
47 |
entries |
|
48 |
end |
|
49 | ||
50 |
def changesets_for_path(path) |
|
51 |
path = "#{path}" unless path.starts_with?('/') |
|
52 |
Change.find(:all, :include => :changeset, |
|
53 |
:conditions => ["repository_id = ? AND path = ?", id, path], |
|
54 |
:order => "committed_on DESC, #{Changeset.table_name}.revision DESC").collect(&:changeset) |
|
55 |
end |
|
56 | ||
57 |
def fetch_changesets |
|
58 |
scm_info = scm.info |
|
59 |
|
|
60 |
if scm_info |
|
61 |
# latest revision found in database |
|
62 |
db_revision = latest_changeset ? latest_changeset.revision : nil |
|
63 |
# latest revision in the repository |
|
64 |
scm_revision = scm_info.lastrev.identifier |
|
65 | ||
66 |
unless changesets.find_by_revision(scm_revision) |
|
67 | ||
68 |
revisions = scm.revisions('', db_revision, nil) |
|
69 |
transaction do |
|
70 |
revisions.reverse_each do |revision| |
|
71 |
changeset = Changeset.create(:repository => self, |
|
72 |
:revision => revision.identifier, |
|
73 |
:scmid => revision.scmid, |
|
74 |
:committer => revision.author, |
|
75 |
:committed_on => revision.time, |
|
76 |
:comments => revision.message) |
|
77 |
|
|
78 |
revision.paths.each do |change| |
|
79 |
Change.create(:changeset => changeset, |
|
80 |
:action => change[:action], |
|
81 |
:path => change[:path], |
|
82 |
:from_path => change[:from_path], |
|
83 |
:from_revision => change[:from_revision]) |
|
84 |
end |
|
85 |
end |
|
86 |
end |
|
87 |
end |
|
88 |
end |
|
89 |
end |
|
90 |
end |
app/models/changeset.rb (working copy) | ||
---|---|---|
32 | 32 |
:date_column => 'committed_on' |
33 | 33 |
|
34 | 34 |
validates_presence_of :repository_id, :revision, :committed_on, :commit_date |
35 |
validates_numericality_of :revision, :only_integer => true |
|
35 |
# validates_numericality_of :revision, :only_integer => true
|
|
36 | 36 |
validates_uniqueness_of :revision, :scope => :repository_id |
37 | 37 |
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true |
38 | 38 |
|
app/controllers/repositories_controller.rb (working copy) | ||
---|---|---|
121 | 121 |
end |
122 | 122 |
|
123 | 123 |
def diff |
124 |
@rev_to = params[:rev_to] ? params[:rev_to].to_i : (@rev - 1)
|
|
124 |
get_rev_to
|
|
125 | 125 |
@diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' |
126 | 126 |
@diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) |
127 | 127 |
|
... | ... | |
170 | 170 |
render_404 and return false unless @repository |
171 | 171 |
@path = params[:path].join('/') unless params[:path].nil? |
172 | 172 |
@path ||= '' |
173 |
@rev = params[:rev].to_i if params[:rev]
|
|
173 |
@rev = params[:rev] if params[:rev] |
|
174 | 174 |
rescue ActiveRecord::RecordNotFound |
175 | 175 |
render_404 |
176 | 176 |
end |
177 | 177 | |
178 |
def get_rev_to |
|
179 |
@rev_to = params[:rev_to].to_i ? params[:rev_to].to_i : (@rev.to_i - 1) if @rev !~ /\D/ |
|
180 |
@rev_to = params[:rev_to] ? params[:rev_to] : (nil) if !(@rev !~ /\D/) |
|
181 |
end |
|
182 | ||
178 | 183 |
def show_error |
179 | 184 |
flash.now[:error] = l(:notice_scm_error) |
180 | 185 |
render :nothing => true, :layout => true |
app/views/repositories/_revisions.rhtml (working copy) | ||
---|---|---|
13 | 13 |
<% line_num = 1 %> |
14 | 14 |
<% revisions.each do |changeset| %> |
15 | 15 |
<tr class="changeset <%= cycle 'odd', 'even' %>"> |
16 |
<td class="id"><%= link_to changeset.revision, :action => 'revision', :id => project, :rev => changeset.revision %></td> |
|
16 |
<td class="id"><%= link_to changeset.revision[0..5], :action => 'revision', :id => project, :rev => changeset.revision %></td>
|
|
17 | 17 |
<td class="checkbox"><%= radio_button_tag('rev', changeset.revision, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < revisions.size) %></td> |
18 | 18 |
<td class="checkbox"><%= radio_button_tag('rev_to', changeset.revision, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %></td> |
19 | 19 |
<td class="committed_on"><%= format_time(changeset.committed_on) %></td> |
20 |
<td class="author"><%=h changeset.committer %></td> |
|
20 |
<td class="author"><%=h changeset.committer.split('<').first %></td>
|
|
21 | 21 |
<td class="comments"><%= textilizable(changeset.comments) %></td> |
22 | 22 |
</tr> |
23 | 23 |
<% line_num += 1 %> |
app/views/repositories/_dir_list_content.rhtml (working copy) | ||
---|---|---|
23 | 23 |
end %> |
24 | 24 |
</td> |
25 | 25 |
<td class="size"><%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %></td> |
26 |
<td class="revision"><%= link_to(entry.lastrev.name, :action => 'revision', :id => @project, :rev => entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %></td> |
|
26 |
<td class="revision"><%= link_to(entry.lastrev.name[0..5], :action => 'revision', :id => @project, :rev => entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %></td>
|
|
27 | 27 |
<td class="age"><%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %></td> |
28 |
<td class="author"><%=h(entry.lastrev.author) if entry.lastrev %></td> |
|
28 |
<td class="author"><%=h(entry.lastrev.author.split('<').first) if entry.lastrev %></td>
|
|
29 | 29 |
<% changeset = @project.repository.changesets.find_by_revision(entry.lastrev.identifier) if entry.lastrev %> |
30 | 30 |
<td class="comments"><%=h truncate(changeset.comments, 50) unless changeset.nil? %></td> |
31 | 31 |
</tr> |
db/migrate/087_make_revisions_string.rb (revision 0) | ||
---|---|---|
1 |
class MakeRevisionsString < ActiveRecord::Migration |
|
2 |
def self.up |
|
3 |
change_column :changes, :from_revision, :string |
|
4 |
change_column :changesets, :revision, :string |
|
5 |
end |
|
6 | ||
7 |
def self.down |
|
8 |
change_column :changes, :from_revision, :integer |
|
9 |
change_column :changesets, :revision, :integer |
|
10 |
end |
|
11 |
end |
lib/redmine/scm/adapters/abstract_adapter.rb (working copy) | ||
---|---|---|
182 | 182 |
end |
183 | 183 |
}.last |
184 | 184 |
end |
185 |
end |
|
185 |
end |
|
186 |
|
|
187 | ||
188 |
def get_rev(rev,path) |
|
189 |
Revision.new |
|
190 |
end |
|
186 | 191 |
|
187 | 192 |
class Revision |
188 | 193 |
attr_accessor :identifier, :scmid, :name, :author, :time, :message, :paths, :revision, :branch |
lib/redmine/scm/adapters/git_adapter.rb (revision 0) | ||
---|---|---|
1 |
# redMine - project management software |
|
2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or |
|
5 |
# modify it under the terms of the GNU General Public License |
|
6 |
# as published by the Free Software Foundation; either version 2 |
|
7 |
# of the License, or (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# 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 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 | ||
18 |
require 'redmine/scm/adapters/abstract_adapter' |
|
19 | ||
20 |
module Redmine |
|
21 |
module Scm |
|
22 |
module Adapters |
|
23 |
class GitAdapter < AbstractAdapter |
|
24 |
|
|
25 |
# Git executable name |
|
26 |
GIT_BIN = "git" |
|
27 |
|
|
28 | ||
29 |
#get the revision of a particuliar file |
|
30 |
def get_rev (rev,path) |
|
31 |
cmd="cd #{target('')} && git show #{rev} #{path}" if rev!='latest' |
|
32 |
cmd="cd #{target('')} && git log -1 master -- #{path}" if |
|
33 |
rev=='latest' or rev.nil? |
|
34 |
puts cmd |
|
35 |
rev=[] |
|
36 |
i=0 |
|
37 |
shellout(cmd) do |io| |
|
38 |
commit_files=[] |
|
39 |
params={:commit=>'',:author=>'',:date=>'',:message=>'',:file=>{:path=>'',:action=>''}} |
|
40 |
|
|
41 |
message='' |
|
42 |
io.each_line do |line| |
|
43 | ||
44 |
i=0 if line=~/^commit/ |
|
45 |
params[:commit]=line.chomp.gsub("commit ",'') if i==0 |
|
46 |
|
|
47 |
params[:author]=line.chomp.gsub("Author: ",'') if i==1 |
|
48 |
params[:date]=line.chomp.gsub("Date: ",'') if i==2 |
|
49 |
params[:message]+= line.chomp.to_s if i==4 and line[0..0]!=':' |
|
50 |
params[:file][:action], params[:file][:path]= line.chomp.slice(/[ACDMRTUXB].*/).split(' ', 2) if i>=4 and line[0..0]==':' |
|
51 |
commit_files << {:action=>params[:file][:action],:path=>params[:file][:path]} if i>=4 and line[0..0]==':' |
|
52 |
i+=1 |
|
53 |
end |
|
54 |
|
|
55 |
rev = Revision.new({:identifier => params[:commit], |
|
56 |
:scmid => params[:commit], |
|
57 |
:author => params[:author], |
|
58 |
:time => Time.parse(params[:date]), |
|
59 |
:message => params[:message], |
|
60 |
:paths => commit_files |
|
61 |
}) |
|
62 |
end |
|
63 | ||
64 |
get_rev('latest',path) if i==0 |
|
65 | ||
66 |
return nil if $? && $?.exitstatus != 0 |
|
67 |
return rev |
|
68 |
# rescue Errno::ENOENT => e |
|
69 |
# raise CommandFailed |
|
70 |
end |
|
71 | ||
72 | ||
73 |
def info |
|
74 |
# cmd = "#{GIT_BIN} -R #{target('')} root" |
|
75 |
# root_url = nil |
|
76 |
# shellout(cmd) do |io| |
|
77 |
root_url = target('') |
|
78 |
# end |
|
79 |
return nil if $? && $?.exitstatus != 0 |
|
80 |
info = Info.new({:root_url => target(''), |
|
81 |
:lastrev => revisions(root_url,nil,nil,nil).first |
|
82 |
}) |
|
83 |
info |
|
84 |
rescue Errno::ENOENT => e |
|
85 |
return nil |
|
86 |
end |
|
87 |
|
|
88 |
def entries(path=nil, identifier=nil) |
|
89 |
path ||= '' |
|
90 |
entries = Entries.new |
|
91 |
cmd = "cd #{target('')} && #{GIT_BIN} show HEAD:#{path}" if identifier.nil? |
|
92 |
cmd = "cd #{target('')} && #{GIT_BIN} show #{identifier}:#{path}" if identifier |
|
93 |
shellout(cmd) do |io| |
|
94 |
io.each_line do |line| |
|
95 |
e = line.chomp.split('\\') |
|
96 |
unless e.to_s.strip=='' or line[0..3]=='tree' |
|
97 |
name=e.first.split('/')[0] |
|
98 |
entries << Entry.new({:name => name, |
|
99 |
:path => (path.empty? ? name : "#{path}/#{name}"), |
|
100 |
:kind => ((e.first.include? '/') ? 'dir' : 'file'), |
|
101 |
:lastrev => get_rev(identifier,(path.empty? ? name : "#{path}/#{name}")) |
|
102 |
}) unless entries.detect{|entry| entry.name == name} |
|
103 |
puts e[0..3] |
|
104 |
end |
|
105 |
end |
|
106 |
end |
|
107 |
return nil if $? && $?.exitstatus != 0 |
|
108 |
entries.sort_by_name |
|
109 |
# rescue Errno::ENOENT => e |
|
110 |
# raise CommandFailed |
|
111 |
end |
|
112 |
|
|
113 |
def entry(path=nil, identifier=nil) |
|
114 |
path ||= '' |
|
115 |
search_path = path.split('/')[0..-2].join('/') |
|
116 |
entry_name = path.split('/').last |
|
117 |
e = entries(search_path, identifier) |
|
118 |
e ? e.detect{|entry| entry.name == entry_name} : nil |
|
119 |
end |
|
120 |
|
|
121 |
def revisions(path, identifier_from, identifier_to, options={}) |
|
122 |
revisions = Revisions.new |
|
123 |
cmd = "cd #{target('')} && #{GIT_BIN} whatchanged " |
|
124 |
cmd << " #{identifier_from}.. " if identifier_from |
|
125 |
cmd << " #{identifier_to} " if identifier_to |
|
126 |
#cmd << " HEAD " if !identifier_to |
|
127 |
puts cmd |
|
128 |
shellout(cmd) do |io| |
|
129 |
files=[] |
|
130 |
params={:commit=>'',:author=>'',:date=>'',:message=>'',:file=>{:path=>'',:action=>''}} |
|
131 |
i=0 |
|
132 |
message='' |
|
133 |
io.each_line do |line| |
|
134 |
|
|
135 |
if line=~/^commit/ and i>0 |
|
136 |
revisions << Revision.new({:identifier => params[:commit], |
|
137 |
:scmid => params[:commit], |
|
138 |
:author => params[:author], |
|
139 |
:time => Time.parse(params[:date]), |
|
140 |
:message => params[:message], |
|
141 |
:paths => files |
|
142 |
}) |
|
143 |
|
|
144 |
files=[] |
|
145 |
i=0 |
|
146 |
params={:commit=>'',:author=>'',:date=>'',:message=>'',:file=>{:path=>'',:action=>''}} |
|
147 |
end |
|
148 |
params[:commit]=line.chomp.gsub("commit ",'') if i==0 |
|
149 |
params[:author]=line.chomp.gsub("Author: ",'') if i==1 |
|
150 |
params[:date]=line.chomp.gsub("Date: ",'') if i==2 |
|
151 |
params[:message]+= line.chomp.to_s if i>=4 and line[0..0]!=':' |
|
152 |
params[:file][:action], params[:file][:path]= line.chomp.slice(/[ACDMRTUXB].*/).split(' ', 2) if i>=4 and line[0..0]==':' |
|
153 |
files << {:action=>params[:file][:action],:path=>params[:file][:path]} if i>=4 and line[0..0]==':' |
|
154 |
i+=1 |
|
155 |
end |
|
156 |
end |
|
157 | ||
158 |
return nil if $? && $?.exitstatus != 0 |
|
159 |
revisions |
|
160 |
rescue Errno::ENOENT => e |
|
161 |
raise CommandFailed |
|
162 |
puts 'revs: #{revisions}' |
|
163 |
end |
|
164 |
|
|
165 |
def diff(path, identifier_from, identifier_to=nil, type="inline") |
|
166 |
path ||= '' |
|
167 |
if identifier_to |
|
168 |
identifier_to = identifier_to |
|
169 |
else |
|
170 |
identifier_to = nil |
|
171 |
end |
|
172 |
cmd = "cd #{target('')} && #{GIT_BIN} diff #{identifier_from}^!" if identifier_to.nil? |
|
173 |
cmd = "cd #{target('')} && #{GIT_BIN} diff #{identifier_to} #{identifier_from}" if !identifier_to.nil? |
|
174 |
cmd << " #{path}" unless path.empty? |
|
175 |
diff = [] |
|
176 |
shellout(cmd) do |io| |
|
177 |
io.each_line do |line| |
|
178 |
diff << line |
|
179 |
end |
|
180 |
end |
|
181 |
return nil if $? && $?.exitstatus != 0 |
|
182 |
DiffTableList.new diff, type |
|
183 |
|
|
184 |
rescue Errno::ENOENT => e |
|
185 |
raise CommandFailed |
|
186 |
end |
|
187 |
|
|
188 |
def cat(path, identifier=nil) |
|
189 |
cmd = "cd #{target('')} && #{GIT_BIN} show #{identifier}:#{path}" |
|
190 |
cat = nil |
|
191 |
shellout(cmd) do |io| |
|
192 |
io.binmode |
|
193 |
cat = io.read |
|
194 |
end |
|
195 |
return nil if $? && $?.exitstatus != 0 |
|
196 |
cat |
|
197 |
rescue Errno::ENOENT => e |
|
198 |
raise CommandFailed |
|
199 |
end |
|
200 |
end |
|
201 |
end |
|
202 |
end |
|
203 | ||
204 |
end |
|
205 |
lib/redmine.rb (working copy) | ||
---|---|---|
10 | 10 |
# RMagick is not available |
11 | 11 |
end |
12 | 12 | |
13 |
REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar ) |
|
13 |
REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git )
|
|
14 | 14 | |
15 | 15 |
# Permissions |
16 | 16 |
Redmine::AccessControl.map do |map| |