Skip to content

Commit da435b1

Browse files
committed
Document and add tests for Git::Status
1 parent c8a77db commit da435b1

File tree

5 files changed

+1369
-16
lines changed

5 files changed

+1369
-16
lines changed

README.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,8 @@
2323

2424
## Summary
2525

26-
The [git gem](https://rubygems.org/gems/git) provides an API that can be used to
27-
create, read, and manipulate Git repositories by wrapping system calls to the `git`
28-
command line. The API can be used for working with Git in complex interactions
29-
including branching and merging, object inspection and manipulation, history, patch
30-
generation and more.
26+
The [git gem](https://rubygems.org/gems/git) provides a Ruby interface to the `git`
27+
command line.
3128

3229
Get started by obtaining a repository object by:
3330

@@ -41,8 +38,7 @@ Methods that can be called on a repository object are documented in [Git::Base](
4138

4239
git 2.0.0 has recently been released. Please give it a try.
4340

44-
45-
**If you have problems with the 2.x release, open an issue and use the 1.9.1 version
41+
**If you have problems with the 2.x release, open an issue and use the 1.x version
4642
instead.** We will do our best to fix your issues in a timely fashion.
4743

4844
**JRuby on Windows is not yet supported by the 2.x release line. Users running JRuby

lib/git/status.rb

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
module Git
2+
# The status class gets the status of a git repository
23
#
3-
# A class for git status
4+
# This identifies which files have been modified, added, or deleted from the
5+
# worktree. Untracked files are also identified.
6+
#
7+
# The Status object is an Enumerable that contains StatusFile objects.
8+
#
9+
# @api public
410
#
511
class Status
612
include Enumerable
@@ -31,7 +37,6 @@ def changed?(file)
3137
changed.member?(file)
3238
end
3339

34-
#
3540
# Returns an Enumerable containing files that have been added.
3641
# File path starts at git base directory
3742
#
@@ -40,8 +45,8 @@ def added
4045
@files.select { |_k, f| f.type == 'A' }
4146
end
4247

43-
#
4448
# Determines whether the given file has been added to the repository
49+
#
4550
# File path starts at git base directory
4651
#
4752
# @param file [String] The name of the file.
@@ -126,9 +131,63 @@ def each(&block)
126131

127132
# subclass that does heavy lifting
128133
class StatusFile
129-
attr_accessor :path, :type, :stage, :untracked
130-
attr_accessor :mode_index, :mode_repo
131-
attr_accessor :sha_index, :sha_repo
134+
# @!attribute [r] path
135+
# The path of the file relative to the project root directory
136+
# @return [String]
137+
attr_accessor :path
138+
139+
# @!attribute [r] type
140+
# The type of change
141+
#
142+
# * 'M': modified
143+
# * 'A': added
144+
# * 'D': deleted
145+
# * nil: ???
146+
#
147+
# @return [String]
148+
attr_accessor :type
149+
150+
# @!attribute [r] mode_index
151+
# The mode of the file in the index
152+
# @return [String]
153+
# @example 100644
154+
#
155+
attr_accessor :mode_index
156+
157+
# @!attribute [r] mode_repo
158+
# The mode of the file in the repo
159+
# @return [String]
160+
# @example 100644
161+
#
162+
attr_accessor :mode_repo
163+
164+
# @!attribute [r] sha_index
165+
# The sha of the file in the index
166+
# @return [String]
167+
# @example 123456
168+
#
169+
attr_accessor :sha_index
170+
171+
# @!attribute [r] sha_repo
172+
# The sha of the file in the repo
173+
# @return [String]
174+
# @example 123456
175+
attr_accessor :sha_repo
176+
177+
# @!attribute [r] untracked
178+
# Whether the file is untracked
179+
# @return [Boolean]
180+
attr_accessor :untracked
181+
182+
# @!attribute [r] stage
183+
# The stage of the file
184+
#
185+
# * '0': the unmerged state
186+
# * '1': the common ancestor (or original) version
187+
# * '2': "our version" from the current branch head
188+
# * '3': "their version" from the other branch head
189+
# @return [String]
190+
attr_accessor :stage
132191

133192
def initialize(base, hash)
134193
@base = base
@@ -158,10 +217,19 @@ def blob(type = :index)
158217
private
159218

160219
def construct_status
220+
# Lists all files in the index and the worktree
221+
# git ls-files --stage
222+
# { file => { path: file, mode_index: '100644', sha_index: 'dd4fc23', stage: '0' } }
161223
@files = @base.lib.ls_files
162224

225+
# Lists files in the worktree that are not in the index
226+
# Add untracked files to @files
163227
fetch_untracked
228+
229+
# Lists files that are different between the index vs. the worktree
164230
fetch_modified
231+
232+
# Lists files that are different between the repo HEAD vs. the worktree
165233
fetch_added
166234

167235
@files.each do |k, file_hash|
@@ -170,22 +238,28 @@ def construct_status
170238
end
171239

172240
def fetch_untracked
241+
# git ls-files --others --exclude-standard, chdir: @git_work_dir)
242+
# { file => { path: file, untracked: true } }
173243
@base.lib.untracked_files.each do |file|
174244
@files[file] = { path: file, untracked: true }
175245
end
176246
end
177247

178248
def fetch_modified
179-
# find modified in tree
249+
# Files changed between the index vs. the worktree
250+
# git diff-files
251+
# { file => { path: file, type: 'M', mode_index: '100644', mode_repo: '100644', sha_index: '0000000', :sha_repo: '52c6c4e' } }
180252
@base.lib.diff_files.each do |path, data|
181253
@files[path] ? @files[path].merge!(data) : @files[path] = data
182254
end
183255
end
184256

185257
def fetch_added
186258
unless @base.lib.empty?
187-
# find added but not committed - new files
188-
@base.lib.diff_index('HEAD').each do |path, data|
259+
# Files changed between the repo HEAD vs. the worktree
260+
# git diff-index HEAD
261+
# { file => { path: file, type: 'M', mode_index: '100644', mode_repo: '100644', sha_index: '0000000', :sha_repo: '52c6c4e' } }
262+
@base.lib.diff_index('HEAD').each do |path, data|
189263
@files[path] ? @files[path].merge!(data) : @files[path] = data
190264
end
191265
end

tests/units/test_status.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,45 @@ def test_on_empty_repo
3535
end
3636
end
3737

38+
def test_added
39+
in_temp_dir do |path|
40+
`git init`
41+
File.write('file1', 'contents1')
42+
File.write('file2', 'contents2')
43+
`git add file1 file2`
44+
`git commit -m "my message"`
45+
46+
File.write('file2', 'contents2B')
47+
File.write('file3', 'contents3')
48+
49+
`git add file2 file3`
50+
51+
git = Git.open('.')
52+
status = assert_nothing_raised do
53+
git.status
54+
end
55+
56+
assert_equal(1, status.added.size)
57+
assert_equal(['file3'], status.added.keys)
58+
end
59+
end
60+
61+
def test_added_on_empty_repo
62+
in_temp_dir do |path|
63+
`git init`
64+
File.write('file1', 'contents1')
65+
File.write('file2', 'contents2')
66+
`git add file1 file2`
67+
68+
git = Git.open('.')
69+
status = assert_nothing_raised do
70+
git.status
71+
end
72+
73+
assert_equal(0, status.added.size)
74+
end
75+
end
76+
3877
def test_dot_files_status
3978
in_temp_dir do |path|
4079
git = Git.clone(@wdir, 'test_dot_files_status')

0 commit comments

Comments
 (0)