Skip to content

Commit a123767

Browse files
author
scott Chacon
committed
git add working, git status object working
1 parent efcce7f commit a123767

File tree

8 files changed

+247
-28
lines changed

8 files changed

+247
-28
lines changed

EXAMPLES

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@ g = Git.init
8181
g = Git.clone(URI, :name => 'name', :path => '/tmp/checkout'
8282
(git_dir, index_file)
8383

84+
g.config('user.name', 'Scott Chacon')
85+
g.config('user.email', 'email@email.com')
86+
8487

8588
***** IMPLEMENTED *****
8689

87-
88-
g.config('user.name', 'Scott Chacon')
89-
g.config('user.email', 'email@email.com')
9090

9191
g.add('.')
9292
g.add([file1, file2])

lib/git.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
require 'git/remote'
2121

2222
require 'git/diff'
23+
require 'git/status'
2324
=begin
2425
require 'git/author'
2526
require 'git/file'

lib/git/base.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def index
9292
def config(name = nil, value = nil)
9393
if(name && value)
9494
# set value
95+
lib.config_set(name, value)
9596
elsif (name)
9697
# return value
9798
lib.config_get(name)
@@ -114,7 +115,11 @@ def object(objectish)
114115
def log(count = 30)
115116
Git::Log.new(self, count)
116117
end
117-
118+
119+
def status
120+
Git::Status.new(self)
121+
end
122+
118123
def branches
119124
Git::Branches.new(self)
120125
end
@@ -131,6 +136,11 @@ def diff(objectish = 'HEAD', obj2 = nil)
131136
Git::Diff.new(self, objectish, obj2)
132137
end
133138

139+
# adds files from the working directory to the git repository
140+
def add(path = '.')
141+
self.lib.add(path)
142+
end
143+
134144
# convenience methods
135145

136146
def revparse(objectish)

lib/git/lib.rb

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ def clone(repository, name, opts = {})
5252
opts[:bare] ? {:repository => clone_dir} : {:working_directory => clone_dir}
5353
end
5454

55+
56+
## READ COMMANDS ##
57+
58+
5559
def log_commits(opts = {})
5660
arr_opts = ['--pretty=oneline']
5761
arr_opts << "-#{opts[:count]}" if opts[:count]
@@ -89,28 +93,6 @@ def branches_all
8993
arr
9094
end
9195

92-
def config_get(name)
93-
command('config', ['--get', name])
94-
end
95-
96-
def config_list
97-
hsh = {}
98-
command_lines('config', ['--list']).each do |line|
99-
(key, value) = line.split('=')
100-
hsh[key] = value
101-
end
102-
hsh
103-
end
104-
105-
def config_remote(name)
106-
hsh = {}
107-
command_lines('config', ['--get-regexp', "remote.#{name}"]).each do |line|
108-
(key, value) = line.split
109-
hsh[key.gsub("remote.#{name}.", '')] = value
110-
end
111-
hsh
112-
end
113-
11496
# returns hash
11597
# [tree-ish] = [[line_no, match], [line_no, match2]]
11698
# [tree-ish] = [[line_no, match], [line_no, match2]]
@@ -161,10 +143,78 @@ def diff_stats(obj1 = 'HEAD', obj2 = nil, opts = {})
161143

162144
hsh
163145
end
146+
147+
# compares the index and the working directory
148+
def diff_files
149+
hsh = {}
150+
command_lines('diff-files').each do |line|
151+
(info, file) = line.split("\t")
152+
(mode_src, mode_dest, sha_src, sha_dest, type) = info.split
153+
hsh[file] = {:path => file, :mode_file => mode_src, :mode_index => mode_dest,
154+
:sha_file => sha_src, :sha_index => sha_dest, :type => type}
155+
end
156+
hsh
157+
end
158+
159+
# compares the index and the repository
160+
def diff_index(treeish)
161+
hsh = {}
162+
command_lines('diff-index', treeish).each do |line|
163+
(info, file) = line.split("\t")
164+
(mode_src, mode_dest, sha_src, sha_dest, type) = info.split
165+
hsh[file] = {:path => file, :mode_repo => mode_src, :mode_index => mode_dest,
166+
:sha_repo => sha_src, :sha_index => sha_dest, :type => type}
167+
end
168+
hsh
169+
end
170+
171+
def ls_files
172+
hsh = {}
173+
command_lines('ls-files', '--stage').each do |line|
174+
(info, file) = line.split("\t")
175+
(mode, sha, stage) = info.split
176+
hsh[file] = {:path => file, :mode_index => mode, :sha_index => sha, :stage => stage}
177+
end
178+
hsh
179+
end
180+
181+
182+
def config_remote(name)
183+
hsh = {}
184+
command_lines('config', ['--get-regexp', "remote.#{name}"]).each do |line|
185+
(key, value) = line.split
186+
hsh[key.gsub("remote.#{name}.", '')] = value
187+
end
188+
hsh
189+
end
190+
191+
def config_get(name)
192+
command('config', ['--get', name])
193+
end
194+
195+
def config_list
196+
hsh = {}
197+
command_lines('config', ['--list']).each do |line|
198+
(key, value) = line.split('=')
199+
hsh[key] = value
200+
end
201+
hsh
202+
end
203+
204+
## WRITE COMMANDS ##
205+
206+
def config_set(name, value)
207+
command('config', [name, "'#{value}'"])
208+
end
209+
210+
def add(path = '.')
211+
command('add', path)
212+
end
164213

214+
165215
private
166216

167-
def command_lines(cmd, opts)
217+
def command_lines(cmd, opts = {})
168218
command(cmd, opts).split("\n")
169219
end
170220

@@ -177,6 +227,7 @@ def command(cmd, opts = {})
177227
#puts "git #{cmd} #{opts}"
178228
out = `git #{cmd} #{opts} 2>&1`.chomp
179229
#puts out
230+
#puts
180231
if $?.exitstatus > 1
181232
raise Git::GitExecuteError.new(out)
182233
end

lib/git/status.rb

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
module Git
2+
3+
class Status
4+
include Enumerable
5+
6+
@base = nil
7+
@files = nil
8+
9+
def initialize(base)
10+
@base = base
11+
construct_status
12+
end
13+
14+
def changed
15+
@files.select { |k, f| f.type == 'M' }
16+
end
17+
18+
def added
19+
@files.select { |k, f| f.type == 'A' }
20+
end
21+
22+
def untracked
23+
@files.select { |k, f| f.untracked }
24+
end
25+
26+
def pretty
27+
out = ''
28+
self.each do |file|
29+
out << file.path
30+
out << "\n\tsha(r) " + file.sha_repo.to_s
31+
out << "\n\tsha(i) " + file.sha_index.to_s
32+
out << "\n\ttype " + file.type.to_s
33+
out << "\n\tstage " + file.stage.to_s
34+
out << "\n\tuntrac " + file.untracked.to_s
35+
out << "\n"
36+
end
37+
out << "\n"
38+
out
39+
end
40+
41+
# enumerable method
42+
43+
def [](file)
44+
@files[file]
45+
end
46+
47+
def each
48+
@files.each do |k, file|
49+
yield file
50+
end
51+
end
52+
53+
class StatusFile
54+
attr_accessor :path, :type, :stage, :untracked
55+
attr_accessor :mode_index, :mode_repo
56+
attr_accessor :sha_index, :sha_repo
57+
58+
def initialize(hash)
59+
@path = hash[:path]
60+
@type = hash[:type]
61+
@stage = hash[:stage]
62+
@mode_index = hash[:mode_index]
63+
@mode_repo = hash[:mode_repo]
64+
@sha_index = hash[:sha_index]
65+
@sha_repo = hash[:sha_repo]
66+
@untracked = hash[:untracked]
67+
end
68+
69+
70+
end
71+
72+
private
73+
74+
def construct_status
75+
@files = @base.lib.ls_files
76+
77+
# find untracked in working dir
78+
Dir.chdir(@base.dir.path) do
79+
Dir.glob('**/*') do |file|
80+
if !@files[file]
81+
@files[file] = {:path => file, :untracked => true} if !File.directory?(file)
82+
end
83+
end
84+
end
85+
86+
# find modified in tree
87+
@base.lib.diff_files.each do |path, data|
88+
@files[path].merge!(data)
89+
end
90+
91+
# find added but not committed - new files
92+
@base.lib.diff_index('HEAD').each do |path, data|
93+
@files[path].merge!(data)
94+
end
95+
96+
@files.each do |k, file_hash|
97+
@files[k] = StatusFile.new(file_hash)
98+
end
99+
end
100+
101+
end
102+
103+
end

tests/units/test_config.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ def test_read_config
2020
end
2121

2222
def test_set_config
23-
# !! TODO !!
23+
in_temp_dir do |path|
24+
g = Git.clone(@wbare, 'bare')
25+
assert_equal('scott Chacon', g.config('user.name'))
26+
g.config('user.name', 'bully')
27+
assert_equal('bully', g.config('user.name'))
28+
end
2429
end
2530

2631
end

tests/units/test_index.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/usr/bin/env ruby
2+
3+
require File.dirname(__FILE__) + '/../test_helper'
4+
5+
class TestIndex< Test::Unit::TestCase
6+
7+
def setup
8+
set_file_paths
9+
@git = Git.open(@wdir)
10+
end
11+
12+
def test_add
13+
in_temp_dir do |path|
14+
#puts path
15+
g = Git.clone(@wbare, 'new')
16+
Dir.chdir('new') do
17+
assert_equal('100644', g.status['example.txt'].mode_index)
18+
new_file('test-file', 'blahblahblah')
19+
assert(g.status.untracked.assoc('test-file'))
20+
g.add
21+
assert(g.status.added.assoc('test-file'))
22+
assert(!g.status.untracked.assoc('test-file'))
23+
assert(!g.status.changed.assoc('example.txt'))
24+
append_file('example.txt', 'hahahaha')
25+
assert(g.status.changed.assoc('example.txt'))
26+
g.add
27+
assert(g.status.changed.assoc('example.txt'))
28+
g.commit('my message')
29+
assert(!g.status.changed.assoc('example.txt'))
30+
assert(!g.status.added.assoc('test-file'))
31+
assert(!g.status.untracked.assoc('test-file'))
32+
end
33+
end
34+
end
35+
36+
def new_file(name, contents)
37+
File.open(name, 'w') do |f|
38+
f.puts contents
39+
end
40+
end
41+
42+
def append_file(name, contents)
43+
File.open(name, 'a') do |f|
44+
f.puts contents
45+
end
46+
end
47+
48+
end

tests/units/test_init.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def test_git_clone
5353
in_temp_dir do |path|
5454
g = Git.clone(@wbare, 'bare-co')
5555
assert(File.exists?(File.join(g.repo.path, 'config')))
56+
assert(g.dir)
5657
end
5758
end
5859

0 commit comments

Comments
 (0)