diff --git a/lib/git/diff.rb b/lib/git/diff.rb index 52189ea8..c2d2ac3c 100644 --- a/lib/git/diff.rb +++ b/lib/git/diff.rb @@ -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 diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 03b19995..3843262a 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -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] @@ -728,40 +734,77 @@ def meets_required_version? private + + # Systen ENV variables involved in the git commands. + # + # @return [] 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 diff --git a/lib/git/object.rb b/lib/git/object.rb index 75427d90..538a671e 100644 --- a/lib/git/object.rb +++ b/lib/git/object.rb @@ -182,7 +182,7 @@ def gtree end def parent - parents.first + parents.first || self end # array of all parent commits diff --git a/lib/git/status.rb b/lib/git/status.rb index d59bc777..905a4ec4 100644 --- a/lib/git/status.rb +++ b/lib/git/status.rb @@ -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) diff --git a/tests/files/working/dot_git/logs/refs/heads/diff_over_patches b/tests/files/working/dot_git/logs/refs/heads/diff_over_patches new file mode 100644 index 00000000..995061b3 --- /dev/null +++ b/tests/files/working/dot_git/logs/refs/heads/diff_over_patches @@ -0,0 +1,2 @@ +0000000000000000000000000000000000000000 6094405a5209406708ffe737077841b45c63fe25 Scott Chacon 1417622944 -0300 push +6094405a5209406708ffe737077841b45c63fe25 1c04149973fb98fe8437fde044eb44cf5eb6ddda Scott Chacon 1417623204 -0300 push diff --git a/tests/files/working/dot_git/objects/0c/ac9b660896797e9cc9abb36c081a7ec0d1a7b1 b/tests/files/working/dot_git/objects/0c/ac9b660896797e9cc9abb36c081a7ec0d1a7b1 new file mode 100644 index 00000000..c3e29f51 Binary files /dev/null and b/tests/files/working/dot_git/objects/0c/ac9b660896797e9cc9abb36c081a7ec0d1a7b1 differ diff --git a/tests/files/working/dot_git/objects/1c/04149973fb98fe8437fde044eb44cf5eb6ddda b/tests/files/working/dot_git/objects/1c/04149973fb98fe8437fde044eb44cf5eb6ddda new file mode 100644 index 00000000..cf935291 --- /dev/null +++ b/tests/files/working/dot_git/objects/1c/04149973fb98fe8437fde044eb44cf5eb6ddda @@ -0,0 +1,3 @@ +x]j0SV+A(} +=jN e=~ 40ub> +(,$*Ep> fˤ՚n0rt`" r5DI~V ?ǽunUhuKSE6XJqwCgx, vryyy;Sa \ No newline at end of file diff --git a/tests/files/working/dot_git/objects/60/94405a5209406708ffe737077841b45c63fe25 b/tests/files/working/dot_git/objects/60/94405a5209406708ffe737077841b45c63fe25 new file mode 100644 index 00000000..3d54f700 Binary files /dev/null and b/tests/files/working/dot_git/objects/60/94405a5209406708ffe737077841b45c63fe25 differ diff --git a/tests/files/working/dot_git/objects/8e/33476f852fffb06e22b244c0f97093588567ee b/tests/files/working/dot_git/objects/8e/33476f852fffb06e22b244c0f97093588567ee new file mode 100644 index 00000000..9ed315c2 Binary files /dev/null and b/tests/files/working/dot_git/objects/8e/33476f852fffb06e22b244c0f97093588567ee differ diff --git a/tests/files/working/dot_git/objects/b9/84607a41cc1f5c512a49213404b1b4cf8df4a6 b/tests/files/working/dot_git/objects/b9/84607a41cc1f5c512a49213404b1b4cf8df4a6 new file mode 100644 index 00000000..df722db7 Binary files /dev/null and b/tests/files/working/dot_git/objects/b9/84607a41cc1f5c512a49213404b1b4cf8df4a6 differ diff --git a/tests/files/working/dot_git/objects/d6/46165a1e3a89399f72c1ffc1fcd76814c5ce1d b/tests/files/working/dot_git/objects/d6/46165a1e3a89399f72c1ffc1fcd76814c5ce1d new file mode 100644 index 00000000..a1040204 Binary files /dev/null and b/tests/files/working/dot_git/objects/d6/46165a1e3a89399f72c1ffc1fcd76814c5ce1d differ diff --git a/tests/files/working/dot_git/refs/heads/diff_over_patches b/tests/files/working/dot_git/refs/heads/diff_over_patches new file mode 100644 index 00000000..04bdcb97 --- /dev/null +++ b/tests/files/working/dot_git/refs/heads/diff_over_patches @@ -0,0 +1 @@ +1c04149973fb98fe8437fde044eb44cf5eb6ddda diff --git a/tests/units/test_diff.rb b/tests/units/test_diff.rb index 0c77769f..ef2cefa4 100644 --- a/tests/units/test_diff.rb +++ b/tests/units/test_diff.rb @@ -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') diff --git a/tests/units/test_lib.rb b/tests/units/test_lib.rb index ee538e6d..4a981785 100644 --- a/tests/units/test_lib.rb +++ b/tests/units/test_lib.rb @@ -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 diff --git a/tests/units/test_logger.rb b/tests/units/test_logger.rb index 6e4179b9..72f2d505 100644 --- a/tests/units/test_logger.rb +++ b/tests/units/test_logger.rb @@ -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 @@ -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 diff --git a/tests/units/test_object.rb b/tests/units/test_object.rb index c115355c..3818e76b 100644 --- a/tests/units/test_object.rb +++ b/tests/units/test_object.rb @@ -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 diff --git a/tests/units/test_status.rb b/tests/units/test_status.rb index 6479b628..b9914b60 100644 --- a/tests/units/test_status.rb +++ b/tests/units/test_status.rb @@ -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