I guess we’ve all heard last week’s sad news about Engine Yard diminishing the awesome support they’ve given the Rubinius project. That’s personally how I see it: they’ve put the project on steroids for roughly a year, rather than “they’re now cutting back” x people.

As Brian Ford pointed out, Rubinius is a community project. And Rubinius is not going away. A lot of people can’t wait to have a Ruby written more in Ruby than in C or C++. Koichi Sasada (lead developer on Ruby 1.9) even recently projected that Rubinius would eventually be the Ruby implementation of choice.

Rubinius’ future is promising. I’d like to go from that positive note, and have YOU try Rubinius now. I promise that in 20 minutes, you’ll be running Rubinius and enjoying it. The longest parts of the process will be waiting (cloning, compiling), so it won’t even be difficult. Note: the article may look long, but it’s not. Half of it is code samples and the results returned.

So it’s been aeons since the last article of the RFTL series. But yes, this article is part of a series. You can look at the first 2 parts if you want. Some details1 won’t be up to date anymore, but it’ll help you get the gist of Rubinius if you’re not familiar with the project yet.

The 20 minutes timer starts now, for those who went ahead and read the past articles.

Install Rubinius

Prerequisites

Prerequisites are probably already taken care of on most Ruby developers’ machines:

  • ruby 1.8, rubygems, rake and ParseTree (sudo gem install rake ParseTree)
  • git (no need to understand it, really, just having it installed)
  • general C++ building tools

Dependencies for Mac users

Leopard users should have all they need when Xcode is installed. Insert your Leopard upgrade DVD and from your terminal:

open /Volumes/Mac\ OS\ X\ Upgrade\ DVD/Optional\ Installs/Xcode\ Tools/XcodeTools.mpkg 

Dependencies for Linux users

Linux users have to make sure the following packages are installed. Use your the equivalent command for your distro:

sudo apt-get install gcc bison make pkg-config libtool git

(where make == GNU make)

Get the Rubinius code

Right now the GitHub feature to download a tarball is disabled for big projects like Rubinius. They say the feature on the radar as one of the things to fix in the next few weeks. Which will be awesome.

For now we have have to clone the repo, which in this case takes a few minutes. Find yourself a comfortable directory and:

git clone git://github.com/evanphx/rubinius.git
# go make coffee
cd rubinius

Build Rubinius

Assuming you’ve installed all the dependencies, the following should work right off the bat. If it’s not the case, check out the notes on the subject.

rake build
# go get a http://www.brawndo.com/

Later, when you want to recompile from a clean slate, just run rake distclean.

If you have not gotten a BRAWNDO, please skip over the next paragraph.

RUBINIUS, like BRAWNDO, is one of the CRAZIEST ideas of the LAST DECADE! Can you realize you’re ABOUT to try the Ruby IMPLEMENTATION that’s got the BEST Ruby code ratio AMONG THEM ALL! Isn’t that FREAKING AWESOME? You can also do some of the CRAZIEST INTROSPECTION with MethodContext, StaticScope and other classes like THAT!

Run Rubinius

The Rubinius executable is rbx in the ‘bin’ subdirectory. It’s a bit different from MRI in that rbx starts an irb session if you don’t specify a file to run. So let’s do that:

bin/rbx
# in irb
puts "Don't you spring a hello world on me"
#=> Don't you spring a hello world on me

Ok then. Well, technically you’ve now tried Rubinius in less than 20 minutes. Now if you keep reading, you’ll really taste some true Rubinius awesomeness.

Kick-ass introspection

Let’s start slow by patching Object to help us quickly grok the new kinds of objects we may encounter:

class Object
  # Return only the methods not present on basic objects
  def interesting_methods
    (self.methods - Object.new.methods).sort
  end
end
#=> #<CompiledMethod interesting_methods file=(irb)>

And now let’s create a basic little class that will help us start our exploration of a MethodContext instance.

class C
  def initialize
    @inst = 42
  end
  def get_mc
    local_var = 'value'
    MethodContext.current
  end
end
#=> #<CompiledMethod get_mc file=(irb)>

So with the help of an instance of the class C, let’s start poking gently at a MethodContext.

c   = C.new
ctx = c.get_mc
#=> #<MethodContext:0xcc #<C:0xca>#get_mc (irb):7>

ctx.interesting_methods
#=> ["__add_method__", "_get_field", "_set_field", "activate",
 "active_path", "alias_method", "back_ref", "block", "class_variable_defined?",
 "const_defined?", "const_path_defined?", "context_from_proc", "context_stack",
 "copy", "current_scope", "describe", "disable_long_return!", "dynamic_locals",
 "file", "fp", "from_eval?", "get_eval_local", "ip", "ip=", "last_match",
 "last_match=", "line", "lines", "locals", "locals=", "location",
 "make_independent", "method=", "method_module", "method_scope",
 "method_scope=", "name", "normalized_name", "nth_ref", "position_info",
 "receiver", "receiver=", "reload_method", "script_object", "send_private?",
 "sender", "set_eval_local", "set_iseq", "sp", "stack_trace_starting_at"]

ctx.name
#=> :get_mc

ctx.describe
#=> "C\#get_mc"

ctx.method_module
#=> C

Interesting, that reminds me of the monkey-patching discussion that often comes up in the Ruby community. Let’s try something else:

module ModuleMC
  def module_mc
    MethodContext.current
  end
end
#=> #<CompiledMethod module_mc file=(irb)>

C.include ModuleMC
#=> [ModuleMC]

c.module_mc.method_module
#=> #<IncludedModule:0xd6>

c.module_mc.method_module.name
#=> "ModuleMC"

Wouldn’t it be nice if we had that kind of introspection, when comes time to debug some mixin magic?

Now let’s go back our MethodContext object. Or rather, its method accessor, which gives us a CompiledMethod instance:

m = ctx.method
#=> #<CompiledMethod get_mc file=(irb)>

m.interesting_methods
#=> ["__ivars__", "__ivars__=", "activate", "activate_as_script",
"as_script", "child_methods", "compile", "decode", "describe",
"exceptions", "exceptions=", "file", "file=", "first_ip_on_line",
"first_line", "from_string", "hints", "hints=", "inherit_scope",
"is_block?", "iseq", "iseq=", "line_from_ip", "lines", "lines=",
"literals", "literals=", "local_count", "local_count=", "local_names",
"local_names=", "locate_line", "min_stack_size", "name", "name=",
"primitive", "primitive=", "private?", "protected?", "public?",
"required_args", "required_args=", "scope", "scope=", "send_sites",
"serial", "serial=", "splat", "splat=", "stack_size", "stack_size=",
"total_args", "total_args="]

m.describe
#=> "method get_mc: 0 arg(s), 0 required"

m.local_names
#=> #<Tuple: :local_var>

m.literals
#=> #<Tuple: "value", :MethodContext, #<SendSite:0xda
#     name=current hits=0 misses=0>>

m.file
#=> :"(irb)"

The local_names method sounds extremely promising, but unfortunately for now, there’s no primitive for actually getting the local variable’s value, but it’s perfectly possible3. It’s just not been done yet.

By the way, what is that? #describe summarizes the arguments? Let’s try something more interesting with it:

def method_with_args(arg1, arg2='default', *args)
  MethodContext.current
end
#=> #<CompiledMethod method_with_args file=(irb)>

ctx2 = method_with_args(42, 'towel', "don't panic")
#=> #<MethodContext:0x16e main#method_with_args (irb):4>

m2 = ctx2.method
#=> #<CompiledMethod method_with_args file=(irb)>

m2.describe
#=> "method method_with_args: 2 arg(s), 1 required, splatted."

m2.local_names
#=> #<Tuple: :arg1, :arg2, :args>

m2.literals
#=> #<Tuple: "default", :MethodContext, #<SendSite:0x16c
#     name=current hits=1 misses=0>>

Nice! Ok, now let’s come back to our CompiledMethod instance and check out it’s scope accessor.

ss = m.scope
#=> #<StaticScope:0xea parent=#<StaticScope:0xe8 parent=nil
#     module=Object> module=C>

ss.interesting_methods
#=> ["initialize", "module", "parent", "script", "script="]

ss.parent
#=> #<StaticScope:0xe8 parent=nil module=Object>

So now we’ve essentially poked 2 levels deep: ctx.method.scope. Let’s rewind again and look at a our context’s receiver and sender accessors. To better understand both, let’s come back to our OO roots of 30 years back and start calling ‘method calls’ ‘messages’ instead.

sender (sends message ‘get_mc’) => receiver

sender is then the caller of the method, and receiver is, the object receiving the message. Also known as self, during the execution of the method.

Let’s see that in action:

r  = ctx.receiver
#=> #<C:0xca @inst=42>

r == c
#=> true

So ctx.receiver is a reference to the instance we’d put in the variable c. From there of course we can do Ruby’s regular meta-poking around:

r.instance_variable_get '@inst'
#=> 42

Now let’s look at the sender:

s = ctx.sender
#=> #<BlockContext:0xf0 main#irb_binding (irb):1>

s.class.ancestors
#=> [BlockContext, MethodContext, Object, PP::ObjectMixin, Kernel]

s.interesting_methods - ctx.interesting_methods
#=> ["env", "home"]

s.home
#=> #<MethodContext:0xf6 main#irb_binding
#     /Users/mat/dev/_rubies/rubinius/rubinius/lib/irb/workspace.rb:1>

s.env
#=> #<BlockEnvironment:0xf8 @initial_ip=0 @last_ip=268435456
#     @post_send=0 @bonus=#<Tuple: true>>

When calling a method from IRB, we’re in a BlockContext instead of a MethodContext, but it’s still in the family.

s = ctx.sender
#=> #<BlockContext:0xfe main#irb_binding (irb):1>

s.class.ancestors
#=> [BlockContext, MethodContext, Object, Kernel]

Anything new we need to know about?

s.interesting_methods - ctx.interesting_methods
#=> ["env", "home"]

s.home
#=> #<MethodContext:0x102 main#irb_binding
#     /Users/mat/dev/_rubies/rubinius/rubinius/lib/irb/workspace.rb:1>

s.env
#=> #<BlockEnvironment:0xf8 @initial_ip=0 @last_ip=268435456
#     @post_send=0 @bonus=#<Tuple: true>>

All of this is strangely reminiscent of a stack trace. Before you go collecting all senders to explore the execution stack, let me point you to the convenient context_stack:

ctx.context_stack.length
#=> 27

puts *ctx.context_stack
# Too noisy to output here

puts *ctx.context_stack.map{ |s| s.describe }

#=>
# C#get_mc
# Object#irb_binding {}
# Kernel(IRB::WorkSpace)#eval
# IRB::WorkSpace#evaluate
# IRB::Context#evaluate
# IRB::IrbRubinius#process_statements {}
# IRB::Irb(IRB::IrbRubinius)#signal_status
# IRB::IrbRubinius#process_statements {}
# RubyLex#each_top_level_statement {}
# Kernel(RubyLex)#catch {}
# ThrownValue.register
# Kernel(RubyLex)#catch
# RubyLex#each_top_level_statement
# IRB::IrbRubinius#process_statements
# IRB::Irb(IRB::IrbRubinius)#eval_input
# IRB.start {}
# Kernel(Module)#catch {}
# ThrownValue.register
# Kernel(Module)#catch
# IRB.start
# main.__script__
# CompiledMethod#activate_as_script
# CompiledMethod#as_script
# Compile.single_load
# Compile.unified_load
# Kernel(Object)#require
# Object#__script__
# #=> nil

I’m pretty sure there’s other areas specific to Rubinius that can be explored like that. Please share any insight in the comments.

S-Expressions

Rubinius groks s-expressions out of the box (similar to standard Ruby with ParseTree or ruby_parser. An example).

require 'pp'
pp sx = "
  class C
    def meth(arg)
      arg * 2
    end
  end".to_sexp

#=>
# s(:class,
#  :C,
#  nil,
#  s(:scope,
#   s(:defn,
#    :meth,
#    s(:args, :arg),
#    s(:scope,
#     s(:block, s(:call, s(:lvar, :arg), :*, s(:arglist, s(:fixnum, 2))))))))

sx[0]
#=> :class

sx[3][1][1]
#=> :meth

With something that reminiscent to Lisp, it’s probably better to explore recursively, though.

S-expressions are used by a lot of the Ruby code inspection tools to understand your ugly Ruby code.

Gems

I won’t touch trying out gems for today. There seems to be little issues as the moment. They do install, but I’ve been having problems running them. Please leave a comment if you’ve had success with specific gems.

If you’re curious and want to try playing with gems, Rubygems is already installed.

rbx gem install rails --no-rdoc --no-ri

Pro tip: always skip the documentation when playing with gems Rubinius. The doc takes unusually long to compile.

Run the famous test suite

The spec suite that’s been keeping all Ruby implementations honest was born from the Rubinius project. It’s been split into a separate project a while ago, since it’s now such an important and central piece of the Ruby ecosystem.

Update the specs

Since they are now in a different project, we first have to get the most recent version. Easy stuff:

rake rubyspec:update

rbx in your PATH

Before you run the specs, you need to do one little thing. One of the specs expects a shell call to rbx to start Rubinius (as in, the executable must be in your path).

The simplest way to do that for now is just to temporarily add the directory to your path (right in your console, not in your .bash_profile).

pwd
#=> /path/to/project/rubinius
export PATH=$PATH:/path/to/project/rubinius/bin
rbx -v

Run the specs

rake spec
# Time for another BRAWNDO!

Or rather, time to actually look at some of the specs you’re currently running. If you look in the spec directory, you’ll see that it’s pretty extensive, to say the least. To start with something familiar, navigate to spec/ruby/1.8, in subdirectories core or library. Open up a few of the specs in there and stare at them for a few minutes. Or better, improve a few of them and try them out on MRI, JRuby and of course, Rubinius.

Conclusion

Well, now I’ve tricked you into putting the Rubinius project on your hard drive. And you’re a Ruby developer. What are you waiting for?

I think Rubinius will be an awesome runtime for our Ruby programs. It probably won’t be only Ruby in the close future, but the kernel of Ruby (base classes & stuff) is mostly implemented in Ruby, and the compiler is also implemented in Ruby. This is awesome to help understand the workings of the language and to lower the barrier to contribution. Which is already pretty low.

Rubinius is here to stay and it’s gonna keep rocking.

Footnotes

  1. Examples of details not up to date in the old articles are: the LOC numbers and the base language of the VM (used to be C, now C++).
  2. If the build craps out with a message you understand, cool. Try to install the dependency through apt-get or macports/fink, or search your hard drive to see if the tool’s just not in your PATH. Otherwise, here are a few related pointers.

  3. For a quick discussion about getting local variable’s values out of a CompiledMethod, check the [IRC logs around 19:20][9].
Nov 212008

Seen on a git 1.6.0.4 installation (dunno about previous versions), installed through MacPorts +bash_completion option.

$ git config #tab
apply.whitespace               core.compression        ...
branch.                        core.fileMode
clean.requireForce             core.gitProxy
color.branch                   core.ignoreStat
color.branch.current           core.logAllRefUpdates
...

With sub-options too, on words ending with a dot:

$ git config remote.origin. #tab
remote.origin.fetch               remote.origin.receivepack      ...
remote.origin.push                remote.origin.skipDefaultUpdate

And as usual, calling git-config with a setting name without specifying a new value displays the current value.

$ git config remote.origin.url
git://github.com/evanphx/rubinius.git

Git’s getting easier by the day. Awesome!

1. A recent change from a previous position!

Tonight I’m trying conciseness.

Editor’s note: I failed.

I recently decided to test my git_remote_branch gem with Ruby 1.9, for the heck of it. Well, I was making sure it ran on a bunch of platforms: Windows, Ruby 1.8.7 and with the most recent Git version (1.6.0.2, get it). So it seemed fitting to check it out under Ruby 1.9.

On Leopard, the only missing dependency to Ruby 1.9 is readline 5.2. This article will present the installation of both. And help heat up your apartment.

Linux too

These instructions will mostly work on Linux as well (tried on Ubuntu). There will be a few minor differences though.

  • Make sure you download the original readline from the gnu site and patch it yourself;
  • Uninstall older versions of Ruby1.9;
  • Make sure you have the basic dev tools installed, like gcc and make;
  • Skip the part about installing Xcode :-)

Prerequisites

You first need to have the Apple developer tools installed on your mac. They’re available on your installation CD. Put it in, run the installer. It’s pretty straightforward.

# in your terminal
open /Volumes/Mac\ OS\ X\ Upgrade\ DVD/Optional\ Installs/Xcode\ Tools/XcodeTools.mpkg 

If you don’t compile your own stuff often, you may have to set up your PATH variable in your ~/.bash_profile.

# file  ~/.bash_profile
export PATH="/usr/local/bin:$PATH"

Now, prepare a working directory to keep the source close to the corresponding executables.

# in your terminal
sudo mkdir -p /usr/local/src
sudo chgrp admin /usr/local/src
sudo chmod -R 775 /usr/local/src
cd /usr/local/src

Once you’ve set yourself up, if you don’t care about the details, you can skip to the end for the Cliff’s notes.

Installing readline

This one’s not as straightforward as it could have been. The gzipped readline library available on the gnu site is 12 patches behind. It so happens that the 12th patch fixes a problem with compilation under OS X. So I applied all 12 to the code and repackaged it. The example uses that file, compiled by me.

You can also do do the patching by yourself if you so wish. Here’s where you can download the readline code:

So let’s get on with the instructions to install readline from my patched package:

# in your terminal
curl -O http://s3.amazonaws.com/webmat-public/readline-5.2-patch012.tar.gz
md5 readline-5.2-patch012.tar.gz
# should be a9f37d2a22d181f8c23c6a320907917d
tar xzf readline-5.2-patch012.tar.gz
cd readline-5.2-patch012

./configure --prefix=/usr/local
make
sudo make install
cd ..

Build Ruby 1.9

Build options

Note that here you have a few options as to how you want to distinguish your 1.9 stack from your main 1.8 one.

In the following example, I build Ruby with the ‘1.9’ suffix, which means all executables will be suffixed with 1.9: ruby1.9, gem1.9, irb1.9, rake1.9 and so on. This approach is ideal for casual use of two versions side by side. If you don’t care about the details, skip right over the next paragraph.

The industrial approach would be to put ruby in a non standard directory and only add it to your path when you want to use that version (or use the explicit path to invoke executables). To go industrial, you can simply use the --prefix=/usr/local/ruby1.9 option and then drop the --program-suffix argument when you run configure for Ruby. This setup is ideal if you really want to have a bunch of versions living side by side (e.g. all 1.9 versions as well as 1.8.7 in addition to the current 1.8.6).

Actual installation of Ruby 1.9

Pick the most recent version or Ruby 1.9 on the ftp server. At the time of writing, 1.9.1-preview1 is the most recent.

So, still from /usr/local/src:

# in your terminal
curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.gz
tar xzvf ruby-1.9.1-preview1.tar.gz
cd ruby-1.9.1-preview1
./configure --prefix=/usr/local --program-suffix=1.9 --enable-pthread --with-readline-dir=/usr/local --enable-shared
make
sudo make install

Now you’re about to see some of the funniest looking progress indicators around. Ruby’s about making the programmer happy, and it delivers even in the details!

Note: the recent source packages of Ruby1.9 automatically include the documentation, as the end of the make install attests.

Try Ruby 1.9

# in your terminal
ruby1.9 --version
gem1.9 --version
irb1.9

Once inside the Ruby interactive shell,

# in irb1.9
RUBY_VERSION
#=> "1.9.1"
stabby = ->(msg='inside the stabby lambda') { puts msg }
stabby.call
# => "inside the stabby lambda"
stabby.call 'hello world'
# => "hello world"

Yep, Ruby 1.9 introduces the very cool stabby lambda syntax. Ruby 1.8’s lambdas couldn’t have optional parameters (unless you fiddled with *args). 1.9’s stabby lambdas can, with a syntax as clean as a simple method definition, as you just experimented.

Now install the gems you use everyday (or kindly make available to your peers) and help make them 1.9 compatible.

For the sake of the stabby lambda!

That’s it! (Except for those who skipped to the Cliff’s Notes).

Cliff’s Notes

# Install patched readline
cd /usr/local/src
curl -O http://s3.amazonaws.com/webmat-public/readline-5.2-patch012.tar.gz
md5 readline-5.2-patch012.tar.gz
# should be a9f37d2a22d181f8c23c6a320907917d
tar xzf readline-5.2-patch012.tar.gz
cd readline-5.2-patch012
./configure --prefix=/usr/local
make
sudo make install
cd ..

# Install Ruby1.9
curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.gz
tar xzvf ruby-1.9.1-preview1.tar.gz
cd ruby-1.9.1-preview1
./configure --prefix=/usr/local --program-suffix=1.9 --enable-pthread --with-readline-dir=/usr/local --enable-shared
make
sudo make install

# Try Ruby 1.9
ruby1.9 --version
gem1.9 --version
irb1.9

# in irb1.9
RUBY_VERSION
stabby = ->(msg='inside the stabby lambda') { puts msg }
stabby.call
stabby.call 'hello world'

Josh Knowles recently suggested that maybe I could merge grb’s functionality to the github gem.

Both gems being command-line tools that help you use Git in a friendlier manner, the question makes a lot of sense. It makes so much sense in fact, that I decided to blog about it. A post about it will scale much better to answer other users who may potentially ask the same question.

So here’s a slightly edited excerpt from the answer I gave him. And yes, I also ramble in email.

I’ve seen what Scott added to the github gem. Pretty cool stuff indeed. I think the idea of merging with the github gem has merit. I definitely can see a future where we start having too many distinct command-line tools that help deal with Git’s sometimes obscure or numerous commands.

However I’m not sure I’d like to merge grb into the gh gem, despite the additional awareness it would get. Here’s why.

In my mind, the github gem should be mostly features about GitHub itself, like managing pull requests (the way GitHub does them). It’s starting to accumulate features that probably aren’t GitHub-specific, which I don’t mind, of course. But grb’s features really are GitHub-agnostic. I’ve started working on it before I even started using GitHub, in fact :-)

Reinforcing the previous point, I wouldn’t want someone who doesn’t use GitHub to not realize the features of grb are available to him because they’re included in a gem called ‘github’ ;-)

Also, one of the goals of git_remote_branch is to explicitly teach the underlying git commands. I do this by always spewing out the underlying commands in red, and by having the explain command. I’m pretty sure an unsuspecting user would wonder what hit him if a few of the github commands started spewing out red text in his console ;-) Having explain for a few commands (ported from grb) and not for the rest of the github gem’s commands would be weird, too.

There’s also a few other architectural decisions of grb that may not fit with github’s, like having aliases. Once again, grb being a teaching tool, I want to offer a bunch of aliases for forgetful people like me. So far I don’t see anything like aliases in github and I’m not sure how the authors of github-gem would react to a pull request polluting it with a bunch of aliases ;-)

Last but not least, the github gem already has a track command, which conflicts with grb’s. github’s is used to track a new remote repo in your local repo while grb’s is to track another branch from your current remote repo.

So git_remote_branch is GitHub-agnostic. You can use it with any Git hosting solution: GitHub, your own Gitosis / gitweb / Gitorious installation, Gitorious.org hosting, Rubyforge or any other.

Better, grb supports working with all of them at the same time. All grb commands support an optional origin argument.

Learn more about git_remote_branch

Awesomeness for the masses

git_remote_branch 0.3 has been released!

Previous releases were pretty much only usable by rubyists on OS X.

Works on my machine logo

No more. This release is mostly focused on making sure git_remote_branch works on a broader range of platforms. A few actual features squeaked in, but nothing big like introducing new commands.

If you don’t care about the details just type the following at your command-line.

sudo gem install git_remote_branch

And check the help

grb --help

If you encounter installation problems, refer to the readme.

Platforms

git_remote_branch 0.3 has been tested with the following configurations:

  • OS X Leopard / Ruby 1.8.6 / Git 1.5.4.3 and 1.6.0.2
  • OS X Leopard / Ruby 1.9.1 / Git 1.5.4.3 and 1.6.0.2
  • Ubuntu Intrepid Ibex / Ruby 1.8.7 / Git 1.5.6.3
  • Windows XP / Ruby 1.8.6 / Git 1.6.0.2 (the msys version)

Features

Better track

Track now works even if you already have a local branch of the same name. It uses git config instead of branch —track in that case. The subtlety can be observed by running (from a git repository):

grb explain track master
grb explain track non_existent_branch

Force the use of a specific git executable

Set the environment variable GRB_GIT to point to it and grb will use this one for all its operations.

Documentation

I’ve also worked quite a bit on the actual documentation. I used to be ashamed at the quality and availability of the documentation of git_remote_branch. At last I’ll be able to sleep at night :-)

git_remote_branch in a nutshell

I’ve rewritten the intro of the readme to be (hopefully) a bit clearer.

git_remote_branch is a simple command-line tool that makes it very easy to manipulate branches published in shared repositories.

It achieves this goal by sticking to a few principles:

  • keep grb’s commands extremely regular (they all look alike)
  • support aliases for commands
  • print all commands it runs on your behalf in red, so you eventually learn them

Another nice thing about git_remote_branch is that it can simply explain a command (print out all the corresponding git commands) instead of running them on your behalf.

Note: git_remote_branch assumes that the local and
remote branches have the same name. Multiple remote
repositories (or origins) are supported.

Documentation availability

The main readme is now available on the main grb page on rubyforge.

Documentation quality

I’ve added clearer information on getting grb to run in different kinds of situation, due to helpful feedback from Axelson and Glenn Rempe.

I’ve also added some information for playing with the code for git_remote_branch (test dependencies and so on). See the end of the readme.

Finally, I’ve updated the links section quite a bit:

Documentation http://grb.rubyforge.org
News http://programblings.com/category/git/git_remote_branch/
Bug tracker Lighthouse
Code http://github.com/webmat/git_remote_branch
Mailing list http://groups.google.com/group/git_remote_branch

Dare

I dare you to find a platform on which git_remote_branch doesn’t work :-)

If you do, please send me feedback through GitHub or via email. I’m using gmail and, as usual, I go by the handle of webmat.

Last note: the git_remote_branch gem on GitHub

Excerpt from the readme:

Note that the only stable version of the gem you should trust is the one from Rubyforge. The GitHub gem is a development gem. The GitHub gem WILL be rebuilt with the same version number, and other horrible things like that. If you use the GitHub version of git_remote_branch, children will die!

You’ve been warned.