public
Description: A pure ruby implementation of Git - unmaintained. See grit for an active project that has inherited much of this code.
Homepage: http://groups.google.com/group/git-ruby
Clone URL: git://github.com/schacon/git-ruby.git
http cloning : (gitr clone http://[something].git my_project) now working
schacon (author)
Mon Mar 31 17:57:40 -0700 2008
commit  cbe5952ddb7eabace75e10edabe0397f715e7be6
tree    195ae0da8b34752ac17924f26239908f8b30042c
parent  21e2d7a32cc879c8e33ca50a7bc42b23b8b17e4d
...
5
6
7
8
 
9
10
11
...
5
6
7
 
8
9
10
11
0
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
0
 spec = Gem::Specification.new do |s|
0
     s.platform = Gem::Platform::RUBY
0
     s.name = "git-ruby"
0
- s.version = "0.1.0"
0
+ s.version = "0.2.0"
0
     s.author = "Scott Chacon"
0
     s.email = "schacon@gmail.com"
0
     s.summary = "A pure ruby implementation of Git"
...
23
24
25
 
26
27
28
...
40
41
42
43
 
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 
 
58
59
60
61
62
 
 
 
63
64
65
...
23
24
25
26
27
28
29
...
41
42
43
 
44
45
46
47
 
 
 
 
 
 
 
 
48
49
50
51
52
53
 
 
 
 
54
55
56
57
58
59
0
@@ -23,6 +23,7 @@ if !command
0
   puts 'usage: gitr (command) [args]'
0
   puts
0
   puts 'commands: init'
0
+ puts ' clone (repo_uri) (name)'
0
   puts ' add'
0
   puts ' commit'
0
   puts ' ls-files'
0
@@ -40,26 +41,19 @@ git_dir = ENV['GIT_DIR'] || '.git'
0
 working_dir = ENV['GIT_WORKING_DIR'] || '.'
0
 #@git = Git.bare(git_dir, :log => Logger.new(STDOUT))
0
 
0
-if command != 'init'
0
+if !['init', 'clone'].include?(command)
0
   @git = GitRuby.open(working_dir)
0
 end
0
 
0
-def short_sha(sha)
0
- if sha
0
- sha[0,8]
0
- else
0
- ' '
0
- end
0
-end
0
-
0
 case command
0
 when 'init'
0
   GitRuby.init
0
+when 'clone'
0
+ GitRuby.clone(ARGV[1], ARGV[2])
0
 when 'ls-files'
0
- puts ['mode', 'repo ', 'index ', 'working ', 'path'].join("\t")
0
- @git.ls_files.sort.each do |f, hsh|
0
- puts [hsh[:mode_index], short_sha(hsh[:sha_repo]), short_sha(hsh[:sha_index]), short_sha(hsh[:sha_working]), hsh[:path]].join("\t")
0
- end
0
+ @git.index.to_s
0
+when 'checkout'
0
+ @git.checkout(ARGV[1])
0
 when 'add'
0
   @git.add(ARGV[1])
0
 when 'commit'
...
35
36
37
38
 
39
40
41
...
35
36
37
 
38
39
40
41
0
@@ -35,7 +35,7 @@ require 'logger'
0
 #
0
 module GitRuby
0
 
0
- VERSION = '0.1.0'
0
+ VERSION = '0.2.0'
0
   
0
   # open a bare repository
0
   #
...
264
265
266
 
 
 
 
267
268
269
...
264
265
266
267
268
269
270
271
272
273
0
@@ -264,6 +264,10 @@ module GitRuby
0
       self.lib.commit(message)
0
     end
0
     
0
+ def checkout(branch)
0
+ self.lib.checkout(branch)
0
+ end
0
+
0
     def cat_file(objectish)
0
       self.lib.object_contents(objectish)
0
     end
...
3
4
5
 
 
 
 
6
7
8
9
10
11
12
13
14
15
...
27
28
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
31
32
...
45
46
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
49
50
...
90
91
92
93
94
95
96
97
98
99
100
101
 
 
 
 
 
102
103
104
105
106
107
 
 
 
 
 
108
109
110
...
159
160
161
 
162
163
164
...
3
4
5
6
7
8
9
10
11
12
13
 
 
 
14
15
16
...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
...
220
221
222
 
 
 
223
224
225
 
 
 
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
...
293
294
295
296
297
298
299
0
@@ -3,13 +3,14 @@ module GitRuby
0
   class GitRubyIndexError < StandardError
0
   end
0
   
0
+ # this file implements my imagination of what the index file does.
0
+ # it accomplishes the same basic tasks, but uses it's own index.gitr file
0
+ # rather than the actual git index file because I don't have the strength to
0
+ # reverse engineer that particular format quite yet. Perhaps one day.
0
   class Index
0
     
0
     attr_accessor :base, :path, :ref, :last_commit, :files
0
     
0
- # for now, this is done entirely in memory - not writing out a file
0
- # so until I can duplicate the git index format, path will be ignored
0
- # for the simple stuff i need to do, pretending we have an index file should be fine
0
     def initialize(base, path, check_path = false)
0
       # read in the current HEAD
0
       if File.extname(path) != '.gitr'
0
@@ -27,6 +28,24 @@ module GitRuby
0
       end
0
     end
0
     
0
+ def short_sha(sha)
0
+ if sha
0
+ sha[0,8]
0
+ else
0
+ ' '
0
+ end
0
+ end
0
+
0
+ def to_s
0
+ scan_working_directory
0
+ outs = []
0
+ outs << ['mode', 'repo ', 'index ', 'working ', 'path'].join("\t")
0
+ @files.sort.each do |f, hsh|
0
+ outs << [hsh[:mode_index], short_sha(hsh[:sha_repo]), short_sha(hsh[:sha_index]), short_sha(hsh[:sha_working]), hsh[:path]].join("\t")
0
+ end
0
+ outs.join("\n")
0
+ end
0
+
0
     def read_head
0
       @files = {}
0
       FileUtils.cd(@base.repo.path) do
0
@@ -45,6 +64,117 @@ module GitRuby
0
       end
0
     end
0
 
0
+
0
+ # scans the current working directory to calculate the shas of files that
0
+ # have been changed since the last scan
0
+ # !! TODO : find removed files !!
0
+ def scan_working_directory
0
+ Dir.chdir(@base.dir.path) do
0
+ Dir.glob('**/*') do |file|
0
+ if File.file?(file)
0
+ file = File.join('.', file) if file[0, 1] != '.'
0
+
0
+ s = File.stat(file)
0
+ mode = sprintf("%o", s.mode)
0
+ mtimesize = s.mtime.to_i.to_s + s.size.to_s
0
+
0
+ if @files[file]
0
+ if(@files[file][:working_mtime_size] != mtimesize)
0
+ sha = Raw::Internal::LooseStorage.calculate_sha(File.read(file), 'blob')
0
+ @files[file][:sha_working] = sha
0
+ @files[file][:mode_working] = mode
0
+ @files[file][:working_mtime_size] = mtimesize
0
+ end
0
+ else
0
+ sha = Raw::Internal::LooseStorage.calculate_sha(File.read(file), 'blob')
0
+ @files[file] = {:path => file, :file => File.basename(file), :type => 'blob',
0
+ :sha_working => sha, :mode_working => mode,
0
+ :working_mtime_size => mtimesize}
0
+ end
0
+ end
0
+ end
0
+ end
0
+ end
0
+
0
+ # are there any files that are in the index not in the repo
0
+ # or modified in the working directory that are not in the index
0
+ #
0
+ def clean?
0
+ scan_working_directory
0
+ clean = true
0
+ @files.each do |f, hsh|
0
+ if hsh[:type] == 'blob' && hsh[:sha_index]
0
+ clean &&= ((hsh[:sha_working] == hsh[:sha_index]) && (hsh[:sha_index] == hsh[:sha_repo]))
0
+ end
0
+ end
0
+ clean
0
+ end
0
+
0
+ # make working directory match the index
0
+ # (takes a ref : ref/heads/master, ref/remote/origin/master)
0
+ # - make sure the current index is clean
0
+ # - resolve the new sha and read it into a parallel struc
0
+ # -- remove wd files in old not in new
0
+ # -- add index files in new not in old
0
+ # -- overwrite wd files different in indexes
0
+ # - update the HEAD to the new branch ref if 'ref/heads', else set to new sha
0
+ #
0
+ def checkout(ref)
0
+ if clean?
0
+ @old_files = @files.dup
0
+ @old_ref = @ref.dup
0
+ @old_last_commit = @last_commit.dup
0
+
0
+ Dir.chdir(@base.repo.path) do
0
+ if File.exists?(ref)
0
+ @ref = ref
0
+ @last_commit = File.read(@ref).chomp
0
+
0
+ @files = {}
0
+ read_commit(@last_commit)
0
+
0
+ Dir.chdir(@base.dir.path) do
0
+ # -- remove wd files in old not in new
0
+ @old_files.each do |f, hsh|
0
+ if(!@files[f] || !@files[f][:sha_index])
0
+ File.unlink(f) if File.file?(f)
0
+ Dir.rmdir(File.dirname(f)) rescue nil
0
+ end
0
+ end
0
+
0
+ # -- add index files in new not in old
0
+ # -- overwrite wd files different in indexes
0
+ @files.each do |f, hsh|
0
+ if(!@old_files[f] || (@old_files[f][:sha_index] != hsh[:sha_index]))
0
+ # put file from repo
0
+ case hsh[:type]
0
+ when 'tree'
0
+ FileUtils.mkdir_p(f)
0
+ when 'blob'
0
+ FileUtils.mkdir_p(File.dirname(f))
0
+ @base.lib.write_file(f, @base.gblob(hsh[:sha_index]).contents)
0
+ end
0
+ end
0
+ end
0
+ end # end work in the working dir
0
+
0
+ # update the HEAD
0
+ ref = @base.lib.write_file('HEAD', "ref: #{ref}")
0
+
0
+ else
0
+ puts 'branch does not exist'
0
+ @files = @old_files
0
+ @ref = @old_ref
0
+ @last_commit = @old_last_commit
0
+ return false
0
+ end
0
+ end
0
+
0
+ else
0
+ puts 'not clean index'
0
+ end
0
+ end
0
+
0
     # read in the commit so we know what in the working directory differs
0
     def read_commit(commit_sha)
0
       # find the tree sha and read the tree
0
@@ -90,21 +220,25 @@ module GitRuby
0
       
0
       if @files[file]
0
         # update an existing file
0
- @files[file][:sha_working] = sha
0
- @files[file][:mode_working] = mode
0
-
0
         @files[file][:sha_index] = sha
0
         @files[file][:mode_index] = mode
0
       else
0
- @files[file] = {:path => file, :file => File.basename(file), :type => 'blob',
0
- :sha_working => sha, :sha_index => sha,
0
- :mode_working => mode, :mode_index => mode}
0
+ @files[file] = {:path => file,
0
+ :file => File.basename(file),
0
+ :type => 'blob',
0
+ :sha_index => sha,
0
+ :mode_index => mode}
0
       end
0
       save_index
0
       sha
0
     end
0
     
0
     def commit(message)
0
+ if clean?
0
+ puts 'no staged files'
0
+ return false
0
+ end
0
+
0
       # find all the modified files
0
       dirs = {}
0
       mods = {}
0
@@ -159,6 +293,7 @@ module GitRuby
0
     end
0
         
0
     def ls_files
0
+ scan_working_directory
0
       @files
0
     end
0
     
...
62
63
64
65
 
 
 
66
67
68
69
70
71
72
73
74
75
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
78
79
...
146
147
148
149
 
150
151
152
...
155
156
157
158
159
160
161
...
364
365
366
367
 
368
369
370
...
62
63
64
 
65
66
67
68
69
70
71
72
73
 
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
176
177
178
 
179
180
181
182
...
185
186
187
 
188
189
190
...
393
394
395
 
396
397
398
399
0
@@ -62,18 +62,48 @@ module GitRuby
0
         # create a local branch
0
         update_ref("refs/heads/#{branch}", revparse("#{remote_name}/#{branch}"))
0
         if !opts[:bare]
0
- # checkout branch
0
+ Dir.chdir(working_dir) do
0
+ dumb_checkout(branch)
0
+ end
0
         end
0
       end
0
             
0
       if opts[:bare]
0
         return {:repository => clone_dir}
0
       else
0
- # !! TODO : checkout to working_dir !!
0
         return {:working_directory => working_dir}
0
       end
0
     end
0
     
0
+ def checkout(branch)
0
+ if branch == branch_current
0
+ puts 'already on branch!'
0
+ end
0
+ @git_index.checkout("refs/heads/#{branch}")
0
+ end
0
+
0
+ # does a dumb checkout - copies the tree pointed to by the branch
0
+ # to the current directory - used by clone, and possibly at some point
0
+ # archive will use this too
0
+ def dumb_checkout(branch)
0
+ sha = revparse(branch)
0
+ commit = commit_data(sha)
0
+ tree_sha = commit['tree']
0
+ dumb_checkout_tree(tree_sha, '.')
0
+ end
0
+
0
+ def dumb_checkout_tree(tree_sha, dir)
0
+ FileUtils.mkdir_p(dir)
0
+ tree = ls_tree(tree_sha)
0
+ tree['blob'].each do |file, blob|
0
+ f = File.join(dir, file)
0
+ write_file(f, object_contents(blob[:sha]))
0
+ end
0
+ tree['tree'].each do |subdir, subtree|
0
+ dumb_checkout_tree(subtree[:sha], subdir)
0
+ end
0
+ end
0
+
0
     def fetch(repository, remote_name)
0
       # look at #{repository} for http://, user@, git://
0
       if repository =~ /^http:\/\//
0
@@ -146,7 +176,7 @@ module GitRuby
0
       obj = sha[2..40]
0
       
0
       path = File.join('objects', dir)
0
-
0
+
0
       if !get_raw_repo.object_exists?(sha)
0
         res = Net::HTTP.get_response(URI.parse("#{url}/objects/#{dir}/#{obj}"))
0
         if res.kind_of?(Net::HTTPSuccess)
0
@@ -155,7 +185,6 @@ module GitRuby
0
           log("#{type} : #{sha} fetched")
0
         else
0
           # file may be packed - get the packfiles if we haven't already and lets try those
0
- puts "trying : #{url}/objects/info/packs"
0
           res = Net::HTTP.get_response(URI.parse("#{url}/objects/info/packs"))
0
           if res.kind_of?(Net::HTTPSuccess)
0
             # fetch packs we don't have, look for it there
0
@@ -364,7 +393,7 @@ module GitRuby
0
     end
0
     
0
     def object_contents(sha)
0
- get_raw_repo.cat_file(revparse(sha)).chomp
0
+ get_raw_repo.cat_file(revparse(sha))
0
     end
0
 
0
     def ls_tree(sha)
...
63
64
65
66
67
68
 
69
70
71
...
83
84
85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
87
88
...
63
64
65
 
 
 
66
67
68
69
...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
0
@@ -63,9 +63,7 @@ module GitRuby
0
         # this function takes content and a type and writes out the loose object and returns a sha
0
         def put_raw_object(content, type)
0
           size = content.length.to_s
0
- if !%w(blob tree commit tag).include?(type) || size !~ /^\d+$/
0
- raise LooseObjectError, "invalid object header"
0
- end
0
+ LooseStorage.verify_header(type, size)
0
           
0
           header = "#{type} #{size}\0"
0
           store = header + content
0
@@ -83,6 +81,22 @@ module GitRuby
0
           end
0
           return sha1
0
         end
0
+
0
+ # simply figure out the sha
0
+ def self.calculate_sha(content, type)
0
+ size = content.length.to_s
0
+ verify_header(type, size)
0
+ header = "#{type} #{size}\0"
0
+ store = header + content
0
+
0
+ Digest::SHA1.hexdigest(store)
0
+ end
0
+
0
+ def self.verify_header(type, size)
0
+ if !%w(blob tree commit tag).include?(type) || size !~ /^\d+$/
0
+ raise LooseObjectError, "invalid object header"
0
+ end
0
+ end
0
 
0
         # private
0
         def unpack_object_header_gently(buf)
...
6
7
8
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
11
12
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
15
...
6
7
8
 
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
0
@@ -6,9 +6,40 @@ class TestIndex < Test::Unit::TestCase
0
     set_file_paths
0
   end
0
   
0
- def test_add
0
+ def test_clean
0
+ @git.chdir do
0
+ assert @git.index.clean?
0
+
0
+ append_file('example.txt', 'my test content')
0
+ assert !@git.index.clean?
0
+
0
+ @git.add('example.txt')
0
+ assert !@git.index.clean?
0
+
0
+ @git.commit('added example.txt')
0
+ assert @git.index.clean?
0
+
0
+ new_file('new_dang_file.txt', 'my test content')
0
+ assert @git.index.clean?
0
+
0
+ @git.add('new_dang_file.txt')
0
+ assert !@git.index.clean?
0
+ end
0
   end
0
   
0
- def test_commit
0
+ def test_checkout
0
+ @git.chdir do
0
+ branch = @git.current_branch
0
+ new_file('new_dang_file.txt', 'my test content')
0
+ @git.add('new_dang_file.txt')
0
+ @git.commit('added new file')
0
+
0
+ @git.checkout('test_branches')
0
+ assert !File.exists?('new_dang_file.txt')
0
+
0
+ @git.checkout(branch)
0
+ assert File.exists?('new_dang_file.txt')
0
+ end
0
   end
0
+
0
 end
0
\ No newline at end of file
...
6
7
8
 
 
 
 
 
 
 
 
9
10
11
...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0
@@ -6,6 +6,14 @@ class TestLib < Test::Unit::TestCase
0
     set_file_paths
0
   end
0
   
0
+ def test_dumb_checkout
0
+ in_temp_dir do
0
+ assert !File.exists?('example.txt')
0
+ @git.lib.dumb_checkout('test_object')
0
+ assert File.exists?('example.txt')
0
+ end
0
+ end
0
+
0
   def test_revparse
0
     #self.lib.revparse(objectish)
0
   end

Comments

    No one has commented yet.