Skip to content

Fix issue #184 (Git status crashes on empty repo) #205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions lib/git/diff.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,20 +116,25 @@ def cache_stats

# break up @diff_full
def process_full_diff
defaults = {
:mode => '',
:src => '',
:dst => '',
:type => 'modified'
}
final = {}
current_file = nil
@full_diff.split("\n").each do |line|
if m = /diff --git a\/(.*?) b\/(.*?)/.match(line)
if m = /^diff --git a\/(.*?) b\/(.*?)/.match(line)
current_file = m[1]
final[current_file] = {:patch => line, :path => current_file,
:mode => '', :src => '', :dst => '', :type => 'modified'}
final[current_file] = defaults.merge({:patch => line, :path => current_file})
else
if m = /index (.......)\.\.(.......)( ......)*/.match(line)
if m = /^index (.......)\.\.(.......)( ......)*/.match(line)
final[current_file][:src] = m[1]
final[current_file][:dst] = m[2]
final[current_file][:mode] = m[3].strip if m[3]
end
if m = /(.*?) file mode (......)/.match(line)
if m = /^([[:alpha:]]*?) file mode (......)/.match(line)
final[current_file][:type] = m[1]
final[current_file][:mode] = m[2]
end
Expand Down
89 changes: 66 additions & 23 deletions lib/git/lib.rb
Original file line number Diff line number Diff line change
Expand Up @@ -699,8 +699,14 @@ def archive(sha, file = nil, opts = {})
opts[:add_gzip] = true
end

file ||= Tempfile.new('archive').path

if !file
tempfile = Tempfile.new('archive')
file = tempfile.path
# delete it now, before we write to it, so that Ruby doesn't delete it
# when it finalizes the Tempfile.
tempfile.close!
end

arr_opts = []
arr_opts << "--format=#{opts[:format]}" if opts[:format]
arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix]
Expand Down Expand Up @@ -728,40 +734,77 @@ def meets_required_version?


private

# Systen ENV variables involved in the git commands.
#
# @return [<String>] the names of the EVN variables involved in the git commands
ENV_VARIABLE_NAMES = ['GIT_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE']

def command_lines(cmd, opts = [], chdir = true, redirect = '')
command(cmd, opts, chdir).split("\n")
end

def command(cmd, opts = [], chdir = true, redirect = '', &block)
# Takes the current git's system ENV variables and store them.
def store_git_system_env_variables
@git_system_env_variables = {}
ENV_VARIABLE_NAMES.each do |env_variable_name|
@git_system_env_variables[env_variable_name] = ENV[env_variable_name]
end
end

# Takes the previously stored git's ENV variables and set them again on ENV.
def restore_git_system_env_variables
ENV_VARIABLE_NAMES.each do |env_variable_name|
ENV[env_variable_name] = @git_system_env_variables[env_variable_name]
end
end

# Sets git's ENV variables to the custom values for the current instance.
def set_custom_git_env_variables
ENV['GIT_DIR'] = @git_dir
ENV['GIT_WORK_TREE'] = @git_work_dir
ENV['GIT_INDEX_FILE'] = @git_index_file
end

path = @git_work_dir || @git_dir || @path

opts = [opts].flatten.map {|s| escape(s) }.join(' ')
# Runs a block inside an environment with customized ENV variables.
# It restores the ENV after execution.
#
# @param [Proc] block block to be executed within the customized environment
def with_custom_env_variables(&block)
store_git_system_env_variables()
set_custom_git_env_variables()
return block.call()
ensure
restore_git_system_env_variables()
end

git_cmd = "git #{cmd} #{opts} #{redirect} 2>&1"
def command(cmd, opts = [], chdir = true, redirect = '', &block)
with_custom_env_variables do
path = @git_work_dir || @git_dir || @path

opts = [opts].flatten.map {|s| escape(s) }.join(' ')

output = nil
git_cmd = "git #{cmd} #{opts} #{redirect} 2>&1"

if chdir && (Dir.getwd != path)
Dir.chdir(path) { output = run_command(git_cmd, &block) }
else
output = run_command(git_cmd, &block)
end

if @logger
@logger.info(git_cmd)
@logger.debug(output)
end

if $?.exitstatus > 1 || ($?.exitstatus == 1 && output != '')
raise Git::GitExecuteError.new(git_cmd + ':' + output.to_s)
end
output = nil

return output
if chdir && (Dir.getwd != path)
Dir.chdir(path) { output = run_command(git_cmd, &block) }
else
output = run_command(git_cmd, &block)
end

if @logger
@logger.info(git_cmd)
@logger.debug(output)
end

if $?.exitstatus > 1 || ($?.exitstatus == 1 && output != '')
raise Git::GitExecuteError.new(git_cmd + ':' + output.to_s)
end

return output
end
end

# Takes the diff command line output (as Array) and parse it into a Hash
Expand Down
2 changes: 1 addition & 1 deletion lib/git/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def gtree
end

def parent
parents.first
parents.first || self
end

# array of all parent commits
Expand Down
2 changes: 1 addition & 1 deletion lib/git/status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def construct_status
# find added but not committed - new files
@base.lib.diff_index('HEAD').each do |path, data|
@files[path] ? @files[path].merge!(data) : @files[path] = data
end
end unless ! File.exists?(@base.index.path)

@files.each do |k, file_hash|
@files[k] = StatusFile.new(@base, file_hash)
Expand Down
2 changes: 2 additions & 0 deletions tests/files/working/dot_git/logs/refs/heads/diff_over_patches
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
0000000000000000000000000000000000000000 6094405a5209406708ffe737077841b45c63fe25 Scott Chacon <schacon@gmail.com> 1417622944 -0300 push
6094405a5209406708ffe737077841b45c63fe25 1c04149973fb98fe8437fde044eb44cf5eb6ddda Scott Chacon <schacon@gmail.com> 1417623204 -0300 push
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
x��]j�0��S�V�+A(}�
=�j�N �e�=~ ��4��0��u�b>��
(,����$*�E�p�> fˤ��՚��n�0rt`"��� �r�5DI~V?ǽu�nU�h�����u��K�S�����E��6XJ�������qw��C�g�x,�vr�yy�y;Sa
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions tests/files/working/dot_git/refs/heads/diff_over_patches
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1c04149973fb98fe8437fde044eb44cf5eb6ddda
8 changes: 8 additions & 0 deletions tests/units/test_diff.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ def test_diff_tags
assert_equal(64, d.insertions)
end

# Patch files on diff outputs used to be parsed as
# part of the diff adding invalid modificaction
# to the diff results.
def test_diff_patch
d = @git.diff('diff_over_patches~2', 'diff_over_patches')
assert_equal(1, d.count)
end

def test_diff_path
d = @git.diff('gitsearch1', 'v2.5').path('scott/')
assert_equal(d.from, 'gitsearch1')
Expand Down
12 changes: 12 additions & 0 deletions tests/units/test_lib.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ def test_log_commits
assert_equal(20, a.size)
end

def test_environment_reset
ENV['GIT_DIR'] = '/my/git/dir'
ENV['GIT_WORK_TREE'] = '/my/work/tree'
ENV['GIT_INDEX_FILE'] = 'my_index'

@lib.log_commits :count => 10

assert_equal(ENV['GIT_DIR'], '/my/git/dir')
assert_equal(ENV['GIT_WORK_TREE'], '/my/work/tree')
assert_equal(ENV['GIT_INDEX_FILE'],'my_index')
end

def test_revparse
assert_equal('1cc8667014381e2788a94777532a788307f38d26', @lib.revparse('1cc8667014381')) # commit
assert_equal('94c827875e2cadb8bc8d4cdd900f19aa9e8634c7', @lib.revparse('1cc8667014381^{tree}')) #tree
Expand Down
4 changes: 2 additions & 2 deletions tests/units/test_logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_logger

logc = File.read(log.path)
assert(/INFO -- : git branch '-a'/.match(logc))
assert(/DEBUG -- : \* git_grep/.match(logc))
assert(/DEBUG -- : diff_over_patches/.match(logc))

log = Tempfile.new('logfile')
log.close
Expand All @@ -32,7 +32,7 @@ def test_logger

logc = File.read(log.path)
assert(/INFO -- : git branch '-a'/.match(logc))
assert(!/DEBUG -- : \* git_grep/.match(logc))
assert(!/DEBUG -- : diff_over_patches/.match(logc))
end

end
3 changes: 3 additions & 0 deletions tests/units/test_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ def test_commit
o = @git.gcommit('test_object')
assert(o.is_a?(Git::Object::Commit))
assert(o.commit?)

o = @git.gcommit('545ffc79786f268524c35e1e05b1770c7c74faf1')
assert('545ffc79786f268524c35e1e05b1770c7c74faf1', o.parent.sha)
end

def test_commit_contents
Expand Down
7 changes: 7 additions & 0 deletions tests/units/test_status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,11 @@ def test_dot_files_status
end
end

def test_empty_repo_status
in_temp_dir do |path|
git = Git.init('empty_repo')
assert git.status
end
end

end