class Git::Status

The Status class gets the status of a git repository. It identifies which files have been modified, added, or deleted, including untracked files. The Status object is an Enumerable of StatusFile objects.

@api public

Public Class Methods

new(base) click to toggle source

@param base [Git::Base] The base git object

# File lib/git/status.rb, line 16
def initialize(base)
  @base = base
  # The factory returns a hash of file paths to StatusFile objects.
  @files = StatusFileFactory.new(base).construct_files
end

Public Instance Methods

[](file) click to toggle source

Access a status file by path, or iterate over all status files.

# File lib/git/status.rb, line 36
    def [](file) = @files[file]
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
end
added(= @added ||= select_files { |f| f.type == 'A' }) click to toggle source
# File lib/git/status.rb, line 24
    def added     = @added ||= select_files { |f| f.type == 'A' }
    def deleted   = @deleted ||= select_files { |f| f.type == 'D' }
    # This works with `true` or `nil`
    def untracked = @untracked ||= select_files(&:untracked)

    # Predicate methods to check the status of a specific file.
    def changed?(file)   = file_in_collection?(:changed, file)
    def added?(file)     = file_in_collection?(:added, file)
    def deleted?(file)   = file_in_collection?(:deleted, file)
    def untracked?(file) = file_in_collection?(:untracked, file)

    # Access a status file by path, or iterate over all status files.
    def [](file) = @files[file]
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
end

module Git
  class Status
    # Represents a single file's status in the git repository. Each instance
    # holds information about a file's state in the index and working tree.
    class StatusFile
      attr_reader :path, :type, :stage, :mode_index, :mode_repo,
                  :sha_index, :sha_repo, :untracked

      def initialize(base, hash)
        @base       = base
        @path       = hash[:path]
        @type       = hash[:type]
        @stage      = hash[:stage]
        @mode_index = hash[:mode_index]
        @mode_repo  = hash[:mode_repo]
        @sha_index  = hash[:sha_index]
        @sha_repo   = hash[:sha_repo]
        @untracked  = hash[:untracked]
      end

      # Returns a Git::Object::Blob for either the index or repo version of the file.
      def blob(type = :index)
        sha = type == :repo ? sha_repo : (sha_index || sha_repo)
        @base.object(sha) if sha
      end
    end
  end
end

module Git
  class Status
    # A factory class responsible for fetching git status data and building
    # a hash of StatusFile objects.
    # @api private
    class StatusFileFactory
      def initialize(base)
        @base = base
        @lib = base.lib
      end

      # Gathers all status data and builds a hash of file paths to
      # StatusFile objects.
      def construct_files
        files_data = fetch_all_files_data
        files_data.transform_values do |data|
          StatusFile.new(@base, data)
        end
      end

      private

      # Fetches and merges status information from multiple git commands.
      def fetch_all_files_data
        files = @lib.ls_files # Start with files tracked in the index.
        merge_untracked_files(files)
        merge_modified_files(files)
        merge_head_diffs(files)
        files
      end

      def merge_untracked_files(files)
        @lib.untracked_files.each do |file|
          files[file] = { path: file, untracked: true }
        end
      end

      def merge_modified_files(files)
        # Merge changes between the index and the working directory.
        @lib.diff_files.each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end

      def merge_head_diffs(files)
        return if @lib.empty?

        # Merge changes between HEAD and the index.
        @lib.diff_index('HEAD').each do |path, data|
          (files[path] ||= {}).merge!(data)
added?(file) click to toggle source
# File lib/git/status.rb, line 31
    def added?(file)     = file_in_collection?(:added, file)
    def deleted?(file)   = file_in_collection?(:deleted, file)
    def untracked?(file) = file_in_collection?(:untracked, file)

    # Access a status file by path, or iterate over all status files.
    def [](file) = @files[file]
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
end

module Git
  class Status
    # Represents a single file's status in the git repository. Each instance
    # holds information about a file's state in the index and working tree.
    class StatusFile
      attr_reader :path, :type, :stage, :mode_index, :mode_repo,
                  :sha_index, :sha_repo, :untracked

      def initialize(base, hash)
        @base       = base
        @path       = hash[:path]
        @type       = hash[:type]
        @stage      = hash[:stage]
        @mode_index = hash[:mode_index]
        @mode_repo  = hash[:mode_repo]
        @sha_index  = hash[:sha_index]
        @sha_repo   = hash[:sha_repo]
        @untracked  = hash[:untracked]
      end

      # Returns a Git::Object::Blob for either the index or repo version of the file.
      def blob(type = :index)
        sha = type == :repo ? sha_repo : (sha_index || sha_repo)
        @base.object(sha) if sha
      end
    end
  end
end

module Git
  class Status
    # A factory class responsible for fetching git status data and building
    # a hash of StatusFile objects.
    # @api private
    class StatusFileFactory
      def initialize(base)
        @base = base
        @lib = base.lib
      end

      # Gathers all status data and builds a hash of file paths to
      # StatusFile objects.
      def construct_files
        files_data = fetch_all_files_data
        files_data.transform_values do |data|
          StatusFile.new(@base, data)
        end
      end

      private

      # Fetches and merges status information from multiple git commands.
      def fetch_all_files_data
        files = @lib.ls_files # Start with files tracked in the index.
        merge_untracked_files(files)
        merge_modified_files(files)
        merge_head_diffs(files)
        files
      end

      def merge_untracked_files(files)
        @lib.untracked_files.each do |file|
          files[file] = { path: file, untracked: true }
        end
      end

      def merge_modified_files(files)
        # Merge changes between the index and the working directory.
        @lib.diff_files.each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end

      def merge_head_diffs(files)
        return if @lib.empty?

        # Merge changes between HEAD and the index.
        @lib.diff_index('HEAD').each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end
    
changed(= @changed ||= select_files { |f| f.type == 'M' }) click to toggle source

File status collections, memoized for performance.

# File lib/git/status.rb, line 23
    def changed   = @changed ||= select_files { |f| f.type == 'M' }
    def added     = @added ||= select_files { |f| f.type == 'A' }
    def deleted   = @deleted ||= select_files { |f| f.type == 'D' }
    # This works with `true` or `nil`
    def untracked = @untracked ||= select_files(&:untracked)

    # Predicate methods to check the status of a specific file.
    def changed?(file)   = file_in_collection?(:changed, file)
    def added?(file)     = file_in_collection?(:added, file)
    def deleted?(file)   = file_in_collection?(:deleted, file)
    def untracked?(file) = file_in_collection?(:untracked, file)

    # Access a status file by path, or iterate over all status files.
    def [](file) = @files[file]
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
end

module Git
  class Status
    # Represents a single file's status in the git repository. Each instance
    # holds information about a file's state in the index and working tree.
    class StatusFile
      attr_reader :path, :type, :stage, :mode_index, :mode_repo,
                  :sha_index, :sha_repo, :untracked

      def initialize(base, hash)
        @base       = base
        @path       = hash[:path]
        @type       = hash[:type]
        @stage      = hash[:stage]
        @mode_index = hash[:mode_index]
        @mode_repo  = hash[:mode_repo]
        @sha_index  = hash[:sha_index]
        @sha_repo   = hash[:sha_repo]
        @untracked  = hash[:untracked]
      end

      # Returns a Git::Object::Blob for either the index or repo version of the file.
      def blob(type = :index)
        sha = type == :repo ? sha_repo : (sha_index || sha_repo)
        @base.object(sha) if sha
      end
    end
  end
end

module Git
  class Status
    # A factory class responsible for fetching git status data and building
    # a hash of StatusFile objects.
    # @api private
    class StatusFileFactory
      def initialize(base)
        @base = base
        @lib = base.lib
      end

      # Gathers all status data and builds a hash of file paths to
      # StatusFile objects.
      def construct_files
        files_data = fetch_all_files_data
        files_data.transform_values do |data|
          StatusFile.new(@base, data)
        end
      end

      private

      # Fetches and merges status information from multiple git commands.
      def fetch_all_files_data
        files = @lib.ls_files # Start with files tracked in the index.
        merge_untracked_files(files)
        merge_modified_files(files)
        merge_head_diffs(files)
        files
      end

      def merge_untracked_files(files)
        @lib.untracked_files.each do |file|
          files[file] = { path: file, untracked: true }
        end
      end

      def merge_modified_files(files)
        # Merge changes between the index and the working directory.
        @lib.diff_files.each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end

      def merge_head_diffs(files)
        return if @lib.empty?

        # Merge changes between HEAD and the index.
        @lib.diff_index('HEAD').each do |path, data|
          (files[path] ||= {}).merge!(
changed?(file) click to toggle source

Predicate methods to check the status of a specific file.

# File lib/git/status.rb, line 30
    def changed?(file)   = file_in_collection?(:changed, file)
    def added?(file)     = file_in_collection?(:added, file)
    def deleted?(file)   = file_in_collection?(:deleted, file)
    def untracked?(file) = file_in_collection?(:untracked, file)

    # Access a status file by path, or iterate over all status files.
    def [](file) = @files[file]
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
end

module Git
  class Status
    # Represents a single file's status in the git repository. Each instance
    # holds information about a file's state in the index and working tree.
    class StatusFile
      attr_reader :path, :type, :stage, :mode_index, :mode_repo,
                  :sha_index, :sha_repo, :untracked

      def initialize(base, hash)
        @base       = base
        @path       = hash[:path]
        @type       = hash[:type]
        @stage      = hash[:stage]
        @mode_index = hash[:mode_index]
        @mode_repo  = hash[:mode_repo]
        @sha_index  = hash[:sha_index]
        @sha_repo   = hash[:sha_repo]
        @untracked  = hash[:untracked]
      end

      # Returns a Git::Object::Blob for either the index or repo version of the file.
      def blob(type = :index)
        sha = type == :repo ? sha_repo : (sha_index || sha_repo)
        @base.object(sha) if sha
      end
    end
  end
end

module Git
  class Status
    # A factory class responsible for fetching git status data and building
    # a hash of StatusFile objects.
    # @api private
    class StatusFileFactory
      def initialize(base)
        @base = base
        @lib = base.lib
      end

      # Gathers all status data and builds a hash of file paths to
      # StatusFile objects.
      def construct_files
        files_data = fetch_all_files_data
        files_data.transform_values do |data|
          StatusFile.new(@base, data)
        end
      end

      private

      # Fetches and merges status information from multiple git commands.
      def fetch_all_files_data
        files = @lib.ls_files # Start with files tracked in the index.
        merge_untracked_files(files)
        merge_modified_files(files)
        merge_head_diffs(files)
        files
      end

      def merge_untracked_files(files)
        @lib.untracked_files.each do |file|
          files[file] = { path: file, untracked: true }
        end
      end

      def merge_modified_files(files)
        # Merge changes between the index and the working directory.
        @lib.diff_files.each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end

      def merge_head_diffs(files)
        return if @lib.empty?

        # Merge changes between HEAD and the index.
        @lib.diff_index('HEAD').each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end
deleted(= @deleted ||= select_files { |f| f.type == 'D' }) click to toggle source
# File lib/git/status.rb, line 25
    def deleted   = @deleted ||= select_files { |f| f.type == 'D' }
    # This works with `true` or `nil`
    def untracked = @untracked ||= select_files(&:untracked)

    # Predicate methods to check the status of a specific file.
    def changed?(file)   = file_in_collection?(:changed, file)
    def added?(file)     = file_in_collection?(:added, file)
    def deleted?(file)   = file_in_collection?(:deleted, file)
    def untracked?(file) = file_in_collection?(:untracked, file)

    # Access a status file by path, or iterate over all status files.
    def [](file) = @files[file]
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
end

module Git
  class Status
    # Represents a single file's status in the git repository. Each instance
    # holds information about a file's state in the index and working tree.
    class StatusFile
      attr_reader :path, :type, :stage, :mode_index, :mode_repo,
                  :sha_index, :sha_repo, :untracked

      def initialize(base, hash)
        @base       = base
        @path       = hash[:path]
        @type       = hash[:type]
        @stage      = hash[:stage]
        @mode_index = hash[:mode_index]
        @mode_repo  = hash[:mode_repo]
        @sha_index  = hash[:sha_index]
        @sha_repo   = hash[:sha_repo]
        @untracked  = hash[:untracked]
      end

      # Returns a Git::Object::Blob for either the index or repo version of the file.
      def blob(type = :index)
        sha = type == :repo ? sha_repo : (sha_index || sha_repo)
        @base.object(sha) if sha
      end
    end
  end
end

module Git
  class Status
    # A factory class responsible for fetching git status data and building
    # a hash of StatusFile objects.
    # @api private
    class StatusFileFactory
      def initialize(base)
        @base = base
        @lib = base.lib
      end

      # Gathers all status data and builds a hash of file paths to
      # StatusFile objects.
      def construct_files
        files_data = fetch_all_files_data
        files_data.transform_values do |data|
          StatusFile.new(@base, data)
        end
      end

      private

      # Fetches and merges status information from multiple git commands.
      def fetch_all_files_data
        files = @lib.ls_files # Start with files tracked in the index.
        merge_untracked_files(files)
        merge_modified_files(files)
        merge_head_diffs(files)
        files
      end

      def merge_untracked_files(files)
        @lib.untracked_files.each do |file|
          files[file] = { path: file, untracked: true }
        end
      end

      def merge_modified_files(files)
        # Merge changes between the index and the working directory.
        @lib.diff_files.each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end

      def merge_head_diffs(files)
        return if @lib.empty?

        # Merge changes between HEAD and the index.
        @lib.diff_index('HEAD').each do |path, data|
          (files[path] ||= {}).merge!(data)
        
deleted?(file) click to toggle source
# File lib/git/status.rb, line 32
    def deleted?(file)   = file_in_collection?(:deleted, file)
    def untracked?(file) = file_in_collection?(:untracked, file)

    # Access a status file by path, or iterate over all status files.
    def [](file) = @files[file]
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
end

module Git
  class Status
    # Represents a single file's status in the git repository. Each instance
    # holds information about a file's state in the index and working tree.
    class StatusFile
      attr_reader :path, :type, :stage, :mode_index, :mode_repo,
                  :sha_index, :sha_repo, :untracked

      def initialize(base, hash)
        @base       = base
        @path       = hash[:path]
        @type       = hash[:type]
        @stage      = hash[:stage]
        @mode_index = hash[:mode_index]
        @mode_repo  = hash[:mode_repo]
        @sha_index  = hash[:sha_index]
        @sha_repo   = hash[:sha_repo]
        @untracked  = hash[:untracked]
      end

      # Returns a Git::Object::Blob for either the index or repo version of the file.
      def blob(type = :index)
        sha = type == :repo ? sha_repo : (sha_index || sha_repo)
        @base.object(sha) if sha
      end
    end
  end
end

module Git
  class Status
    # A factory class responsible for fetching git status data and building
    # a hash of StatusFile objects.
    # @api private
    class StatusFileFactory
      def initialize(base)
        @base = base
        @lib = base.lib
      end

      # Gathers all status data and builds a hash of file paths to
      # StatusFile objects.
      def construct_files
        files_data = fetch_all_files_data
        files_data.transform_values do |data|
          StatusFile.new(@base, data)
        end
      end

      private

      # Fetches and merges status information from multiple git commands.
      def fetch_all_files_data
        files = @lib.ls_files # Start with files tracked in the index.
        merge_untracked_files(files)
        merge_modified_files(files)
        merge_head_diffs(files)
        files
      end

      def merge_untracked_files(files)
        @lib.untracked_files.each do |file|
          files[file] = { path: file, untracked: true }
        end
      end

      def merge_modified_files(files)
        # Merge changes between the index and the working directory.
        @lib.diff_files.each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end

      def merge_head_diffs(files)
        return if @lib.empty?

        # Merge changes between HEAD and the index.
        @lib.diff_index('HEAD').each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end
    end
downcased_keys(collection_name) click to toggle source
# File lib/git/status.rb, line 70
def downcased_keys(collection_name)
  @_downcased_keys ||= {}
  @_downcased_keys[collection_name] ||=
    public_send(collection_name).keys.to_set(&:downcase)
end
each(&) click to toggle source
# File lib/git/status.rb, line 37
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
file_in_collection?(collection_name, file_path) click to toggle source
# File lib/git/status.rb, line 61
def file_in_collection?(collection_name, file_path)
  collection = public_send(collection_name)
  if ignore_case?
    downcased_keys(collection_name).include?(file_path.downcase)
  else
    collection.key?(file_path)
  end
end
ignore_case?() click to toggle source
# File lib/git/status.rb, line 76
def ignore_case?
  return @_ignore_case if defined?(@_ignore_case)

  @_ignore_case = (@base.config('core.ignoreCase') == 'true')
rescue Git::FailedError
  @_ignore_case = false
end
pretty() click to toggle source

Returns a formatted string representation of the status.

# File lib/git/status.rb, line 40
def pretty
  map { |file| pretty_file(file) }.join << "\n"
end
pretty_file(file) click to toggle source
# File lib/git/status.rb, line 46
    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end
select_files(&block) click to toggle source
# File lib/git/status.rb, line 57
def select_files(&block)
  @files.select { |_path, file| block.call(file) }
end
untracked(= @untracked ||= select_files(&:untracked)) click to toggle source

This works with ‘true` or `nil`

# File lib/git/status.rb, line 27
    def untracked = @untracked ||= select_files(&:untracked)

    # Predicate methods to check the status of a specific file.
    def changed?(file)   = file_in_collection?(:changed, file)
    def added?(file)     = file_in_collection?(:added, file)
    def deleted?(file)   = file_in_collection?(:deleted, file)
    def untracked?(file) = file_in_collection?(:untracked, file)

    # Access a status file by path, or iterate over all status files.
    def [](file) = @files[file]
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
end

module Git
  class Status
    # Represents a single file's status in the git repository. Each instance
    # holds information about a file's state in the index and working tree.
    class StatusFile
      attr_reader :path, :type, :stage, :mode_index, :mode_repo,
                  :sha_index, :sha_repo, :untracked

      def initialize(base, hash)
        @base       = base
        @path       = hash[:path]
        @type       = hash[:type]
        @stage      = hash[:stage]
        @mode_index = hash[:mode_index]
        @mode_repo  = hash[:mode_repo]
        @sha_index  = hash[:sha_index]
        @sha_repo   = hash[:sha_repo]
        @untracked  = hash[:untracked]
      end

      # Returns a Git::Object::Blob for either the index or repo version of the file.
      def blob(type = :index)
        sha = type == :repo ? sha_repo : (sha_index || sha_repo)
        @base.object(sha) if sha
      end
    end
  end
end

module Git
  class Status
    # A factory class responsible for fetching git status data and building
    # a hash of StatusFile objects.
    # @api private
    class StatusFileFactory
      def initialize(base)
        @base = base
        @lib = base.lib
      end

      # Gathers all status data and builds a hash of file paths to
      # StatusFile objects.
      def construct_files
        files_data = fetch_all_files_data
        files_data.transform_values do |data|
          StatusFile.new(@base, data)
        end
      end

      private

      # Fetches and merges status information from multiple git commands.
      def fetch_all_files_data
        files = @lib.ls_files # Start with files tracked in the index.
        merge_untracked_files(files)
        merge_modified_files(files)
        merge_head_diffs(files)
        files
      end

      def merge_untracked_files(files)
        @lib.untracked_files.each do |file|
          files[file] = { path: file, untracked: true }
        end
      end

      def merge_modified_files(files)
        # Merge changes between the index and the working directory.
        @lib.diff_files.each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end

      def merge_head_diffs(files)
        return if @lib.empty?

        # Merge changes between HEAD and the index.
        @lib.diff_index('HEAD').each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
untracked?(file) click to toggle source
# File lib/git/status.rb, line 33
    def untracked?(file) = file_in_collection?(:untracked, file)

    # Access a status file by path, or iterate over all status files.
    def [](file) = @files[file]
    def each(&) = @files.values.each(&)

    # Returns a formatted string representation of the status.
    def pretty
      map { |file| pretty_file(file) }.join << "\n"
    end

    private

    def pretty_file(file)
      <<~FILE
        #{file.path}
        \tsha(r) #{file.sha_repo} #{file.mode_repo}
        \tsha(i) #{file.sha_index} #{file.mode_index}
        \ttype   #{file.type}
        \tstage  #{file.stage}
        \tuntrac #{file.untracked}
      FILE
    end

    def select_files(&block)
      @files.select { |_path, file| block.call(file) }
    end

    def file_in_collection?(collection_name, file_path)
      collection = public_send(collection_name)
      if ignore_case?
        downcased_keys(collection_name).include?(file_path.downcase)
      else
        collection.key?(file_path)
      end
    end

    def downcased_keys(collection_name)
      @_downcased_keys ||= {}
      @_downcased_keys[collection_name] ||=
        public_send(collection_name).keys.to_set(&:downcase)
    end

    def ignore_case?
      return @_ignore_case if defined?(@_ignore_case)

      @_ignore_case = (@base.config('core.ignoreCase') == 'true')
    rescue Git::FailedError
      @_ignore_case = false
    end
  end
end

module Git
  class Status
    # Represents a single file's status in the git repository. Each instance
    # holds information about a file's state in the index and working tree.
    class StatusFile
      attr_reader :path, :type, :stage, :mode_index, :mode_repo,
                  :sha_index, :sha_repo, :untracked

      def initialize(base, hash)
        @base       = base
        @path       = hash[:path]
        @type       = hash[:type]
        @stage      = hash[:stage]
        @mode_index = hash[:mode_index]
        @mode_repo  = hash[:mode_repo]
        @sha_index  = hash[:sha_index]
        @sha_repo   = hash[:sha_repo]
        @untracked  = hash[:untracked]
      end

      # Returns a Git::Object::Blob for either the index or repo version of the file.
      def blob(type = :index)
        sha = type == :repo ? sha_repo : (sha_index || sha_repo)
        @base.object(sha) if sha
      end
    end
  end
end

module Git
  class Status
    # A factory class responsible for fetching git status data and building
    # a hash of StatusFile objects.
    # @api private
    class StatusFileFactory
      def initialize(base)
        @base = base
        @lib = base.lib
      end

      # Gathers all status data and builds a hash of file paths to
      # StatusFile objects.
      def construct_files
        files_data = fetch_all_files_data
        files_data.transform_values do |data|
          StatusFile.new(@base, data)
        end
      end

      private

      # Fetches and merges status information from multiple git commands.
      def fetch_all_files_data
        files = @lib.ls_files # Start with files tracked in the index.
        merge_untracked_files(files)
        merge_modified_files(files)
        merge_head_diffs(files)
        files
      end

      def merge_untracked_files(files)
        @lib.untracked_files.each do |file|
          files[file] = { path: file, untracked: true }
        end
      end

      def merge_modified_files(files)
        # Merge changes between the index and the working directory.
        @lib.diff_files.each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end

      def merge_head_diffs(files)
        return if @lib.empty?

        # Merge changes between HEAD and the index.
        @lib.diff_index('HEAD').each do |path, data|
          (files[path] ||= {}).merge!(data)
        end
      end
    end
  end