Skip to content

3ofcoins/minigit

Repository files navigation

Minigit

Minigit is a minimal Ruby interface for Git. It is a simple proxy that runs Git commands, and optionally captures output. It does not provide any abstraction provided by Grit or Git gems. It is just a simple wrapper over system('git ...') call. It also allows capturing output of Git commands.

Installation

Add this line to your application's Gemfile:

gem 'minigit'

And then execute:

$ bundle

Or install it yourself as:

$ gem install minigit

Usage

To use the library in your code, simply require it.

require 'minigit'

One-off Commands

You can run one-off commands simply by calling methods on the MiniGit class:

 MiniGit.branch # => nil (`git branch` output goes directly to terminal)

To capture output, use MiniGit::Capturing:

 MiniGit::Capturing.branch # => "* master\n"

Methods are translated directly into Git commands. Arguments are translated into command-line switches and arguments:

MiniGit.status                  # git status
MiniGit.status :s => true       # git status -s
MiniGit.status :short => true   # git status --short
MiniGit.log :n => 5             # git log -n 5
MiniGit.log({:n => 5}, 'path/'  # git log -n 5 path/
MiniGit.ls_tree :HEAD           # git ls-tree HEAD
MiniGit.something {:a => true}, 'foo', [1, {2 => 3}, 4], 'a_b', :c_d
  # Not useful, but shows how arguments are composed and interpreted:
  # git something -a foo 1 -2 3 4 a_b c-d

For scripted access or to run a Git subcommand with underscore character, use the git method:

MiniGit.git :foo_bar, :baz => true  # git foo-bar --baz
MiniGit.git 'foo_bar', :baz => true # git foo_bar --baz

The MiniGit class methods call out to Git without any particular parameters, it behaves as if you just called git in your current directory.

Instances

You can create instances of MiniGit and MiniGit::Capturing. If you don't provide any arguments, the instance will behave as if the class methods have been called - just run git in current directory. The methods are also the same. If you call a capturing method, you get instance of the MiniGit::Capturing class; if you call a noncapturing method, you get instance of MiniGit.

git = MiniGit.new
git.branch              # => nil (output shown to the terminal)
git.capturing.branch    # => "* master\n"
cgit = MiniGit::Capturing.new
cgit.branch              # => "* master\n"
cgit.noncapturing.branch # => nil (output shown to the terminal)

You can also provide a path specifying the Git repo. It can be:

  • a working directory
  • a file in or subdirectory of a working directory
  • a bare repository
  • a .git directory (which will be treated as a bare repository)

MiniGit will find the Git directory and work tree automagically by calling out to git rev-parse --git-dir --show-toplevel, will set git_dir and git_work_tree attributes, and add them as environment variables when calling Git to have the calls work with a specified repository. The git_dir and git_work_tree attributes are preserved over #capturing and #noncapturing calls.

MiniGit.log :n => 1, :oneline => true     # 47aac92 MiniGit.git method
MiniGit.new.log :n => 1, :oneline => true # 47aac92 MiniGit.git method
MiniGit.new('../vendorificator').log :n => 1, :oneline => true
    # b485d32 Merge branch 'release/0.1.1' into develop
MiniGit.new('../vendorificator').capturing.log :n => 1, :oneline => true
    # => "b485d32 Merge branch 'release/0.1.1' into develop\n"

Git config hash-like access

You can call, modify and create new git config attributes with simple hash-like syntax:

git = MiniGit.new
git['user.email'] # => returns the user email assigned to the repository
git['user.email'] = 'foo@bar' # changes the user.email to foo@bar

The same works on the class itself:

MiniGit['user.email'] # => "foo@bar"
MiniGit['user.email'] = 'foo@bar' # changes the user.email to foo@bar

Git command

By default, MiniGit just calls git. You can override the Git command on a couple levels:

  • Instance level (when instantiating and as an attribute) will override Git command for that instance, and instance it creates via #capturing / #noncapturing:
MiniGit.new(nil, :git_command => '/path/to/git')
MiniGit.new('/path/to/repo', :git_command => '/path/to/git')
git = MiniGit.new
git.git_command = '/path/to/git'
  • Class level - when set on subclass, will be used by this class methods of this subclass, and as a default for instances of this subclass.
class CustomGit < MiniGit
  self.git_command = '/path/to/git'
end  
CustomGit.git_command            # => "/path/to/git"
CustomGit.new.git_command        # => "/path/to/git"
CustomGit.new(nil, :git_command => '/other/git').git_command
                                 # => "/other/git"
MiniGit.new.git_command          # => "git"
MiniGit.git_command              # => "git"
MiniGit::Capturing.git_command   # => "git"
  • MiniGit level - Changing MiniGit.git_command will be used as a default for MiniGit itself, and for all its subclasses and subclass instances that don't override it.
MiniGit.git_command = '/yet/another/git' # => "/yet/another/git"
MiniGit.new.git_command                  # => "/yet/another/git"
MiniGit::Capturing.git_command           # => "/yet/another/git"
CustomGit.git_command                    # => "/path/to/git"
CustomGit.new.git_command                # => "/path/to/git"

Debugging

Set MiniGit.debug to true to see what MiniGit is doing:

MiniGit.debug = true
MiniGit.new('.').status
  # + [/Users/japhy/Projekty/minigit] git rev-parse --git-dir --show-toplevel # => ".git\n/Users/japhy/Projekty/minigit\n"
  # + git status

Issues

Non-capturing MiniGit doesn't always play well when Git is configured to use pager. You can disable it by setting GIT_PAGER environment variable to an empty string:

ENV['GIT_PAGER'] = ''

Contributing

See CONTRIBUTING.md