<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -49,9 +49,13 @@ case command
 when 'init'
   GitRuby.init
 when 'clone'
-  GitRuby.clone(ARGV[1], ARGV[2])
+  if ARGV[2]
+    GitRuby.clone(ARGV[1], ARGV[2], :logger =&gt; Logger.new(STDERR))
+  else
+    puts 'please specify a name'
+  end
 when 'ls-files'
-  @git.index.to_s
+  puts @git.index.to_s
 when 'checkout'
   @git.checkout(ARGV[1])
 when 'add'
@@ -65,9 +69,9 @@ when 'log'
     puts l.contents
     puts
   end
-when 'log-shas'
+when 'rev-list'
   # gitr log-shas
-  puts @git.log
+  puts @git.lib.rev_list
 when 'cat-file'
   # gitr cat-file
   puts @git.cat_file(ARGV[1])
@@ -91,6 +95,10 @@ when 'ls-tree'
   tree.trees.sort.each do |name, c|
     puts [[c.mode, c.type, c.sha].join(&quot; &quot;), name].join(&quot;\t&quot;)
   end
+when 'done'
+  puts '&lt;LtCG&gt;i dont care who you are, thats funny right there...&lt;/LtCG&gt;'
+else
+  puts 'command not found'
 end
 
 # todo:</diff>
      <filename>bin/gitr</filename>
    </modified>
    <modified>
      <diff>@@ -168,10 +168,23 @@ module GitRuby
 
 
     # returns a Git::Log object with count commits
-    def log(count = 30)
+    # :first_parent =&gt; true
+    def log(count = nil)
       GitRuby::Log.new(self, count)
     end
 
+    # rev-list returns a list of commit shas
+    # :object =&gt; tree-ish to start from
+    # :count =&gt; @count
+    # :since =&gt; @since  # should be a Time object
+    # :until =&gt; @until  # should be a Time object
+    # :between =&gt; @between # should be an array of 2 Time objects
+    
+    # :path_limiter =&gt; @path
+    def rev_list(options = {})
+      self.lib.rev_list(options)
+    end
+    
     # this is a convenience method for accessing the class that wraps all the actual 'git' calls. 
     def lib
       @lib ||= GitRuby::Lib.new(self, @logger)</diff>
      <filename>lib/git-ruby/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -285,16 +285,37 @@ module GitRuby
     end
 
     def full_log_commits(opts = {})
-      # can do this in pure ruby
+      data = log_data(opts)
+      text = data.map { |a,b| b }.join(&quot;\n&quot;)
+      return process_commit_data(text)
+    end
+    
+    def rev_list(opts = {})
+      data = log_data(opts)
+      data.map { |a,b| a }
+    end
+    
+    def log_data(opts)
+      # resolve options
       sha = revparse(opts[:object] || branch_current || 'master')
-      count = opts[:count] || 30
+      if opts[:between] &amp;&amp; opts[:between].size == 2
+        opts[:since] = opts[:between][0]
+        opts[:until] = opts[:between][1]
+      end
+      if opts[:path_limiter] &amp;&amp; opts[:path_limiter][0,1] != '.'
+        opts[:path_limiter] = File.join('.', opts[:path_limiter])
+      end
       
       if /\w{40}$/.match(sha)  # valid sha
         repo = get_raw_repo
-        return process_commit_data(repo.log(sha, count))
+        return repo.log(sha, opts)
       end
     end
     
+    def diff_data(tree_sha1, tree_sha2)
+      get_raw_repo.quick_diff(tree_sha1, tree_sha2)
+    end
+    
     def revparse(string)
       if /\w{40}/.match(string)  # passing in a sha - just no-op it
         return string
@@ -397,13 +418,7 @@ module GitRuby
     end
 
     def ls_tree(sha)
-      data = {'blob' =&gt; {}, 'tree' =&gt; {}}
-      
-      get_raw_repo.object(revparse(sha)).entry.each do |e|
-        data[e.format_type][e.name] = {:mode =&gt; e.format_mode, :sha =&gt; e.sha1}
-      end
-              
-      data
+      get_raw_repo.ls_tree(revparse(sha))
     end
 
     def branches_all</diff>
      <filename>lib/git-ruby/lib.rb</filename>
    </modified>
    <modified>
      <diff>@@ -48,22 +48,122 @@ module GitRuby
         object(sha).raw_content
       end
       
-      def log(sha, count = 30)
-        output = ''
-        i = 0
-
-        while sha &amp;&amp; (i &lt; count) do
+      def log(sha, options = {})
+        walk_log(sha, 0, options)
+      end
+      
+      def walk_log(sha, count, opts)
+        array = []
+        
+        if (sha &amp;&amp; (!opts[:count] || (count &lt; opts[:count])))
           o = get_raw_object_by_sha1(sha)
           c = GitRuby::Raw::Object.from_raw(o)
+
+          add_sha = true
+          
+          if opts[:since] &amp;&amp; opts[:since].is_a?(Time) &amp;&amp; (opts[:since] &gt; c.committer.date)
+            add_sha = false
+          end
+          if opts[:until] &amp;&amp; opts[:until].is_a?(Time) &amp;&amp; (opts[:until] &lt; c.committer.date)
+            add_sha = false
+          end
+          
+          # follow all parents unless '--first-parent' is specified #
+          subarray = []
+          
+          if !c.parent.first &amp;&amp; opts[:path_limiter]  # check for the last commit
+            add_sha = false
+          end
+          
+          if opts[:first_parent]
+            psha = c.parent.first
+            subarray += walk_log(psha, count + 1, opts)
+            if psha &amp;&amp; !files_changed?(c.tree, object(psha).tree, opts[:path_limiter])
+              add_sha = false
+            end
+          else
+            c.parent.each do |psha|
+              subarray += walk_log(psha, count + 1, opts)
+              if psha &amp;&amp; !files_changed?(c.tree, object(psha).tree, opts[:path_limiter])
+                add_sha = false 
+              end
+            end
+          end
           
-          output += &quot;commit #{sha}\n&quot;
-          output += o.content + &quot;\n\n&quot;
+          if add_sha
+            output = &quot;commit #{sha}\n&quot;
+            output += o.content + &quot;\n\n&quot;
+            array &lt;&lt; [sha, output]
+          end
 
-          sha = c.parent.first
-          i += 1
+          array += subarray
+                                
         end
         
-        output
+        array
+      end
+      
+      # returns true if the files in path_limiter were changed, or no path limiter
+      def files_changed?(tree_sha1, tree_sha2, path_limiter = nil)
+        if path_limiter
+          mod = quick_diff(tree_sha1, tree_sha2)
+          files = mod.map { |c| c.first }
+          path_limiter.to_a.each do |filepath|
+            if files.include?(filepath)
+              return true
+            end
+          end
+          return false
+        end
+        true
+      end
+      
+      def quick_diff(tree1, tree2, path = '.')
+        # handle empty trees
+        changed = []
+
+        t1 = ls_tree(tree1) if tree1
+        t2 = ls_tree(tree2) if tree2
+
+        # finding files that are different
+        t1['blob'].each do |file, hsh|
+          t2_file = t2['blob'][file] rescue nil
+          full = File.join(path, file)
+          if !t2_file
+            changed &lt;&lt; [full, 'added', hsh[:sha], nil]      # not in parent
+          elsif (hsh[:sha] != t2_file[:sha])
+            changed &lt;&lt; [full, 'modified', hsh[:sha], t2_file[:sha]]   # file changed
+          end
+        end if t1
+        t2['blob'].each do |file, hsh|
+          if !t1['blob'][file]
+            changed &lt;&lt; [File.join(path, file), 'removed', nil, hsh[:sha]]
+          end if t1
+        end if t2
+
+        t1['tree'].each do |dir, hsh|
+          t2_tree = t2['tree'][dir] rescue nil
+          full = File.join(path, dir)
+          if !t2_tree
+            changed += quick_diff(hsh[:sha], nil, full)  # recurse
+          elsif (hsh[:sha] != t2_tree[:sha])
+            changed += quick_diff(hsh[:sha], t2_tree[:sha], full)  # recurse
+          end
+        end if t1
+        t2['tree'].each do |dir, hsh|
+          full = File.join(path, dir)
+          changed += quick_diff(nil, hsh[:sha], full)  # recurse
+        end if t2
+
+        changed
+      end
+      
+      def ls_tree(sha)
+        data = {'blob' =&gt; {}, 'tree' =&gt; {}}
+        self.object(sha).entry.each do |e|
+          data[e.format_type][e.name] = {:mode =&gt; e.format_mode, :sha =&gt; e.sha1}
+        end              
+        data
       end
       
       def get_object_by_sha1(sha1)</diff>
      <filename>lib/git-ruby/raw/repository.rb</filename>
    </modified>
    <modified>
      <diff>@@ -32,7 +32,7 @@ class Test::Unit::TestCase
   
   def with_temp_bare
     in_temp_dir do |path|
-      g = Git.clone(@wbare, 'new')
+      g = GitRuby.clone(@wbare, 'new')
       Dir.chdir('new') do
         yield g
       end</diff>
      <filename>tests/test_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -14,6 +14,16 @@ class TestLib &lt; Test::Unit::TestCase
     end
   end
   
+  def test_diff_data
+    tr1 = 'e8bd03b163f82fba4560c11839d49361a78dec85'
+    tr2 = '33edabb4334cbe849a477a0d2893cdb768fa3091'
+    diff = @git.lib.diff_data(tr1, tr2)
+    assert_equal './example.txt', diff.first[0]
+    assert_equal 'modified', diff.first[1]
+    assert_equal '8a3fb747983bf2a7f4ef136af4bfcf7993a19307', diff.first[2]
+    assert_equal 'a115413501949f4f09811fd1aaecf136c012c7d7', diff.first[3]
+  end
+  
   def test_revparse
     #self.lib.revparse(objectish)
   end</diff>
      <filename>tests/units/test_lib.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,14 +1,66 @@
 #!/usr/bin/env ruby
 require File.dirname(__FILE__) + '/../test_helper'
+require 'date'
 
 class TestLog &lt; Test::Unit::TestCase
   def setup
     set_file_paths
+    @start_date = Time.local(2007, 11, 8, 11, 20, 38);
+    @end_date = Time.local(2007, 11, 9, 10, 29, 14)
+    @full_size = @git.rev_list.size
   end
 
   def test_log
+    assert @git.log.map { |c| c.sha }.include?('291b6be488d6abc586d3ee03ca61238766625a75')
   end
 
-  def test_log_shas
+  def test_rev_list
+    assert @git.rev_list.include?('d5b9587b65731e25216743b0caca72051a760211')
   end
+
+  def test_since
+    part = @git.rev_list(:since =&gt; @start_date).size
+    assert @full_size &gt; part
+    assert part &gt; 0
+  end
+
+  def test_count
+    assert_equal 20, @git.rev_list(:count =&gt; 20).size
+    assert_equal 15, @git.rev_list(:count =&gt; 15).size
+  end
+
+  def test_until
+    part = @git.rev_list(:until =&gt; @start_date).size
+    assert @full_size &gt; part
+    assert part &gt; 0
+  end
+
+  def test_between
+    part = @git.rev_list(:between =&gt; [@start_date, @end_date]).size
+    none = @git.rev_list(:between =&gt; [@end_date, @start_date]).size
+    assert @full_size &gt; part
+    assert part &gt; none
+    assert_equal 0, none
+  end
+
+  def test_first_parent
+    part = @git.rev_list(:first_parent =&gt; true).size
+    assert part &gt; 0
+  end
+  
+  def test_path_limiter
+    part1 = @git.rev_list(:path_limiter =&gt; './example.txt')
+    part2 = @git.rev_list(:path_limiter =&gt; './scott/text.txt')
+    assert @full_size &gt; part1.size
+    assert part1.size &gt; part2.size
+    assert part2.size &gt; 0
+  end
+
+  def test_multi
+    part = @git.rev_list(:path_limiter =&gt; './example.txt', :between =&gt; [@start_date, @end_date])
+    assert_equal part.size, 57
+    part = @git.rev_list(:path_limiter =&gt; './example.txt')
+    assert_equal part.size, 67
+  end
+  
 end
\ No newline at end of file</diff>
      <filename>tests/units/test_log.rb</filename>
    </modified>
    <modified>
      <diff>@@ -22,13 +22,13 @@ class TestRawInternals &lt; Test::Unit::TestCase
   end
   
   def test_commit_object
-    g = Git.bare(@wbare)    
+    g = GitRuby.bare(@wbare)    
     c = g.gcommit(&quot;v2.5&quot;)
     assert_equal('test', c.message)
   end
   
   def test_lstree
-    g = Git.bare(@wbare)
+    g = GitRuby.bare(@wbare)
     c = g.object(&quot;v2.5&quot;).gtree
     sha = c.sha
     </diff>
      <filename>tests/units/test_raw_internals.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>cbe5952ddb7eabace75e10edabe0397f715e7be6</id>
    </parent>
  </parents>
  <author>
    <name>Scott Chacon</name>
    <email>schacon@gmail.com</email>
  </author>
  <url>http://github.com/schacon/git-ruby/commit/781dc3e28ee1bc82b706414bba1b5ff4e1b1b97c</url>
  <id>781dc3e28ee1bc82b706414bba1b5ff4e1b1b97c</id>
  <committed-date>2008-04-05T11:37:06-07:00</committed-date>
  <authored-date>2008-04-05T11:37:06-07:00</authored-date>
  <message>added bunches of options to the log() function (since, until, path_limiter, etc)
added rev-list and diff_data(tree1, tree2), which are both helpful</message>
  <tree>4031a3a5a8e471212c319c674767d6c1f6f6b85d</tree>
  <committer>
    <name>Scott Chacon</name>
    <email>schacon@gmail.com</email>
  </committer>
</commit>
